blob: 22008e8c51202733e1df598d4f7fd03eefb1dd9e [file] [log] [blame]
Christopher Durham173a8172018-09-28 15:09:32 -04001// Not public API.
2#[doc(hidden)]
3#[macro_export(local_inner_macros)]
4macro_rules! punct_len {
5 (+) => ( 1usize );
6 (+=) => ( 2usize );
7 (&) => ( 1usize );
8 (&&) => ( 2usize );
9 (&=) => ( 2usize );
10 (@) => ( 1usize );
11 (!) => ( 1usize );
12 (^) => ( 1usize );
13 (^=) => ( 2usize );
14 (:) => ( 1usize );
15 (::) => ( 2usize );
16 (,) => ( 1usize );
17 (/) => ( 1usize );
18 (/=) => ( 2usize );
19 (.) => ( 1usize );
20 (..) => ( 2usize );
21 (...) => ( 3usize );
22 (..=) => ( 3usize );
23 (=) => ( 1usize );
24 (==) => ( 2usize );
25 (>=) => ( 2usize );
26 (>) => ( 1usize );
27 (<=) => ( 2usize );
28 (<) => ( 1usize );
29 (*=) => ( 2usize );
30 (!=) => ( 2usize );
31 (|) => ( 1usize );
32 (|=) => ( 2usize );
33 (||) => ( 2usize );
34 (#) => ( 1usize );
35 (?) => ( 1usize );
36 (->) => ( 2usize );
37 (<-) => ( 2usize );
38 (%) => ( 1usize );
39 (%=) => ( 2usize );
40 (=>) => ( 2usize );
41 (;) => ( 1usize );
42 (<<) => ( 2usize );
43 (<<=) => ( 3usize );
44 (>>) => ( 2usize );
45 (>>=) => ( 3usize );
46 (*) => ( 1usize );
47 (-) => ( 1usize );
48 (-=) => ( 2usize );
49 (~) => ( 1usize );
50 ($tt:tt) => ( compile_error!("Punctuation `{}` is not supported", stringify!($tt)) );
51 ($head:tt $($tail:tt)+) => ( punct_len!($head) $(+ punct_len!($tail))+ );
52}
53
54// Not public API.
55#[doc(hidden)]
56#[macro_export]
57macro_rules! stringify_punct {
58 ($($tt:tt)*) => ( concat!($(stringify!($tt)),*) );
59}
60
61// Not public API.
62// Without this, local_inner_macros breaks when looking for concat!
63#[doc(hidden)]
64#[macro_export]
65macro_rules! my_concat {
66 ($($tt:tt)*) => ( concat!($($tt)*) );
67}
68
69///////////////////////////////////////////////////////////////////////////////
70
71/// Define a type that supports parsing and printing a given identifier as if it
72/// were a keyword.
73///
74/// # Usage
75///
76/// As a convention, it is recommended that this macro be invoked within a
77/// module called `kw` or `keyword` and that the resulting parser be invoked
78/// with a `kw::` or `keyword::` prefix.
79///
80/// ```edition2018
81/// mod kw {
82/// syn::custom_keyword!(whatever);
83/// }
84/// ```
85///
86/// The generated syntax tree node supports the following operations just like
87/// any built-in keyword token.
88///
89/// - [Peeking] — `input.peek(kw::whatever)`
90///
91/// - [Parsing] — `input.parse::<kw::whatever>()?`
92///
93/// - [Printing] — `quote!( ... #whatever_token ... )`
94///
95/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)`
96///
97/// - Field access to its span — `let sp = whatever_token.span`
98///
99/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
100/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
101/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
102/// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html
103///
104/// # Example
105///
106/// This example parses input that looks like `bool = true` or `str = "value"`.
107/// The key must be either the identifier `bool` or the identifier `str`. If
108/// `bool`, the value may be either `true` or `false`. If `str`, the value may
109/// be any string literal.
110///
111/// The symbols `bool` and `str` are not reserved keywords in Rust so these are
112/// not considered keywords in the `syn::token` module. Like any other
113/// identifier that is not a keyword, these can be declared as custom keywords
114/// by crates that need to use them as such.
115///
116/// ```edition2018
117/// use syn::{LitBool, LitStr, Result, Token};
118/// use syn::parse::{Parse, ParseStream};
119///
120/// mod kw {
121/// syn::custom_keyword!(bool);
122/// syn::custom_keyword!(str);
123/// }
124///
125/// enum Argument {
126/// Bool {
127/// bool_token: kw::bool,
128/// eq_token: Token![=],
129/// value: LitBool,
130/// },
131/// Str {
132/// str_token: kw::str,
133/// eq_token: Token![=],
134/// value: LitStr,
135/// },
136/// }
137///
138/// impl Parse for Argument {
139/// fn parse(input: ParseStream) -> Result<Self> {
140/// let lookahead = input.lookahead1();
141/// if lookahead.peek(kw::bool) {
142/// Ok(Argument::Bool {
143/// bool_token: input.parse::<kw::bool>()?,
144/// eq_token: input.parse()?,
145/// value: input.parse()?,
146/// })
147/// } else if lookahead.peek(kw::str) {
148/// Ok(Argument::Str {
149/// str_token: input.parse::<kw::str>()?,
150/// eq_token: input.parse()?,
151/// value: input.parse()?,
152/// })
153/// } else {
154/// Err(lookahead.error())
155/// }
156/// }
157/// }
158/// ```
159#[macro_export(local_inner_macros)]
160macro_rules! custom_keyword {
161 ($ident:ident) => {
162 #[allow(non_camel_case_types)]
163 pub struct $ident {
164 pub span: $crate::export::Span,
165 }
166
167 #[doc(hidden)]
168 #[allow(non_snake_case)]
169 pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; 1]>>(
170 span: __S,
171 ) -> $ident {
172 $ident {
173 span: $crate::export::IntoSpans::into_spans(span)[0],
174 }
175 }
176
177 impl $crate::export::Default for $ident {
178 fn default() -> Self {
179 $ident {
180 span: $crate::export::Span::call_site(),
181 }
182 }
183 }
184
185 impl_parse_for_custom_keyword!($ident);
186 impl_to_tokens_for_custom_keyword!($ident);
187 impl_clone_for_custom_keyword!($ident);
188 impl_extra_traits_for_custom_keyword!($ident);
189 };
190}
191
192// Not public API.
193#[cfg(feature = "parsing")]
194#[doc(hidden)]
195#[macro_export]
196macro_rules! impl_parse_for_custom_keyword {
197 ($ident:ident) => {
198 // For peek.
199 impl $crate::token::CustomKeyword for $ident {
200 fn ident() -> &'static $crate::export::str {
201 stringify!($ident)
202 }
203
204 fn display() -> &'static $crate::export::str {
205 concat!("`", stringify!($ident), "`")
206 }
207 }
208
209 impl $crate::parse::Parse for $ident {
210 fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
211 input.step(|cursor| {
212 if let $crate::export::Some((ident, rest)) = cursor.ident() {
213 if ident == stringify!($ident) {
214 return $crate::export::Ok(($ident { span: ident.span() }, rest));
215 }
216 }
217 $crate::export::Err(cursor.error(concat!(
218 "expected `",
219 stringify!($ident),
220 "`"
221 )))
222 })
223 }
224 }
225 };
226}
227
228// Not public API.
229#[cfg(not(feature = "parsing"))]
230#[doc(hidden)]
231#[macro_export]
232macro_rules! impl_parse_for_custom_keyword {
233 ($ident:ident) => {};
234}
235
236// Not public API.
237#[cfg(feature = "printing")]
238#[doc(hidden)]
239#[macro_export]
240macro_rules! impl_to_tokens_for_custom_keyword {
241 ($ident:ident) => {
242 impl $crate::export::ToTokens for $ident {
243 fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
244 let ident = $crate::Ident::new(stringify!($ident), self.span);
245 $crate::export::TokenStreamExt::append(tokens, ident);
246 }
247 }
248 };
249}
250
251// Not public API.
252#[cfg(not(feature = "printing"))]
253#[doc(hidden)]
254#[macro_export]
255macro_rules! impl_to_tokens_for_custom_keyword {
256 ($ident:ident) => {};
257}
258
259// Not public API.
260#[cfg(feature = "clone-impls")]
261#[doc(hidden)]
262#[macro_export]
263macro_rules! impl_clone_for_custom_keyword {
264 ($ident:ident) => {
265 impl $crate::export::Copy for $ident {}
266
267 impl $crate::export::Clone for $ident {
268 fn clone(&self) -> Self {
269 *self
270 }
271 }
272 };
273}
274
275// Not public API.
276#[cfg(not(feature = "clone-impls"))]
277#[doc(hidden)]
278#[macro_export]
279macro_rules! impl_clone_for_custom_keyword {
280 ($ident:ident) => {};
281}
282
283// Not public API.
284#[cfg(feature = "extra-traits")]
285#[doc(hidden)]
286#[macro_export]
287macro_rules! impl_extra_traits_for_custom_keyword {
288 ($ident:ident) => {
289 impl $crate::export::Debug for $ident {
290 fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
291 $crate::export::Formatter::write_str(f, stringify!($ident))
292 }
293 }
294
295 impl $crate::export::Eq for $ident {}
296
297 impl $crate::export::PartialEq for $ident {
298 fn eq(&self, _other: &Self) -> $crate::export::bool {
299 true
300 }
301 }
302
303 impl $crate::export::Hash for $ident {
304 fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
305 }
306 };
307}
308
309// Not public API.
310#[cfg(not(feature = "extra-traits"))]
311#[doc(hidden)]
312#[macro_export]
313macro_rules! impl_extra_traits_for_custom_keyword {
314 ($ident:ident) => {};
315}
316
317///////////////////////////////////////////////////////////////////////////////
318
319/// Define a type that supports parsing and printing a multi-character symbol
320/// as if it were a token.
321///
322/// # Usage
323///
324/// As a convention, it is recommended that this macro be invoked within a
325/// module called `punct` or `punctuation` and that the resulting parser be invoked
326/// with a `punct::` or `punctuation::` prefix.
327///
328/// ```edition2018
329/// mod punct {
330/// syn::custom_punctuation!(LeftRightArrow, <=>);
331/// }
332/// ```
333///
334/// The generated syntax tree node supports the following operations just like
335/// any built-in punctuation token.
336///
337/// - [Peeking] — `input.peek(punct::LeftRightArrow)`
338///
339/// - [Parsing] — `input.parse::<punct::LeftRightArrow>()?`
340///
341/// - [Printing] — `quote!( ... #left_right_arrow ... )`
342///
343/// - Construction from a [`Span`] — `let left_right_arrow = punct::LeftRightArrow(sp)`
344///
345/// - Construction from multiple [`Span`] — `let left_right_arrow = punct::LeftRightArrow([sp, sp, sp])`
346///
347/// - Field access to its spans — `let spans = left_right_arrow.spans`
348///
349/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
350/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
351/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
352/// [`Span`]: struct.Span.html
353///
354/// # Example
355///
356/// ```edition2018
357/// use syn::Expr;
358/// use syn::punctuated::Punctuated;
359/// use syn::parse::{Parse, ParseStream, Result};
360/// use syn::token::Paren;
361///
362/// mod punct {
363/// syn::custom_punctuation!(PathSeparator, </>);
364/// }
365///
366/// // (expr) </> (expr) </> (expr) ...
367/// struct PathSegments {
368/// segments: Punctuated<Expr, punct::PathSeparator>,
369/// }
370///
371/// impl Parse for PathSegments {
372/// fn parse(input: ParseStream) -> Result<Self> {
373/// let mut segments = Punctuated::new();
374///
375/// let la = input.lookahead1();
376/// if la.peek(Paren) {
377/// segments.push_value(input.parse()?);
378/// } else {
379/// return Err(la.error());
380/// }
381///
382/// while input.peek(punct::PathSeparator) {
383/// segments.push_punct(input.parse()?);
384/// segments.push_value(input.parse()?);
385/// }
386///
387/// Ok(PathSegments { segments })
388/// }
389/// }
390///
391/// let _: PathSegments = syn::parse_str(stringify!(("five") </> ("hundred"))).unwrap();
392/// ```
393///
394#[macro_export(local_inner_macros)]
395macro_rules! custom_punctuation {
396 ($ident:ident, $($tt:tt)*) => {
397 pub struct $ident {
398 pub spans: [$crate::export::Span; punct_len!($($tt)*)],
399 }
400
401 #[doc(hidden)]
402 #[allow(non_snake_case)]
403 pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; punct_len!($($tt)*)]>>(
404 spans: __S,
405 ) -> $ident {
406 $ident {
407 spans: $crate::export::IntoSpans::into_spans(spans)
408 }
409 }
410
411 impl $crate::export::Default for $ident {
412 fn default() -> Self {
413 $ident($crate::export::Span::call_site())
414 }
415 }
416
417 impl_parsing_for_custom_punctuation!($ident, $($tt)*);
418 impl_printing_for_custom_punctuation!($ident, $($tt)*);
419 impl_clone_for_custom_punctuation!($ident, $($tt)*);
420 impl_extra_traits_for_custom_punctuation!($ident, $($tt)*);
421 };
422}
423
424// Not public API.
425#[cfg(feature = "parsing")]
426#[doc(hidden)]
427#[macro_export(local_inner_macros)]
428macro_rules! impl_parsing_for_custom_punctuation {
429 ($ident: ident, $($tt:tt)*) => {
430 impl $crate::token::CustomToken for $ident {
431 fn peek(cursor: $crate::buffer::Cursor) -> bool {
432 $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)*))
433 }
434
435 fn display() -> &'static $crate::export::str {
436 my_concat!("`", stringify_punct!($($tt)*), "`")
437 }
438 }
439
440 impl $crate::parse::Parse for $ident {
441 fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
442 let spans: [$crate::export::Span; punct_len!($($tt)*)] =
443 $crate::token::parsing::punct(input, stringify_punct!($($tt)*))?;
444 Ok($ident(spans))
445 }
446 }
447 };
448}
449
450// Not public API.
451#[cfg(not(feature = "parsing"))]
452#[doc(hidden)]
453#[macro_export]
454macro_rules! impl_parsing_for_custom_punctuation {
455 ($ident: ident, $($tt:tt)*) => {};
456}
457
458// Not public API.
459#[cfg(feature = "printing")]
460#[doc(hidden)]
461#[macro_export(local_inner_macros)]
462macro_rules! impl_printing_for_custom_punctuation {
463 ($ident: ident, $($tt:tt)*) => {
464 impl $crate::export::ToTokens for $ident {
465 fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
466 $crate::token::printing::punct(stringify_punct!($($tt)*), &self.spans, tokens)
467 }
468 }
469 };
470}
471
472// Not public API.
473#[cfg(not(feature = "printing"))]
474#[doc(hidden)]
475#[macro_export]
476macro_rules! impl_printing_for_custom_punctuation {
477 ($ident: ident, $($tt:tt)*) => {};
478}
479
480// Not public API.
481#[cfg(feature = "clone-impls")]
482#[doc(hidden)]
483#[macro_export]
484macro_rules! impl_clone_for_custom_punctuation {
485 ($ident: ident, $($tt:tt)*) => {
486 impl $crate::export::Copy for $ident {}
487
488 impl $crate::export::Clone for $ident {
489 fn clone(&self) -> Self {
490 *self
491 }
492 }
493 };
494}
495
496// Not public API.
497#[cfg(not(feature = "clone-impls"))]
498#[doc(hidden)]
499#[macro_export]
500macro_rules! impl_clone_for_custom_punctuation {
501 ($ident: ident, $($tt:tt)*) => {};
502}
503
504// Not public API.
505#[cfg(feature = "extra-traits")]
506#[doc(hidden)]
507#[macro_export(local_inner_macros)]
508macro_rules! impl_extra_traits_for_custom_punctuation {
509 ($ident: ident, $($tt:tt)*) => {
510 impl $crate::export::Debug for $ident {
511 fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
512 $crate::export::Formatter::write_str(f, stringify_punct!($($tt)*))
513 }
514 }
515
516 impl $crate::export::Eq for $ident {}
517
518 impl $crate::export::PartialEq for $ident {
519 fn eq(&self, _other: &Self) -> $crate::export::bool {
520 true
521 }
522 }
523
524 impl $crate::export::Hash for $ident {
525 fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
526 }
527 };
528}
529
530// Not public API.
531#[cfg(not(feature = "extra-traits"))]
532#[doc(hidden)]
533#[macro_export]
534macro_rules! impl_extra_traits_for_custom_punctuation {
535 ($ident: ident, $($tt:tt)*) => {};
536}