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