Rollup merge of #95343 - dtolnay:literals, r=petrochenkov

Reduce unnecessary escaping in proc_macro::Literal::character/string

I noticed that https://doc.rust-lang.org/proc_macro/struct.Literal.html#method.character is producing unreadable literals that make macro-expanded code unnecessarily hard to read. Since the proc macro server was using `escape_unicode()`, every char is escaped using `\u{…}` regardless of whether there is any need to do so. For example `Literal::character('=')` would previously produce `'\u{3d}'` which unnecessarily obscures the meaning when reading the macro-expanded code.

I've changed Literal::string also in this PR because `str`'s `Debug` impl is also smarter than just calling `escape_debug` on every char. For example `Literal::string("ferris's")` would previously produce `"ferris\'s"` but will now produce `"ferris's"`.
This commit is contained in:
Dylan DPC 2022-04-04 20:41:30 +02:00 committed by GitHub
commit 2d1496a8f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 10 deletions

View file

@ -658,16 +658,16 @@ fn f64(&mut self, n: &str) -> Self::Literal {
self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
}
fn string(&mut self, string: &str) -> Self::Literal {
let mut escaped = String::new();
for ch in string.chars() {
escaped.extend(ch.escape_debug());
}
self.lit(token::Str, Symbol::intern(&escaped), None)
let quoted = format!("{:?}", string);
assert!(quoted.starts_with('"') && quoted.ends_with('"'));
let symbol = &quoted[1..quoted.len() - 1];
self.lit(token::Str, Symbol::intern(symbol), None)
}
fn character(&mut self, ch: char) -> Self::Literal {
let mut escaped = String::new();
escaped.extend(ch.escape_unicode());
self.lit(token::Char, Symbol::intern(&escaped), None)
let quoted = format!("{:?}", ch);
assert!(quoted.starts_with('\'') && quoted.ends_with('\''));
let symbol = &quoted[1..quoted.len() - 1];
self.lit(token::Char, Symbol::intern(symbol), None)
}
fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
let string = bytes

View file

@ -18,6 +18,17 @@ fn test_display_literal() {
Literal::f64_unsuffixed(1e100).to_string(),
"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
);
assert_eq!(
Literal::string("a \t ❤ ' \" \u{1}").to_string(),
"\"a \\t ❤ ' \\\" \\u{1}\"",
);
assert_eq!(Literal::character('a').to_string(), "'a'");
assert_eq!(Literal::character('\t').to_string(), "'\\t'");
assert_eq!(Literal::character('❤').to_string(), "'❤'");
assert_eq!(Literal::character('\'').to_string(), "'\\''");
assert_eq!(Literal::character('"').to_string(), "'\"'");
assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'");
}
fn test_parse_literal() {

View file

@ -22,7 +22,7 @@ fn main() {
crate::Span::recover_proc_macro_span(0)))),
crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
crate::Span::recover_proc_macro_span(1)))),
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}',
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('=',
crate::Spacing::Alone))),
crate::TokenStream::from(crate::TokenTree::Literal({
let mut iter =
@ -35,7 +35,7 @@ fn main() {
::core::panicking::panic("internal error: entered unreachable code")
}
})),
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}',
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new(';',
crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
}
const _: () =