Skip to content

Commit

Permalink
Use Ident::new_raw to quote raw identifiers
Browse files Browse the repository at this point in the history
This requires the changes in
dtolnay/proc-macro2#331 which expose
Ident::new_raw from proc-macro2, along with providing a fallback for
earlier versions of Rust.

Fixes dtolnay#223
  • Loading branch information
mystor authored and dtolnay committed Jun 20, 2022
1 parent eeabf0d commit ca2b2ed
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -14,7 +14,7 @@ autobenches = false
rust-version = "1.31"

[dependencies]
proc-macro2 = { version = "1.0.36", default-features = false }
proc-macro2 = { version = "1.0.40", default-features = false }

[dev-dependencies]
rustversion = "1.0"
Expand Down
50 changes: 6 additions & 44 deletions src/runtime.rs
Expand Up @@ -205,27 +205,11 @@ fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
}

pub fn push_ident(tokens: &mut TokenStream, s: &str) {
// Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident.
//
// FIXME: When `Ident::new_raw` becomes stable, this method should be
// updated to call it when available.
if s.starts_with("r#") {
parse(tokens, s);
} else {
tokens.append(Ident::new(s, Span::call_site()));
}
tokens.append(mk_ident(s, None));
}

pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
// Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident.
//
// FIXME: When `Ident::new_raw` becomes stable, this method should be
// updated to call it when available.
if s.starts_with("r#") {
parse_spanned(tokens, span, s);
} else {
tokens.append(Ident::new(s, span));
}
tokens.append(mk_ident(s, Some(span)));
}

pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
Expand Down Expand Up @@ -392,36 +376,14 @@ pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) {

// Helper method for constructing identifiers from the `format_ident!` macro,
// handling `r#` prefixes.
//
// Directly parsing the input string may produce a valid identifier,
// although the input string was invalid, due to ignored characters such as
// whitespace and comments. Instead, we always create a non-raw identifier
// to validate that the string is OK, and only parse again if needed.
pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
let span = span.unwrap_or_else(Span::call_site);

let is_raw = id.starts_with("r#");
let unraw = Ident::new(if is_raw { &id[2..] } else { id }, span);
if !is_raw {
return unraw;
}

// At this point, the identifier is raw, and the unraw-ed version of it was
// successfully converted into an identifier. Try to produce a valid raw
// identifier by running the `TokenStream` parser, and unwrapping the first
// token as an `Ident`.
//
// FIXME: When `Ident::new_raw` becomes stable, this method should be
// updated to call it when available.
if let Ok(ts) = id.parse::<TokenStream>() {
let mut iter = ts.into_iter();
if let (Some(TokenTree::Ident(mut id)), None) = (iter.next(), iter.next()) {
id.set_span(span);
return id;
}
if id.starts_with("r#") {
Ident::new_raw(&id[2..], span)
} else {
Ident::new(id, span)
}

panic!("not allowed as a raw identifier: `{}`", id);
}

// Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
Expand Down

0 comments on commit ca2b2ed

Please sign in to comment.