loess_rust/lexical_structure/
identifiers.rs1use loess::{Error, ErrorPriority, Errors, Input, IntoTokens, PeekFrom, PopFrom, SimpleSpanned};
2use proc_macro2::{Ident, Span, TokenStream, TokenTree};
3
4#[derive(Clone)]
6pub struct Identifier(pub Ident);
7
8impl PeekFrom for Identifier {
9 fn peek_from(input: &Input) -> bool {
10 matches!(
11 input.front(),
12 Some(TokenTree::Ident(ident))
13 if !(["r#crate", "r#self", "r#super", "r#Self"]
14 .into_iter()
15 .any(|s| ident == s)
16 || is_strict_keyword(&ident)
17 || is_reserved_keyword(&ident)),
18 )
19 }
20}
21
22impl PopFrom for Identifier {
24 fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
25 let ident = Ident::peek_pop_from(input, errors)?;
26
27 match ident {
28 Some(ident)
29 if !(["r#crate", "r#self", "r#super", "r#Self"]
30 .into_iter()
31 .any(|s| ident == s)
32 || is_strict_keyword(&ident)
33 || is_reserved_keyword(&ident)) =>
34 {
35 Ok(Self(ident))
36 }
37 ident => Err(if let Some(ident) = ident {
38 errors.push(Error::new(
39 ErrorPriority::GRAMMAR,
40 if ident.to_string().starts_with("r#") {
41 format!(
42 "Expected Identifier. (`{}` cannot be a raw identifier.)",
43 &ident.to_string()[2..]
44 )
45 } else {
46 format!("Expected Identifier. (`{ident}` is a keyword.)")
47 },
48 [ident.span()],
49 ));
50
51 input.push_front(TokenTree::Ident(ident));
52 } else {
53 errors.push(Error::new(
54 ErrorPriority::GRAMMAR,
55 "Expected Identifier.",
56 [input.front_span()],
57 ));
58 }),
59 }
60 }
61}
62
63impl IntoTokens for Identifier {
64 fn into_tokens(self, root: &TokenStream, tokens: &mut impl Extend<TokenTree>) {
65 self.0.into_tokens(root, tokens)
66 }
67}
68
69impl SimpleSpanned for Identifier {
70 fn span(&self) -> Span {
71 self.0.span()
72 }
73
74 fn set_span(&mut self, span: Span) {
75 self.0.set_span(span)
76 }
77}
78
79pub fn is_strict_keyword(ident: &Ident) -> bool {
81 [
82 "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
83 "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
84 "return", "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe",
85 "use", "where", "while", "async", "await", "dyn",
88 ]
89 .iter()
90 .any(|s| ident == s)
91}
92
93pub fn is_reserved_keyword(ident: &Ident) -> bool {
95 [
96 "abstract", "become", "box", "do", "final", "macro", "override", "priv", "typeof",
97 "unsized", "virtual", "yield", "try", "gen",
102 ]
103 .iter()
104 .any(|s| ident == s)
105}