1 /// Define a type that supports parsing and printing a given identifier as if it
2 /// were a keyword.
3 ///
4 /// # Usage
5 ///
6 /// As a convention, it is recommended that this macro be invoked within a
7 /// module called `kw` or `keyword` and that the resulting parser be invoked
8 /// with a `kw::` or `keyword::` prefix.
9 ///
10 /// ```
11 /// mod kw {
12 ///     syn::custom_keyword!(whatever);
13 /// }
14 /// ```
15 ///
16 /// The generated syntax tree node supports the following operations just like
17 /// any built-in keyword token.
18 ///
19 /// - [Peeking] — `input.peek(kw::whatever)`
20 ///
21 /// - [Parsing] — `input.parse::<kw::whatever>()?`
22 ///
23 /// - [Printing] — `quote!( ... #whatever_token ... )`
24 ///
25 /// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)`
26 ///
27 /// - Field access to its span — `let sp = whatever_token.span`
28 ///
29 /// [Peeking]: crate::parse::ParseBuffer::peek
30 /// [Parsing]: crate::parse::ParseBuffer::parse
31 /// [Printing]: quote::ToTokens
32 /// [`Span`]: proc_macro2::Span
33 ///
34 /// # Example
35 ///
36 /// This example parses input that looks like `bool = true` or `str = "value"`.
37 /// The key must be either the identifier `bool` or the identifier `str`. If
38 /// `bool`, the value may be either `true` or `false`. If `str`, the value may
39 /// be any string literal.
40 ///
41 /// The symbols `bool` and `str` are not reserved keywords in Rust so these are
42 /// not considered keywords in the `syn::token` module. Like any other
43 /// identifier that is not a keyword, these can be declared as custom keywords
44 /// by crates that need to use them as such.
45 ///
46 /// ```
47 /// use syn::{LitBool, LitStr, Result, Token};
48 /// use syn::parse::{Parse, ParseStream};
49 ///
50 /// mod kw {
51 ///     syn::custom_keyword!(bool);
52 ///     syn::custom_keyword!(str);
53 /// }
54 ///
55 /// enum Argument {
56 ///     Bool {
57 ///         bool_token: kw::bool,
58 ///         eq_token: Token![=],
59 ///         value: LitBool,
60 ///     },
61 ///     Str {
62 ///         str_token: kw::str,
63 ///         eq_token: Token![=],
64 ///         value: LitStr,
65 ///     },
66 /// }
67 ///
68 /// impl Parse for Argument {
69 ///     fn parse(input: ParseStream) -> Result<Self> {
70 ///         let lookahead = input.lookahead1();
71 ///         if lookahead.peek(kw::bool) {
72 ///             Ok(Argument::Bool {
73 ///                 bool_token: input.parse::<kw::bool>()?,
74 ///                 eq_token: input.parse()?,
75 ///                 value: input.parse()?,
76 ///             })
77 ///         } else if lookahead.peek(kw::str) {
78 ///             Ok(Argument::Str {
79 ///                 str_token: input.parse::<kw::str>()?,
80 ///                 eq_token: input.parse()?,
81 ///                 value: input.parse()?,
82 ///             })
83 ///         } else {
84 ///             Err(lookahead.error())
85 ///         }
86 ///     }
87 /// }
88 /// ```
89 #[macro_export]
90 macro_rules! custom_keyword {
91     ($ident:ident) => {
92         #[allow(non_camel_case_types)]
93         pub struct $ident {
94             #[allow(dead_code)]
95             pub span: $crate::__private::Span,
96         }
97 
98         #[doc(hidden)]
99         #[allow(dead_code, non_snake_case)]
100         pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>(
101             span: __S,
102         ) -> $ident {
103             $ident {
104                 span: $crate::__private::IntoSpans::into_spans(span),
105             }
106         }
107 
108         const _: () = {
109             impl $crate::__private::Default for $ident {
110                 fn default() -> Self {
111                     $ident {
112                         span: $crate::__private::Span::call_site(),
113                     }
114                 }
115             }
116 
117             $crate::impl_parse_for_custom_keyword!($ident);
118             $crate::impl_to_tokens_for_custom_keyword!($ident);
119             $crate::impl_clone_for_custom_keyword!($ident);
120             $crate::impl_extra_traits_for_custom_keyword!($ident);
121         };
122     };
123 }
124 
125 // Not public API.
126 #[cfg(feature = "parsing")]
127 #[doc(hidden)]
128 #[macro_export]
129 macro_rules! impl_parse_for_custom_keyword {
130     ($ident:ident) => {
131         // For peek.
132         impl $crate::__private::CustomToken for $ident {
133             fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool {
134                 if let $crate::__private::Some((ident, _rest)) = cursor.ident() {
135                     ident == $crate::__private::stringify!($ident)
136                 } else {
137                     false
138                 }
139             }
140 
141             fn display() -> &'static $crate::__private::str {
142                 $crate::__private::concat!("`", $crate::__private::stringify!($ident), "`")
143             }
144         }
145 
146         impl $crate::parse::Parse for $ident {
147             fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
148                 input.step(|cursor| {
149                     if let $crate::__private::Some((ident, rest)) = cursor.ident() {
150                         if ident == $crate::__private::stringify!($ident) {
151                             return $crate::__private::Ok(($ident { span: ident.span() }, rest));
152                         }
153                     }
154                     $crate::__private::Err(cursor.error($crate::__private::concat!(
155                         "expected `",
156                         $crate::__private::stringify!($ident),
157                         "`",
158                     )))
159                 })
160             }
161         }
162     };
163 }
164 
165 // Not public API.
166 #[cfg(not(feature = "parsing"))]
167 #[doc(hidden)]
168 #[macro_export]
169 macro_rules! impl_parse_for_custom_keyword {
170     ($ident:ident) => {};
171 }
172 
173 // Not public API.
174 #[cfg(feature = "printing")]
175 #[doc(hidden)]
176 #[macro_export]
177 macro_rules! impl_to_tokens_for_custom_keyword {
178     ($ident:ident) => {
179         impl $crate::__private::ToTokens for $ident {
180             fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) {
181                 let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span);
182                 $crate::__private::TokenStreamExt::append(tokens, ident);
183             }
184         }
185     };
186 }
187 
188 // Not public API.
189 #[cfg(not(feature = "printing"))]
190 #[doc(hidden)]
191 #[macro_export]
192 macro_rules! impl_to_tokens_for_custom_keyword {
193     ($ident:ident) => {};
194 }
195 
196 // Not public API.
197 #[cfg(feature = "clone-impls")]
198 #[doc(hidden)]
199 #[macro_export]
200 macro_rules! impl_clone_for_custom_keyword {
201     ($ident:ident) => {
202         impl $crate::__private::Copy for $ident {}
203 
204         #[allow(clippy::expl_impl_clone_on_copy)]
205         impl $crate::__private::Clone for $ident {
206             fn clone(&self) -> Self {
207                 *self
208             }
209         }
210     };
211 }
212 
213 // Not public API.
214 #[cfg(not(feature = "clone-impls"))]
215 #[doc(hidden)]
216 #[macro_export]
217 macro_rules! impl_clone_for_custom_keyword {
218     ($ident:ident) => {};
219 }
220 
221 // Not public API.
222 #[cfg(feature = "extra-traits")]
223 #[doc(hidden)]
224 #[macro_export]
225 macro_rules! impl_extra_traits_for_custom_keyword {
226     ($ident:ident) => {
227         impl $crate::__private::Debug for $ident {
228             fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult {
229                 $crate::__private::Formatter::write_str(
230                     f,
231                     $crate::__private::concat!(
232                         "Keyword [",
233                         $crate::__private::stringify!($ident),
234                         "]",
235                     ),
236                 )
237             }
238         }
239 
240         impl $crate::__private::Eq for $ident {}
241 
242         impl $crate::__private::PartialEq for $ident {
243             fn eq(&self, _other: &Self) -> $crate::__private::bool {
244                 true
245             }
246         }
247 
248         impl $crate::__private::Hash for $ident {
249             fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {}
250         }
251     };
252 }
253 
254 // Not public API.
255 #[cfg(not(feature = "extra-traits"))]
256 #[doc(hidden)]
257 #[macro_export]
258 macro_rules! impl_extra_traits_for_custom_keyword {
259     ($ident:ident) => {};
260 }
261