Skip to main content

moxy_token/
keyword.rs

1use super::ToTokens;
2use super::lex::{Cursor, LexError, Scan};
3use crate::{Span, Spanner, TokenStream, TokenTree};
4
5macro_rules! define_keyword {
6    ($($name:ident[$is_method:ident, $as_method:ident] => $text:literal),+ $(,)?) => {
7        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8        pub enum Keyword {
9            $($name($name),)*
10        }
11
12        impl Keyword {
13            #[inline]
14            pub fn as_str(&self) -> &'static str {
15                match self {
16                    $(Self::$name(v) => v.as_str(),)*
17                }
18            }
19
20            #[inline]
21            pub fn span(&self) -> Span {
22                match self {
23                    $(Self::$name(v) => v.span(),)*
24                }
25            }
26
27            #[inline]
28            pub fn set_span(&mut self, span: Span) {
29                match self {
30                    $(Self::$name(v) => v.set_span(span),)*
31                }
32            }
33
34            #[inline]
35            pub fn from_str(text: &str, span: Span) -> Option<Self> {
36                match text {
37                    $($text => Some(Self::$name($name::new(span))),)*
38                    _ => None,
39                }
40            }
41
42            #[inline]
43            pub fn to_token_tree(&self) -> TokenTree {
44                TokenTree::Keyword(*self)
45            }
46
47            #[inline]
48            pub fn into_token_tree(self) -> TokenTree {
49                TokenTree::Keyword(self)
50            }
51        }
52
53        impl Scan for Keyword {
54            fn scan(cursor: Cursor<'_>) -> Result<(Cursor<'_>, Self), LexError> {
55                let (end, id) = super::Ident::scan(cursor)?;
56
57                if id.is_raw() {
58                    return cursor.error().into();
59                }
60
61                match id.text() {
62                    $($text => Ok((end, Self::$name($name::new(id.span())))),)*
63                    _ => cursor.error().into(),
64                }
65            }
66        }
67
68        impl ToTokens for Keyword {
69            fn to_tokens(&self, tokens: &mut TokenStream) {
70                match self {
71                    $(Self::$name(v) => v.to_tokens(tokens),)*
72                }
73            }
74        }
75
76        impl Spanner for Keyword {
77            fn span(&self) -> Span {
78                self.span()
79            }
80        }
81
82        impl std::fmt::Display for Keyword {
83            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84                match self {
85                    $(Self::$name(v) => v.fmt(f),)*
86                }
87            }
88        }
89
90        #[cfg(feature = "serde")]
91        impl serde::Serialize for Keyword {
92            fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
93            where
94                S: serde::Serializer,
95            {
96                self.as_str().serialize(s)
97            }
98        }
99
100        $(
101            #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
102            pub struct $name {
103                span: Span,
104            }
105
106            impl $name {
107                pub const TEXT: &'static str = $text;
108
109                #[inline]
110                pub fn new(span: Span) -> Self {
111                    Self { span }
112                }
113
114                #[inline]
115                pub fn span(&self) -> Span {
116                    self.span
117                }
118
119                #[inline]
120                pub fn set_span(&mut self, span: Span) {
121                    self.span = span;
122                }
123
124                #[inline]
125                pub fn as_str(&self) -> &'static str {
126                    Self::TEXT
127                }
128            }
129
130            impl std::fmt::Display for $name {
131                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132                    f.write_str($text)
133                }
134            }
135
136            impl Scan for $name {
137                fn scan(cursor: Cursor<'_>) -> Result<(Cursor<'_>, Self), LexError> {
138                    let (end, id) = super::Ident::scan(cursor)?;
139
140                    if !id.is_raw() && id.text() == $text {
141                        Ok((end, Self::new(id.span())))
142                    } else {
143                        cursor.error().into()
144                    }
145                }
146            }
147
148            impl ToTokens for $name {
149                fn to_tokens(&self, tokens: &mut TokenStream) {
150                    tokens.extend_one(TokenTree::Keyword(Keyword::$name(*self)));
151                }
152            }
153
154            impl Spanner for $name {
155                fn span(&self) -> Span {
156                    self.span
157                }
158            }
159
160            impl From<$name> for Keyword {
161                fn from(value: $name) -> Self {
162                    Self::$name(value)
163                }
164            }
165
166            #[cfg(feature = "serde")]
167            impl serde::Serialize for $name {
168                fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
169                where
170                    S: serde::Serializer,
171                {
172                    self.as_str().serialize(s)
173                }
174            }
175        )+
176
177        impl TokenTree {
178            pub fn is_keyword(&self) -> bool {
179                matches!(self, Self::Keyword(_))
180            }
181
182            pub fn as_keyword(&self) -> Option<&Keyword> {
183                match self {
184                    Self::Keyword(v) => Some(v),
185                    _ => None,
186                }
187            }
188
189            $(
190                #[doc = concat!("**", stringify!($name), "** (\"", $text, "\")")]
191                pub fn $is_method(&self) -> bool {
192                    matches!(self, Self::Keyword(Keyword::$name(_)))
193                }
194
195                #[doc = concat!("**", stringify!($name), "** (\"", $text, "\")")]
196                pub fn $as_method(&self) -> Option<&$name> {
197                    match self {
198                        Self::Keyword(Keyword::$name(v)) => Some(v),
199                        _ => None,
200                    }
201                }
202            )*
203        }
204    };
205}
206
207define_keyword! {
208    As[is_keyword_as, as_keyword_as]                            => "as",
209    Async[is_keyword_async, as_keyword_async]                   => "async",
210    Auto[is_keyword_auto, as_keyword_auto]                      => "auto",
211    Await[is_keyword_await, as_keyword_await]                   => "await",
212    Become[is_keyword_become, as_keyword_become]                => "become",
213    Box[is_keyword_box, as_keyword_box]                         => "box",
214    Break[is_keyword_break, as_keyword_break]                   => "break",
215    Const[is_keyword_const, as_keyword_const]                   => "const",
216    Continue[is_keyword_continue, as_keyword_continue]          => "continue",
217    Crate[is_keyword_crate, as_keyword_crate]                   => "crate",
218    Default[is_keyword_default, as_keyword_default]             => "default",
219    Do[is_keyword_do, as_keyword_do]                            => "do",
220    Dyn[is_keyword_dyn, as_keyword_dyn]                         => "dyn",
221    Else[is_keyword_else, as_keyword_else]                      => "else",
222    Enum[is_keyword_enum, as_keyword_enum]                      => "enum",
223    Extern[is_keyword_extern, as_keyword_extern]                => "extern",
224    Final[is_keyword_final, as_keyword_final]                   => "final",
225    Fn[is_keyword_fn, as_keyword_fn]                            => "fn",
226    For[is_keyword_for, as_keyword_for]                         => "for",
227    If[is_keyword_if, as_keyword_if]                            => "if",
228    Impl[is_keyword_impl, as_keyword_impl]                      => "impl",
229    In[is_keyword_in, as_keyword_in]                            => "in",
230    Let[is_keyword_let, as_keyword_let]                         => "let",
231    Loop[is_keyword_loop, as_keyword_loop]                      => "loop",
232    Macro[is_keyword_macro, as_keyword_macro]                   => "macro",
233    MacroRules[is_keyword_macro_rules, as_keyword_macro_rules]  => "macro_rules",
234    Match[is_keyword_match, as_keyword_match]                   => "match",
235    Mod[is_keyword_mod, as_keyword_mod]                         => "mod",
236    Move[is_keyword_move, as_keyword_move]                      => "move",
237    Mut[is_keyword_mut, as_keyword_mut]                         => "mut",
238    Override[is_keyword_override, as_keyword_override]          => "override",
239    Priv[is_keyword_priv, as_keyword_priv]                      => "priv",
240    Pub[is_keyword_pub, as_keyword_pub]                         => "pub",
241    Raw[is_keyword_raw, as_keyword_raw]                         => "raw",
242    Ref[is_keyword_ref, as_keyword_ref]                         => "ref",
243    Return[is_keyword_return, as_keyword_return]                => "return",
244    SelfType[is_keyword_self_type, as_keyword_self_type]        => "Self",
245    SelfValue[is_keyword_self_value, as_keyword_self_value]     => "self",
246    Static[is_keyword_static, as_keyword_static]                => "static",
247    Struct[is_keyword_struct, as_keyword_struct]                => "struct",
248    Super[is_keyword_super, as_keyword_super]                   => "super",
249    Trait[is_keyword_trait, as_keyword_trait]                   => "trait",
250    Try[is_keyword_try, as_keyword_try]                         => "try",
251    Type[is_keyword_type, as_keyword_type]                      => "type",
252    Typeof[is_keyword_typeof, as_keyword_typeof]                => "typeof",
253    Union[is_keyword_union, as_keyword_union]                   => "union",
254    Unsafe[is_keyword_unsafe, as_keyword_unsafe]                => "unsafe",
255    Unsized[is_keyword_unsized, as_keyword_unsized]             => "unsized",
256    Use[is_keyword_use, as_keyword_use]                         => "use",
257    Virtual[is_keyword_virtual, as_keyword_virtual]             => "virtual",
258    Where[is_keyword_where, as_keyword_where]                   => "where",
259    While[is_keyword_while, as_keyword_while]                   => "while",
260    Yield[is_keyword_yield, as_keyword_yield]                   => "yield",
261}