standalone_syn/
token.rs

1// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Tokens representing Rust punctuation, keywords, and delimiters.
10//!
11//! The type names in this module can be difficult to keep straight, so we
12//! prefer to use the [`Token!`] macro instead. This is a type-macro that
13//! expands to the token type of the given token.
14//!
15//! [`Token!`]: ../macro.Token.html
16//!
17//! # Example
18//!
19//! The [`ItemStatic`] syntax tree node is defined like this.
20//!
21//! [`ItemStatic`]: ../struct.ItemStatic.html
22//!
23//! ```
24//! # #[macro_use]
25//! # extern crate syn;
26//! #
27//! # use syn::{Attribute, Visibility, Ident, Type, Expr};
28//! #
29//! pub struct ItemStatic {
30//!     pub attrs: Vec<Attribute>,
31//!     pub vis: Visibility,
32//!     pub static_token: Token![static],
33//!     pub mutability: Option<Token![mut]>,
34//!     pub ident: Ident,
35//!     pub colon_token: Token![:],
36//!     pub ty: Box<Type>,
37//!     pub eq_token: Token![=],
38//!     pub expr: Box<Expr>,
39//!     pub semi_token: Token![;],
40//! }
41//! #
42//! # fn main() {}
43//! ```
44//!
45//! # Parsing
46//!
47//! These tokens can be parsed using the [`Synom`] trait and the parser
48//! combinator macros [`punct!`], [`keyword!`], [`parens!`], [`braces!`], and
49//! [`brackets!`].
50//!
51//! [`Synom`]: ../synom/trait.Synom.html
52//! [`punct!`]: ../macro.punct.html
53//! [`keyword!`]: ../macro.keyword.html
54//! [`parens!`]: ../macro.parens.html
55//! [`braces!`]: ../macro.braces.html
56//! [`brackets!`]: ../macro.brackets.html
57//!
58//! ```
59//! #[macro_use]
60//! extern crate syn;
61//!
62//! use syn::synom::Synom;
63//! use syn::{Attribute, Visibility, Ident, Type, Expr};
64//! #
65//! # struct ItemStatic;
66//! # use syn::ItemStatic as SynItemStatic;
67//!
68//! // Parse the ItemStatic struct shown above.
69//! impl Synom for ItemStatic {
70//!     named!(parse -> Self, do_parse!(
71//! #       (ItemStatic)
72//! #   ));
73//! # }
74//! #
75//! # mod example {
76//! #   use super::*;
77//! #   use super::SynItemStatic as ItemStatic;
78//! #
79//! #   named!(parse -> ItemStatic, do_parse!(
80//!         attrs: many0!(Attribute::parse_outer) >>
81//!         vis: syn!(Visibility) >>
82//!         static_token: keyword!(static) >>
83//!         mutability: option!(keyword!(mut)) >>
84//!         ident: syn!(Ident) >>
85//!         colon_token: punct!(:) >>
86//!         ty: syn!(Type) >>
87//!         eq_token: punct!(=) >>
88//!         expr: syn!(Expr) >>
89//!         semi_token: punct!(;) >>
90//!         (ItemStatic {
91//!             attrs, vis, static_token, mutability, ident, colon_token,
92//!             ty: Box::new(ty), eq_token, expr: Box::new(expr), semi_token,
93//!         })
94//!     ));
95//! }
96//! #
97//! # fn main() {}
98//! ```
99
100use proc_macro2::Span;
101
102macro_rules! tokens {
103    (
104        punct: {
105            $($punct:tt pub struct $punct_name:ident/$len:tt #[$punct_doc:meta])*
106        }
107        delimiter: {
108            $($delimiter:tt pub struct $delimiter_name:ident #[$delimiter_doc:meta])*
109        }
110        keyword: {
111            $($keyword:tt pub struct $keyword_name:ident #[$keyword_doc:meta])*
112        }
113    ) => (
114        $(token_punct! { #[$punct_doc] $punct pub struct $punct_name/$len })*
115        $(token_delimiter! { #[$delimiter_doc] $delimiter pub struct $delimiter_name })*
116        $(token_keyword! { #[$keyword_doc] $keyword pub struct $keyword_name })*
117    )
118}
119
120macro_rules! token_punct {
121    (#[$doc:meta] $s:tt pub struct $name:ident/$len:tt) => {
122        #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
123        #[$doc]
124        ///
125        /// Don't try to remember the name of this type -- use the [`Token!`]
126        /// macro instead.
127        ///
128        /// [`Token!`]: index.html
129        pub struct $name(pub [Span; $len]);
130
131        impl $name {
132            pub fn new(span: Span) -> Self {
133                $name([span; $len])
134            }
135        }
136
137        impl ::std::default::Default for $name {
138            fn default() -> Self {
139                $name([Span::def_site(); $len])
140            }
141        }
142
143        #[cfg(feature = "extra-traits")]
144        impl ::std::fmt::Debug for $name {
145            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
146                f.write_str(stringify!($name))
147            }
148        }
149
150        #[cfg(feature = "extra-traits")]
151        impl ::std::cmp::Eq for $name {}
152
153        #[cfg(feature = "extra-traits")]
154        impl ::std::cmp::PartialEq for $name {
155            fn eq(&self, _other: &$name) -> bool {
156                true
157            }
158        }
159
160        #[cfg(feature = "extra-traits")]
161        impl ::std::hash::Hash for $name {
162            fn hash<H>(&self, _state: &mut H)
163                where H: ::std::hash::Hasher
164            {}
165        }
166
167        #[cfg(feature = "printing")]
168        impl ::quote::ToTokens for $name {
169            fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
170                printing::punct($s, &self.0, tokens);
171            }
172        }
173
174        #[cfg(feature = "parsing")]
175        impl ::Synom for $name {
176            fn parse(tokens: $crate::buffer::Cursor) -> $crate::synom::PResult<$name> {
177                parsing::punct($s, tokens, $name)
178            }
179
180            fn description() -> Option<&'static str> {
181                Some(concat!("`", $s, "`"))
182            }
183        }
184
185        impl From<Span> for $name {
186            fn from(span: Span) -> Self {
187                $name([span; $len])
188            }
189        }
190    }
191}
192
193macro_rules! token_keyword {
194    (#[$doc:meta] $s:tt pub struct $name:ident) => {
195        #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
196        #[$doc]
197        ///
198        /// Don't try to remember the name of this type -- use the [`Token!`]
199        /// macro instead.
200        ///
201        /// [`Token!`]: index.html
202        pub struct $name(pub Span);
203
204        impl ::std::default::Default for $name {
205            fn default() -> Self {
206                $name(Span::def_site())
207            }
208        }
209
210        #[cfg(feature = "extra-traits")]
211        impl ::std::fmt::Debug for $name {
212            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
213                f.write_str(stringify!($name))
214            }
215        }
216
217        #[cfg(feature = "extra-traits")]
218        impl ::std::cmp::Eq for $name {}
219
220        #[cfg(feature = "extra-traits")]
221        impl ::std::cmp::PartialEq for $name {
222            fn eq(&self, _other: &$name) -> bool {
223                true
224            }
225        }
226
227        #[cfg(feature = "extra-traits")]
228        impl ::std::hash::Hash for $name {
229            fn hash<H>(&self, _state: &mut H)
230                where H: ::std::hash::Hasher
231            {}
232        }
233
234        #[cfg(feature = "printing")]
235        impl ::quote::ToTokens for $name {
236            fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
237                printing::keyword($s, &self.0, tokens);
238            }
239        }
240
241        #[cfg(feature = "parsing")]
242        impl ::Synom for $name {
243            fn parse(tokens: $crate::buffer::Cursor) -> $crate::synom::PResult<$name> {
244                parsing::keyword($s, tokens, $name)
245            }
246
247            fn description() -> Option<&'static str> {
248                Some(concat!("`", $s, "`"))
249            }
250        }
251
252        impl From<Span> for $name {
253            fn from(span: Span) -> Self {
254                $name(span)
255            }
256        }
257    }
258}
259
260macro_rules! token_delimiter {
261    (#[$doc:meta] $s:tt pub struct $name:ident) => {
262        #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
263        #[$doc]
264        pub struct $name(pub Span);
265
266        impl ::std::default::Default for $name {
267            fn default() -> Self {
268                $name(Span::def_site())
269            }
270        }
271
272        #[cfg(feature = "extra-traits")]
273        impl ::std::fmt::Debug for $name {
274            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
275                f.write_str(stringify!($name))
276            }
277        }
278
279        #[cfg(feature = "extra-traits")]
280        impl ::std::cmp::Eq for $name {}
281
282        #[cfg(feature = "extra-traits")]
283        impl ::std::cmp::PartialEq for $name {
284            fn eq(&self, _other: &$name) -> bool {
285                true
286            }
287        }
288
289        #[cfg(feature = "extra-traits")]
290        impl ::std::hash::Hash for $name {
291            fn hash<H>(&self, _state: &mut H)
292                where H: ::std::hash::Hasher
293            {}
294        }
295
296        impl $name {
297            #[cfg(feature = "printing")]
298            pub fn surround<F>(&self,
299                               tokens: &mut ::quote::Tokens,
300                               f: F)
301                where F: FnOnce(&mut ::quote::Tokens)
302            {
303                printing::delim($s, &self.0, tokens, f);
304            }
305
306            #[cfg(feature = "parsing")]
307            pub fn parse<F, R>(tokens: $crate::buffer::Cursor, f: F) -> $crate::synom::PResult<($name, R)>
308                where F: FnOnce($crate::buffer::Cursor) -> $crate::synom::PResult<R>
309            {
310                parsing::delim($s, tokens, $name, f)
311            }
312        }
313
314        impl From<Span> for $name {
315            fn from(span: Span) -> Self {
316                $name(span)
317            }
318        }
319    }
320}
321
322tokens! {
323    punct: {
324        "+"        pub struct Add/1        /// `+`
325        "+="       pub struct AddEq/2      /// `+=`
326        "&"        pub struct And/1        /// `&`
327        "&&"       pub struct AndAnd/2     /// `&&`
328        "&="       pub struct AndEq/2      /// `&=`
329        "@"        pub struct At/1         /// `@`
330        "!"        pub struct Bang/1       /// `!`
331        "^"        pub struct Caret/1      /// `^`
332        "^="       pub struct CaretEq/2    /// `^=`
333        ":"        pub struct Colon/1      /// `:`
334        "::"       pub struct Colon2/2     /// `::`
335        ","        pub struct Comma/1      /// `,`
336        "/"        pub struct Div/1        /// `/`
337        "/="       pub struct DivEq/2      /// `/=`
338        "."        pub struct Dot/1        /// `.`
339        ".."       pub struct Dot2/2       /// `..`
340        "..."      pub struct Dot3/3       /// `...`
341        "..="      pub struct DotDotEq/3   /// `..=`
342        "="        pub struct Eq/1         /// `=`
343        "=="       pub struct EqEq/2       /// `==`
344        ">="       pub struct Ge/2         /// `>=`
345        ">"        pub struct Gt/1         /// `>`
346        "<="       pub struct Le/2         /// `<=`
347        "<"        pub struct Lt/1         /// `<`
348        "*="       pub struct MulEq/2      /// `*=`
349        "!="       pub struct Ne/2         /// `!=`
350        "|"        pub struct Or/1         /// `|`
351        "|="       pub struct OrEq/2       /// `|=`
352        "||"       pub struct OrOr/2       /// `||`
353        "#"        pub struct Pound/1      /// `#`
354        "?"        pub struct Question/1   /// `?`
355        "->"       pub struct RArrow/2     /// `->`
356        "<-"       pub struct LArrow/2     /// `<-`
357        "%"        pub struct Rem/1        /// `%`
358        "%="       pub struct RemEq/2      /// `%=`
359        "=>"       pub struct Rocket/2     /// `=>`
360        ";"        pub struct Semi/1       /// `;`
361        "<<"       pub struct Shl/2        /// `<<`
362        "<<="      pub struct ShlEq/3      /// `<<=`
363        ">>"       pub struct Shr/2        /// `>>`
364        ">>="      pub struct ShrEq/3      /// `>>=`
365        "*"        pub struct Star/1       /// `*`
366        "-"        pub struct Sub/1        /// `-`
367        "-="       pub struct SubEq/2      /// `-=`
368        "_"        pub struct Underscore/1 /// `_`
369    }
370    delimiter: {
371        "{"        pub struct Brace        /// `{...}`
372        "["        pub struct Bracket      /// `[...]`
373        "("        pub struct Paren        /// `(...)`
374        " "        pub struct Group        /// None-delimited group
375    }
376    keyword: {
377        "as"       pub struct As           /// `as`
378        "auto"     pub struct Auto         /// `auto`
379        "box"      pub struct Box          /// `box`
380        "break"    pub struct Break        /// `break`
381        "Self"     pub struct CapSelf      /// `Self`
382        "catch"    pub struct Catch        /// `catch`
383        "const"    pub struct Const        /// `const`
384        "continue" pub struct Continue     /// `continue`
385        "crate"    pub struct Crate        /// `crate`
386        "default"  pub struct Default      /// `default`
387        "do"       pub struct Do           /// `do`
388        "dyn"      pub struct Dyn          /// `dyn`
389        "else"     pub struct Else         /// `else`
390        "enum"     pub struct Enum         /// `enum`
391        "extern"   pub struct Extern       /// `extern`
392        "fn"       pub struct Fn           /// `fn`
393        "for"      pub struct For          /// `for`
394        "if"       pub struct If           /// `if`
395        "impl"     pub struct Impl         /// `impl`
396        "in"       pub struct In           /// `in`
397        "let"      pub struct Let          /// `let`
398        "loop"     pub struct Loop         /// `loop`
399        "macro"    pub struct Macro        /// `macro`
400        "match"    pub struct Match        /// `match`
401        "mod"      pub struct Mod          /// `mod`
402        "move"     pub struct Move         /// `move`
403        "mut"      pub struct Mut          /// `mut`
404        "pub"      pub struct Pub          /// `pub`
405        "ref"      pub struct Ref          /// `ref`
406        "return"   pub struct Return       /// `return`
407        "self"     pub struct Self_        /// `self`
408        "static"   pub struct Static       /// `static`
409        "struct"   pub struct Struct       /// `struct`
410        "super"    pub struct Super        /// `super`
411        "trait"    pub struct Trait        /// `trait`
412        "type"     pub struct Type         /// `type`
413        "union"    pub struct Union        /// `union`
414        "unsafe"   pub struct Unsafe       /// `unsafe`
415        "use"      pub struct Use          /// `use`
416        "where"    pub struct Where        /// `where`
417        "while"    pub struct While        /// `while`
418        "yield"    pub struct Yield        /// `yield`
419    }
420}
421
422/// A type-macro that expands to the name of the Rust type representation of a
423/// given token.
424///
425/// See the [token module] documentation for details and examples.
426///
427/// [token module]: token/index.html
428// Unfortunate duplication due to a rustdoc bug.
429// https://github.com/rust-lang/rust/issues/45939
430#[macro_export]
431macro_rules! Token {
432    (+)        => { $crate::token::Add };
433    (+=)       => { $crate::token::AddEq };
434    (&)        => { $crate::token::And };
435    (&&)       => { $crate::token::AndAnd };
436    (&=)       => { $crate::token::AndEq };
437    (@)        => { $crate::token::At };
438    (!)        => { $crate::token::Bang };
439    (^)        => { $crate::token::Caret };
440    (^=)       => { $crate::token::CaretEq };
441    (:)        => { $crate::token::Colon };
442    (::)       => { $crate::token::Colon2 };
443    (,)        => { $crate::token::Comma };
444    (/)        => { $crate::token::Div };
445    (/=)       => { $crate::token::DivEq };
446    (.)        => { $crate::token::Dot };
447    (..)       => { $crate::token::Dot2 };
448    (...)      => { $crate::token::Dot3 };
449    (..=)      => { $crate::token::DotDotEq };
450    (=)        => { $crate::token::Eq };
451    (==)       => { $crate::token::EqEq };
452    (>=)       => { $crate::token::Ge };
453    (>)        => { $crate::token::Gt };
454    (<=)       => { $crate::token::Le };
455    (<)        => { $crate::token::Lt };
456    (*=)       => { $crate::token::MulEq };
457    (!=)       => { $crate::token::Ne };
458    (|)        => { $crate::token::Or };
459    (|=)       => { $crate::token::OrEq };
460    (||)       => { $crate::token::OrOr };
461    (#)        => { $crate::token::Pound };
462    (?)        => { $crate::token::Question };
463    (->)       => { $crate::token::RArrow };
464    (<-)       => { $crate::token::LArrow };
465    (%)        => { $crate::token::Rem };
466    (%=)       => { $crate::token::RemEq };
467    (=>)       => { $crate::token::Rocket };
468    (;)        => { $crate::token::Semi };
469    (<<)       => { $crate::token::Shl };
470    (<<=)      => { $crate::token::ShlEq };
471    (>>)       => { $crate::token::Shr };
472    (>>=)      => { $crate::token::ShrEq };
473    (*)        => { $crate::token::Star };
474    (-)        => { $crate::token::Sub };
475    (-=)       => { $crate::token::SubEq };
476    (_)        => { $crate::token::Underscore };
477    (as)       => { $crate::token::As };
478    (auto)     => { $crate::token::Auto };
479    (box)      => { $crate::token::Box };
480    (break)    => { $crate::token::Break };
481    (Self)     => { $crate::token::CapSelf };
482    (catch)    => { $crate::token::Catch };
483    (const)    => { $crate::token::Const };
484    (continue) => { $crate::token::Continue };
485    (crate)    => { $crate::token::Crate };
486    (default)  => { $crate::token::Default };
487    (do)       => { $crate::token::Do };
488    (dyn)      => { $crate::token::Dyn };
489    (else)     => { $crate::token::Else };
490    (enum)     => { $crate::token::Enum };
491    (extern)   => { $crate::token::Extern };
492    (fn)       => { $crate::token::Fn };
493    (for)      => { $crate::token::For };
494    (if)       => { $crate::token::If };
495    (impl)     => { $crate::token::Impl };
496    (in)       => { $crate::token::In };
497    (let)      => { $crate::token::Let };
498    (loop)     => { $crate::token::Loop };
499    (macro)    => { $crate::token::Macro };
500    (match)    => { $crate::token::Match };
501    (mod)      => { $crate::token::Mod };
502    (move)     => { $crate::token::Move };
503    (mut)      => { $crate::token::Mut };
504    (pub)      => { $crate::token::Pub };
505    (ref)      => { $crate::token::Ref };
506    (return)   => { $crate::token::Return };
507    (self)     => { $crate::token::Self_ };
508    (static)   => { $crate::token::Static };
509    (struct)   => { $crate::token::Struct };
510    (super)    => { $crate::token::Super };
511    (trait)    => { $crate::token::Trait };
512    (type)     => { $crate::token::Type };
513    (union)    => { $crate::token::Union };
514    (unsafe)   => { $crate::token::Unsafe };
515    (use)      => { $crate::token::Use };
516    (where)    => { $crate::token::Where };
517    (while)    => { $crate::token::While };
518    (yield)    => { $crate::token::Yield };
519}
520
521/// Parse a single Rust punctuation token.
522///
523/// See the [token module] documentation for details and examples.
524///
525/// [token module]: token/index.html
526///
527/// *This macro is available if Syn is built with the `"parsing"` feature.*
528#[cfg(feature = "parsing")]
529#[macro_export]
530macro_rules! punct {
531    ($i:expr, +)   => { call!($i, <$crate::token::Add as $crate::synom::Synom>::parse) };
532    ($i:expr, +=)  => { call!($i, <$crate::token::AddEq as $crate::synom::Synom>::parse) };
533    ($i:expr, &)   => { call!($i, <$crate::token::And as $crate::synom::Synom>::parse) };
534    ($i:expr, &&)  => { call!($i, <$crate::token::AndAnd as $crate::synom::Synom>::parse) };
535    ($i:expr, &=)  => { call!($i, <$crate::token::AndEq as $crate::synom::Synom>::parse) };
536    ($i:expr, @)   => { call!($i, <$crate::token::At as $crate::synom::Synom>::parse) };
537    ($i:expr, !)   => { call!($i, <$crate::token::Bang as $crate::synom::Synom>::parse) };
538    ($i:expr, ^)   => { call!($i, <$crate::token::Caret as $crate::synom::Synom>::parse) };
539    ($i:expr, ^=)  => { call!($i, <$crate::token::CaretEq as $crate::synom::Synom>::parse) };
540    ($i:expr, :)   => { call!($i, <$crate::token::Colon as $crate::synom::Synom>::parse) };
541    ($i:expr, ::)  => { call!($i, <$crate::token::Colon2 as $crate::synom::Synom>::parse) };
542    ($i:expr, ,)   => { call!($i, <$crate::token::Comma as $crate::synom::Synom>::parse) };
543    ($i:expr, /)   => { call!($i, <$crate::token::Div as $crate::synom::Synom>::parse) };
544    ($i:expr, /=)  => { call!($i, <$crate::token::DivEq as $crate::synom::Synom>::parse) };
545    ($i:expr, .)   => { call!($i, <$crate::token::Dot as $crate::synom::Synom>::parse) };
546    ($i:expr, ..)  => { call!($i, <$crate::token::Dot2 as $crate::synom::Synom>::parse) };
547    ($i:expr, ...) => { call!($i, <$crate::token::Dot3 as $crate::synom::Synom>::parse) };
548    ($i:expr, ..=) => { call!($i, <$crate::token::DotDotEq as $crate::synom::Synom>::parse) };
549    ($i:expr, =)   => { call!($i, <$crate::token::Eq as $crate::synom::Synom>::parse) };
550    ($i:expr, ==)  => { call!($i, <$crate::token::EqEq as $crate::synom::Synom>::parse) };
551    ($i:expr, >=)  => { call!($i, <$crate::token::Ge as $crate::synom::Synom>::parse) };
552    ($i:expr, >)   => { call!($i, <$crate::token::Gt as $crate::synom::Synom>::parse) };
553    ($i:expr, <=)  => { call!($i, <$crate::token::Le as $crate::synom::Synom>::parse) };
554    ($i:expr, <)   => { call!($i, <$crate::token::Lt as $crate::synom::Synom>::parse) };
555    ($i:expr, *=)  => { call!($i, <$crate::token::MulEq as $crate::synom::Synom>::parse) };
556    ($i:expr, !=)  => { call!($i, <$crate::token::Ne as $crate::synom::Synom>::parse) };
557    ($i:expr, |)   => { call!($i, <$crate::token::Or as $crate::synom::Synom>::parse) };
558    ($i:expr, |=)  => { call!($i, <$crate::token::OrEq as $crate::synom::Synom>::parse) };
559    ($i:expr, ||)  => { call!($i, <$crate::token::OrOr as $crate::synom::Synom>::parse) };
560    ($i:expr, #)   => { call!($i, <$crate::token::Pound as $crate::synom::Synom>::parse) };
561    ($i:expr, ?)   => { call!($i, <$crate::token::Question as $crate::synom::Synom>::parse) };
562    ($i:expr, ->)  => { call!($i, <$crate::token::RArrow as $crate::synom::Synom>::parse) };
563    ($i:expr, <-)  => { call!($i, <$crate::token::LArrow as $crate::synom::Synom>::parse) };
564    ($i:expr, %)   => { call!($i, <$crate::token::Rem as $crate::synom::Synom>::parse) };
565    ($i:expr, %=)  => { call!($i, <$crate::token::RemEq as $crate::synom::Synom>::parse) };
566    ($i:expr, =>)  => { call!($i, <$crate::token::Rocket as $crate::synom::Synom>::parse) };
567    ($i:expr, ;)   => { call!($i, <$crate::token::Semi as $crate::synom::Synom>::parse) };
568    ($i:expr, <<)  => { call!($i, <$crate::token::Shl as $crate::synom::Synom>::parse) };
569    ($i:expr, <<=) => { call!($i, <$crate::token::ShlEq as $crate::synom::Synom>::parse) };
570    ($i:expr, >>)  => { call!($i, <$crate::token::Shr as $crate::synom::Synom>::parse) };
571    ($i:expr, >>=) => { call!($i, <$crate::token::ShrEq as $crate::synom::Synom>::parse) };
572    ($i:expr, *)   => { call!($i, <$crate::token::Star as $crate::synom::Synom>::parse) };
573    ($i:expr, -)   => { call!($i, <$crate::token::Sub as $crate::synom::Synom>::parse) };
574    ($i:expr, -=)  => { call!($i, <$crate::token::SubEq as $crate::synom::Synom>::parse) };
575    ($i:expr, _)   => { call!($i, <$crate::token::Underscore as $crate::synom::Synom>::parse) };
576}
577
578/// Parse a single Rust keyword token.
579///
580/// See the [token module] documentation for details and examples.
581///
582/// [token module]: token/index.html
583///
584/// *This macro is available if Syn is built with the `"parsing"` feature.*
585#[cfg(feature = "parsing")]
586#[macro_export]
587macro_rules! keyword {
588    ($i:expr, as)       => { call!($i, <$crate::token::As as $crate::synom::Synom>::parse) };
589    ($i:expr, auto)     => { call!($i, <$crate::token::Auto as $crate::synom::Synom>::parse) };
590    ($i:expr, box)      => { call!($i, <$crate::token::Box as $crate::synom::Synom>::parse) };
591    ($i:expr, break)    => { call!($i, <$crate::token::Break as $crate::synom::Synom>::parse) };
592    ($i:expr, Self)     => { call!($i, <$crate::token::CapSelf as $crate::synom::Synom>::parse) };
593    ($i:expr, catch)    => { call!($i, <$crate::token::Catch as $crate::synom::Synom>::parse) };
594    ($i:expr, const)    => { call!($i, <$crate::token::Const as $crate::synom::Synom>::parse) };
595    ($i:expr, continue) => { call!($i, <$crate::token::Continue as $crate::synom::Synom>::parse) };
596    ($i:expr, crate)    => { call!($i, <$crate::token::Crate as $crate::synom::Synom>::parse) };
597    ($i:expr, default)  => { call!($i, <$crate::token::Default as $crate::synom::Synom>::parse) };
598    ($i:expr, do)       => { call!($i, <$crate::token::Do as $crate::synom::Synom>::parse) };
599    ($i:expr, dyn)      => { call!($i, <$crate::token::Dyn as $crate::synom::Synom>::parse) };
600    ($i:expr, else)     => { call!($i, <$crate::token::Else as $crate::synom::Synom>::parse) };
601    ($i:expr, enum)     => { call!($i, <$crate::token::Enum as $crate::synom::Synom>::parse) };
602    ($i:expr, extern)   => { call!($i, <$crate::token::Extern as $crate::synom::Synom>::parse) };
603    ($i:expr, fn)       => { call!($i, <$crate::token::Fn as $crate::synom::Synom>::parse) };
604    ($i:expr, for)      => { call!($i, <$crate::token::For as $crate::synom::Synom>::parse) };
605    ($i:expr, if)       => { call!($i, <$crate::token::If as $crate::synom::Synom>::parse) };
606    ($i:expr, impl)     => { call!($i, <$crate::token::Impl as $crate::synom::Synom>::parse) };
607    ($i:expr, in)       => { call!($i, <$crate::token::In as $crate::synom::Synom>::parse) };
608    ($i:expr, let)      => { call!($i, <$crate::token::Let as $crate::synom::Synom>::parse) };
609    ($i:expr, loop)     => { call!($i, <$crate::token::Loop as $crate::synom::Synom>::parse) };
610    ($i:expr, macro)    => { call!($i, <$crate::token::Macro as $crate::synom::Synom>::parse) };
611    ($i:expr, match)    => { call!($i, <$crate::token::Match as $crate::synom::Synom>::parse) };
612    ($i:expr, mod)      => { call!($i, <$crate::token::Mod as $crate::synom::Synom>::parse) };
613    ($i:expr, move)     => { call!($i, <$crate::token::Move as $crate::synom::Synom>::parse) };
614    ($i:expr, mut)      => { call!($i, <$crate::token::Mut as $crate::synom::Synom>::parse) };
615    ($i:expr, pub)      => { call!($i, <$crate::token::Pub as $crate::synom::Synom>::parse) };
616    ($i:expr, ref)      => { call!($i, <$crate::token::Ref as $crate::synom::Synom>::parse) };
617    ($i:expr, return)   => { call!($i, <$crate::token::Return as $crate::synom::Synom>::parse) };
618    ($i:expr, self)     => { call!($i, <$crate::token::Self_ as $crate::synom::Synom>::parse) };
619    ($i:expr, static)   => { call!($i, <$crate::token::Static as $crate::synom::Synom>::parse) };
620    ($i:expr, struct)   => { call!($i, <$crate::token::Struct as $crate::synom::Synom>::parse) };
621    ($i:expr, super)    => { call!($i, <$crate::token::Super as $crate::synom::Synom>::parse) };
622    ($i:expr, trait)    => { call!($i, <$crate::token::Trait as $crate::synom::Synom>::parse) };
623    ($i:expr, type)     => { call!($i, <$crate::token::Type as $crate::synom::Synom>::parse) };
624    ($i:expr, union)    => { call!($i, <$crate::token::Union as $crate::synom::Synom>::parse) };
625    ($i:expr, unsafe)   => { call!($i, <$crate::token::Unsafe as $crate::synom::Synom>::parse) };
626    ($i:expr, use)      => { call!($i, <$crate::token::Use as $crate::synom::Synom>::parse) };
627    ($i:expr, where)    => { call!($i, <$crate::token::Where as $crate::synom::Synom>::parse) };
628    ($i:expr, while)    => { call!($i, <$crate::token::While as $crate::synom::Synom>::parse) };
629    ($i:expr, yield)    => { call!($i, <$crate::token::Yield as $crate::synom::Synom>::parse) };
630}
631
632#[cfg(feature = "parsing")]
633mod parsing {
634    use proc_macro2::{Delimiter, Spacing, Span};
635
636    use buffer::Cursor;
637    use parse_error;
638    use synom::PResult;
639
640    pub trait FromSpans: Sized {
641        fn from_spans(spans: &[Span]) -> Self;
642    }
643
644    impl FromSpans for [Span; 1] {
645        fn from_spans(spans: &[Span]) -> Self {
646            [spans[0]]
647        }
648    }
649
650    impl FromSpans for [Span; 2] {
651        fn from_spans(spans: &[Span]) -> Self {
652            [spans[0], spans[1]]
653        }
654    }
655
656    impl FromSpans for [Span; 3] {
657        fn from_spans(spans: &[Span]) -> Self {
658            [spans[0], spans[1], spans[2]]
659        }
660    }
661
662    pub fn punct<'a, T, R>(s: &str, mut tokens: Cursor<'a>, new: fn(T) -> R) -> PResult<'a, R>
663    where
664        T: FromSpans,
665    {
666        let mut spans = [Span::def_site(); 3];
667        assert!(s.len() <= spans.len());
668        let chars = s.chars();
669
670        for (i, (ch, slot)) in chars.zip(&mut spans).enumerate() {
671            match tokens.op() {
672                Some((span, op, kind, rest)) if op == ch => {
673                    if i != s.len() - 1 {
674                        match kind {
675                            Spacing::Joint => {}
676                            _ => return parse_error(),
677                        }
678                    }
679                    *slot = span;
680                    tokens = rest;
681                }
682                _ => return parse_error(),
683            }
684        }
685        Ok((new(T::from_spans(&spans)), tokens))
686    }
687
688    pub fn keyword<'a, T>(keyword: &str, tokens: Cursor<'a>, new: fn(Span) -> T) -> PResult<'a, T> {
689        if let Some((span, term, rest)) = tokens.term() {
690            if term.as_str() == keyword {
691                return Ok((new(span), rest));
692            }
693        }
694        parse_error()
695    }
696
697    pub fn delim<'a, F, R, T>(
698        delim: &str,
699        tokens: Cursor<'a>,
700        new: fn(Span) -> T,
701        f: F,
702    ) -> PResult<'a, (T, R)>
703    where
704        F: FnOnce(Cursor) -> PResult<R>,
705    {
706        // NOTE: We should support none-delimited sequences here.
707        let delim = match delim {
708            "(" => Delimiter::Parenthesis,
709            "{" => Delimiter::Brace,
710            "[" => Delimiter::Bracket,
711            " " => Delimiter::None,
712            _ => panic!("unknown delimiter: {}", delim),
713        };
714
715        if let Some((inside, span, rest)) = tokens.group(delim) {
716            match f(inside) {
717                Ok((ret, remaining)) => {
718                    if remaining.eof() {
719                        return Ok(((new(span), ret), rest));
720                    }
721                }
722                Err(err) => return Err(err),
723            }
724        }
725        parse_error()
726    }
727}
728
729#[cfg(feature = "printing")]
730mod printing {
731    use proc_macro2::{Delimiter, Spacing, Span, Term, TokenNode, TokenTree};
732    use quote::Tokens;
733
734    pub fn punct(s: &str, spans: &[Span], tokens: &mut Tokens) {
735        assert_eq!(s.len(), spans.len());
736
737        let mut chars = s.chars();
738        let mut spans = spans.iter();
739        let ch = chars.next_back().unwrap();
740        let span = spans.next_back().unwrap();
741        for (ch, span) in chars.zip(spans) {
742            tokens.append(TokenTree {
743                span: *span,
744                kind: TokenNode::Op(ch, Spacing::Joint),
745            });
746        }
747
748        tokens.append(TokenTree {
749            span: *span,
750            kind: TokenNode::Op(ch, Spacing::Alone),
751        });
752    }
753
754    pub fn keyword(s: &str, span: &Span, tokens: &mut Tokens) {
755        tokens.append(TokenTree {
756            span: *span,
757            kind: TokenNode::Term(Term::intern(s)),
758        });
759    }
760
761    pub fn delim<F>(s: &str, span: &Span, tokens: &mut Tokens, f: F)
762    where
763        F: FnOnce(&mut Tokens),
764    {
765        let delim = match s {
766            "(" => Delimiter::Parenthesis,
767            "[" => Delimiter::Bracket,
768            "{" => Delimiter::Brace,
769            " " => Delimiter::None,
770            _ => panic!("unknown delimiter: {}", s),
771        };
772        let mut inner = Tokens::new();
773        f(&mut inner);
774        tokens.append(TokenTree {
775            span: *span,
776            kind: TokenNode::Group(delim, inner.into()),
777        });
778    }
779}