1#[cfg(feature = "parsing")] 2use crate::lookahead; 3 4pub use proc_macro2::Ident; 5 6#[cfg(feature = "parsing")] 7pub_if_not_doc! { 8 #[doc(hidden)] 9 #[allow(non_snake_case)] 10 pub fn Ident(marker: lookahead::TokenMarker) -> Ident { 11 match marker {} 12 } 13} 14 15macro_rules! ident_from_token { 16 ($token:ident) => { 17 impl From<Token![$token]> for Ident { 18 fn from(token: Token![$token]) -> Ident { 19 Ident::new(stringify!($token), token.span) 20 } 21 } 22 }; 23} 24 25ident_from_token!(self); 26ident_from_token!(Self); 27ident_from_token!(super); 28ident_from_token!(crate); 29ident_from_token!(extern); 30 31impl From<Token![_]> for Ident { 32 fn from(token: Token![_]) -> Ident { 33 Ident::new("_", token.span) 34 } 35} 36 37pub(crate) fn xid_ok(symbol: &str) -> bool { 38 let mut chars = symbol.chars(); 39 let first = chars.next().unwrap(); 40 if !(first == '_' || unicode_ident::is_xid_start(first)) { 41 return false; 42 } 43 for ch in chars { 44 if !unicode_ident::is_xid_continue(ch) { 45 return false; 46 } 47 } 48 true 49} 50 51#[cfg(feature = "parsing")] 52mod parsing { 53 use crate::buffer::Cursor; 54 use crate::parse::{Parse, ParseStream, Result}; 55 use crate::token::Token; 56 use proc_macro2::Ident; 57 58 fn accept_as_ident(ident: &Ident) -> bool { 59 match ident.to_string().as_str() { 60 "_" | 61 // Based on https://doc.rust-lang.org/1.65.0/reference/keywords.html 62 "abstract" | "as" | "async" | "await" | "become" | "box" | "break" | 63 "const" | "continue" | "crate" | "do" | "dyn" | "else" | "enum" | 64 "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in" | 65 "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | 66 "override" | "priv" | "pub" | "ref" | "return" | "Self" | "self" | 67 "static" | "struct" | "super" | "trait" | "true" | "try" | "type" | 68 "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | 69 "while" | "yield" => false, 70 _ => true, 71 } 72 } 73 74 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 75 impl Parse for Ident { 76 fn parse(input: ParseStream) -> Result<Self> { 77 input.step(|cursor| { 78 if let Some((ident, rest)) = cursor.ident() { 79 if accept_as_ident(&ident) { 80 Ok((ident, rest)) 81 } else { 82 Err(cursor.error(format_args!( 83 "expected identifier, found keyword `{}`", 84 ident, 85 ))) 86 } 87 } else { 88 Err(cursor.error("expected identifier")) 89 } 90 }) 91 } 92 } 93 94 impl Token for Ident { 95 fn peek(cursor: Cursor) -> bool { 96 if let Some((ident, _rest)) = cursor.ident() { 97 accept_as_ident(&ident) 98 } else { 99 false 100 } 101 } 102 103 fn display() -> &'static str { 104 "identifier" 105 } 106 } 107} 108