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 | pub span: $crate::__private::Span, |
95 | } |
96 | |
97 | #[doc(hidden)] |
98 | #[allow(dead_code, non_snake_case)] |
99 | pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>( |
100 | span: __S, |
101 | ) -> $ident { |
102 | $ident { |
103 | span: $crate::__private::IntoSpans::into_spans(span), |
104 | } |
105 | } |
106 | |
107 | const _: () = { |
108 | impl $crate::__private::Default for $ident { |
109 | fn default() -> Self { |
110 | $ident { |
111 | span: $crate::__private::Span::call_site(), |
112 | } |
113 | } |
114 | } |
115 | |
116 | $crate::impl_parse_for_custom_keyword!($ident); |
117 | $crate::impl_to_tokens_for_custom_keyword!($ident); |
118 | $crate::impl_clone_for_custom_keyword!($ident); |
119 | $crate::impl_extra_traits_for_custom_keyword!($ident); |
120 | }; |
121 | }; |
122 | } |
123 | |
124 | // Not public API. |
125 | #[cfg (feature = "parsing" )] |
126 | #[doc (hidden)] |
127 | #[macro_export ] |
128 | macro_rules! impl_parse_for_custom_keyword { |
129 | ($ident:ident) => { |
130 | // For peek. |
131 | impl $crate::__private::CustomToken for $ident { |
132 | fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool { |
133 | if let $crate::__private::Some((ident, _rest)) = cursor.ident() { |
134 | ident == $crate::__private::stringify!($ident) |
135 | } else { |
136 | false |
137 | } |
138 | } |
139 | |
140 | fn display() -> &'static $crate::__private::str { |
141 | $crate::__private::concat!("`" , $crate::__private::stringify!($ident), "`" ) |
142 | } |
143 | } |
144 | |
145 | impl $crate::parse::Parse for $ident { |
146 | fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { |
147 | input.step(|cursor| { |
148 | if let $crate::__private::Some((ident, rest)) = cursor.ident() { |
149 | if ident == $crate::__private::stringify!($ident) { |
150 | return $crate::__private::Ok(($ident { span: ident.span() }, rest)); |
151 | } |
152 | } |
153 | $crate::__private::Err(cursor.error($crate::__private::concat!( |
154 | "expected `" , |
155 | $crate::__private::stringify!($ident), |
156 | "`" , |
157 | ))) |
158 | }) |
159 | } |
160 | } |
161 | }; |
162 | } |
163 | |
164 | // Not public API. |
165 | #[cfg (not(feature = "parsing" ))] |
166 | #[doc (hidden)] |
167 | #[macro_export ] |
168 | macro_rules! impl_parse_for_custom_keyword { |
169 | ($ident:ident) => {}; |
170 | } |
171 | |
172 | // Not public API. |
173 | #[cfg (feature = "printing" )] |
174 | #[doc (hidden)] |
175 | #[macro_export ] |
176 | macro_rules! impl_to_tokens_for_custom_keyword { |
177 | ($ident:ident) => { |
178 | impl $crate::__private::ToTokens for $ident { |
179 | fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { |
180 | let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span); |
181 | $crate::__private::TokenStreamExt::append(tokens, ident); |
182 | } |
183 | } |
184 | }; |
185 | } |
186 | |
187 | // Not public API. |
188 | #[cfg (not(feature = "printing" ))] |
189 | #[doc (hidden)] |
190 | #[macro_export ] |
191 | macro_rules! impl_to_tokens_for_custom_keyword { |
192 | ($ident:ident) => {}; |
193 | } |
194 | |
195 | // Not public API. |
196 | #[cfg (feature = "clone-impls" )] |
197 | #[doc (hidden)] |
198 | #[macro_export ] |
199 | macro_rules! impl_clone_for_custom_keyword { |
200 | ($ident:ident) => { |
201 | impl $crate::__private::Copy for $ident {} |
202 | |
203 | #[allow(clippy::expl_impl_clone_on_copy)] |
204 | impl $crate::__private::Clone for $ident { |
205 | fn clone(&self) -> Self { |
206 | *self |
207 | } |
208 | } |
209 | }; |
210 | } |
211 | |
212 | // Not public API. |
213 | #[cfg (not(feature = "clone-impls" ))] |
214 | #[doc (hidden)] |
215 | #[macro_export ] |
216 | macro_rules! impl_clone_for_custom_keyword { |
217 | ($ident:ident) => {}; |
218 | } |
219 | |
220 | // Not public API. |
221 | #[cfg (feature = "extra-traits" )] |
222 | #[doc (hidden)] |
223 | #[macro_export ] |
224 | macro_rules! impl_extra_traits_for_custom_keyword { |
225 | ($ident:ident) => { |
226 | impl $crate::__private::Debug for $ident { |
227 | fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult { |
228 | $crate::__private::Formatter::write_str( |
229 | f, |
230 | $crate::__private::concat!( |
231 | "Keyword [" , |
232 | $crate::__private::stringify!($ident), |
233 | "]" , |
234 | ), |
235 | ) |
236 | } |
237 | } |
238 | |
239 | impl $crate::__private::Eq for $ident {} |
240 | |
241 | impl $crate::__private::PartialEq for $ident { |
242 | fn eq(&self, _other: &Self) -> $crate::__private::bool { |
243 | true |
244 | } |
245 | } |
246 | |
247 | impl $crate::__private::Hash for $ident { |
248 | fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} |
249 | } |
250 | }; |
251 | } |
252 | |
253 | // Not public API. |
254 | #[cfg (not(feature = "extra-traits" ))] |
255 | #[doc (hidden)] |
256 | #[macro_export ] |
257 | macro_rules! impl_extra_traits_for_custom_keyword { |
258 | ($ident:ident) => {}; |
259 | } |
260 | |