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