1//! Tokens representing Rust punctuation, keywords, and delimiters.
2//!
3//! The type names in this module can be difficult to keep straight, so we
4//! prefer to use the [`Token!`] macro instead. This is a type-macro that
5//! expands to the token type of the given token.
6//!
7//! [`Token!`]: crate::Token
8//!
9//! # Example
10//!
11//! The [`ItemStatic`] syntax tree node is defined like this.
12//!
13//! [`ItemStatic`]: crate::ItemStatic
14//!
15//! ```
16//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility};
17//! #
18//! pub struct ItemStatic {
19//! pub attrs: Vec<Attribute>,
20//! pub vis: Visibility,
21//! pub static_token: Token![static],
22//! pub mutability: Option<Token![mut]>,
23//! pub ident: Ident,
24//! pub colon_token: Token![:],
25//! pub ty: Box<Type>,
26//! pub eq_token: Token![=],
27//! pub expr: Box<Expr>,
28//! pub semi_token: Token![;],
29//! }
30//! ```
31//!
32//! # Parsing
33//!
34//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
35//! method. Delimiter tokens are parsed using the [`parenthesized!`],
36//! [`bracketed!`] and [`braced!`] macros.
37//!
38//! [`ParseStream::parse`]: crate::parse::ParseBuffer::parse()
39//! [`parenthesized!`]: crate::parenthesized!
40//! [`bracketed!`]: crate::bracketed!
41//! [`braced!`]: crate::braced!
42//!
43//! ```
44//! use syn::{Attribute, Result};
45//! use syn::parse::{Parse, ParseStream};
46//! #
47//! # enum ItemStatic {}
48//!
49//! // Parse the ItemStatic struct shown above.
50//! impl Parse for ItemStatic {
51//! fn parse(input: ParseStream) -> Result<Self> {
52//! # use syn::ItemStatic;
53//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
54//! Ok(ItemStatic {
55//! attrs: input.call(Attribute::parse_outer)?,
56//! vis: input.parse()?,
57//! static_token: input.parse()?,
58//! mutability: input.parse()?,
59//! ident: input.parse()?,
60//! colon_token: input.parse()?,
61//! ty: input.parse()?,
62//! eq_token: input.parse()?,
63//! expr: input.parse()?,
64//! semi_token: input.parse()?,
65//! })
66//! # }
67//! # unimplemented!()
68//! }
69//! }
70//! ```
71//!
72//! # Other operations
73//!
74//! Every keyword and punctuation token supports the following operations.
75//!
76//! - [Peeking] — `input.peek(Token![...])`
77//!
78//! - [Parsing] — `input.parse::<Token![...]>()?`
79//!
80//! - [Printing] — `quote!( ... #the_token ... )`
81//!
82//! - Construction from a [`Span`] — `let the_token = Token![...](sp)`
83//!
84//! - Field access to its span — `let sp = the_token.span`
85//!
86//! [Peeking]: crate::parse::ParseBuffer::peek()
87//! [Parsing]: crate::parse::ParseBuffer::parse()
88//! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html
89//! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html
90
91use self::private::WithSpan;
92#[cfg(feature = "parsing")]
93use crate::buffer::Cursor;
94#[cfg(feature = "parsing")]
95use crate::error::Result;
96#[cfg(feature = "parsing")]
97use crate::lifetime::Lifetime;
98#[cfg(feature = "parsing")]
99use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
100#[cfg(feature = "parsing")]
101use crate::lookahead;
102#[cfg(feature = "parsing")]
103use crate::parse::{Parse, ParseStream};
104use crate::span::IntoSpans;
105#[cfg(any(feature = "parsing", feature = "printing"))]
106use proc_macro2::Ident;
107use proc_macro2::Span;
108#[cfg(feature = "printing")]
109use proc_macro2::TokenStream;
110#[cfg(feature = "parsing")]
111use proc_macro2::{Delimiter, Literal, Punct, TokenTree};
112#[cfg(feature = "printing")]
113use quote::{ToTokens, TokenStreamExt};
114#[cfg(feature = "extra-traits")]
115use std::cmp;
116#[cfg(feature = "extra-traits")]
117use std::fmt::{self, Debug};
118#[cfg(feature = "extra-traits")]
119use std::hash::{Hash, Hasher};
120use std::ops::{Deref, DerefMut};
121
122/// Marker trait for types that represent single tokens.
123///
124/// This trait is sealed and cannot be implemented for types outside of Syn.
125#[cfg(feature = "parsing")]
126pub trait Token: private::Sealed {
127 // Not public API.
128 #[doc(hidden)]
129 fn peek(cursor: Cursor) -> bool;
130
131 // Not public API.
132 #[doc(hidden)]
133 fn display() -> &'static str;
134}
135
136mod private {
137 use proc_macro2::Span;
138
139 #[cfg(feature = "parsing")]
140 pub trait Sealed {}
141
142 /// Support writing `token.span` rather than `token.spans[0]` on tokens that
143 /// hold a single span.
144 #[repr(C)]
145 pub struct WithSpan {
146 pub span: Span,
147 }
148}
149
150#[cfg(feature = "parsing")]
151impl private::Sealed for Ident {}
152
153#[cfg(feature = "parsing")]
154fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
155 use crate::parse::Unexpected;
156 use std::cell::Cell;
157 use std::rc::Rc;
158
159 let scope: Span = Span::call_site();
160 let unexpected: Rc> = Rc::new(Cell::new(Unexpected::None));
161 let buffer: ParseBuffer<'_> = crate::parse::new_parse_buffer(scope, cursor, unexpected);
162 peek(&buffer)
163}
164
165macro_rules! impl_token {
166 ($display:tt $name:ty) => {
167 #[cfg(feature = "parsing")]
168 impl Token for $name {
169 fn peek(cursor: Cursor) -> bool {
170 fn peek(input: ParseStream) -> bool {
171 <$name as Parse>::parse(input).is_ok()
172 }
173 peek_impl(cursor, peek)
174 }
175
176 fn display() -> &'static str {
177 $display
178 }
179 }
180
181 #[cfg(feature = "parsing")]
182 impl private::Sealed for $name {}
183 };
184}
185
186impl_token!("lifetime" Lifetime);
187impl_token!("literal" Lit);
188impl_token!("string literal" LitStr);
189impl_token!("byte string literal" LitByteStr);
190impl_token!("byte literal" LitByte);
191impl_token!("character literal" LitChar);
192impl_token!("integer literal" LitInt);
193impl_token!("floating point literal" LitFloat);
194impl_token!("boolean literal" LitBool);
195impl_token!("group token" proc_macro2::Group);
196
197macro_rules! impl_low_level_token {
198 ($display:tt $ty:ident $get:ident) => {
199 #[cfg(feature = "parsing")]
200 impl Token for $ty {
201 fn peek(cursor: Cursor) -> bool {
202 cursor.$get().is_some()
203 }
204
205 fn display() -> &'static str {
206 $display
207 }
208 }
209
210 #[cfg(feature = "parsing")]
211 impl private::Sealed for $ty {}
212 };
213}
214
215impl_low_level_token!("punctuation token" Punct punct);
216impl_low_level_token!("literal" Literal literal);
217impl_low_level_token!("token" TokenTree token_tree);
218
219// Not public API.
220#[doc(hidden)]
221#[cfg(feature = "parsing")]
222pub trait CustomToken {
223 fn peek(cursor: Cursor) -> bool;
224 fn display() -> &'static str;
225}
226
227#[cfg(feature = "parsing")]
228impl<T: CustomToken> private::Sealed for T {}
229
230#[cfg(feature = "parsing")]
231impl<T: CustomToken> Token for T {
232 fn peek(cursor: Cursor) -> bool {
233 <Self as CustomToken>::peek(cursor)
234 }
235
236 fn display() -> &'static str {
237 <Self as CustomToken>::display()
238 }
239}
240
241macro_rules! define_keywords {
242 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
243 $(
244 #[$doc]
245 ///
246 /// Don't try to remember the name of this type &mdash; use the
247 /// [`Token!`] macro instead.
248 ///
249 /// [`Token!`]: crate::token
250 pub struct $name {
251 pub span: Span,
252 }
253
254 #[doc(hidden)]
255 #[allow(non_snake_case)]
256 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
257 $name {
258 span: span.into_spans()[0],
259 }
260 }
261
262 impl std::default::Default for $name {
263 fn default() -> Self {
264 $name {
265 span: Span::call_site(),
266 }
267 }
268 }
269
270 #[cfg(feature = "clone-impls")]
271 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
272 impl Copy for $name {}
273
274 #[cfg(feature = "clone-impls")]
275 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
276 impl Clone for $name {
277 fn clone(&self) -> Self {
278 *self
279 }
280 }
281
282 #[cfg(feature = "extra-traits")]
283 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
284 impl Debug for $name {
285 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286 f.write_str(stringify!($name))
287 }
288 }
289
290 #[cfg(feature = "extra-traits")]
291 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
292 impl cmp::Eq for $name {}
293
294 #[cfg(feature = "extra-traits")]
295 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
296 impl PartialEq for $name {
297 fn eq(&self, _other: &$name) -> bool {
298 true
299 }
300 }
301
302 #[cfg(feature = "extra-traits")]
303 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
304 impl Hash for $name {
305 fn hash<H: Hasher>(&self, _state: &mut H) {}
306 }
307
308 #[cfg(feature = "printing")]
309 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
310 impl ToTokens for $name {
311 fn to_tokens(&self, tokens: &mut TokenStream) {
312 printing::keyword($token, self.span, tokens);
313 }
314 }
315
316 #[cfg(feature = "parsing")]
317 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
318 impl Parse for $name {
319 fn parse(input: ParseStream) -> Result<Self> {
320 Ok($name {
321 span: parsing::keyword(input, $token)?,
322 })
323 }
324 }
325
326 #[cfg(feature = "parsing")]
327 impl Token for $name {
328 fn peek(cursor: Cursor) -> bool {
329 parsing::peek_keyword(cursor, $token)
330 }
331
332 fn display() -> &'static str {
333 concat!("`", $token, "`")
334 }
335 }
336
337 #[cfg(feature = "parsing")]
338 impl private::Sealed for $name {}
339 )*
340 };
341}
342
343macro_rules! impl_deref_if_len_is_1 {
344 ($name:ident/1) => {
345 impl Deref for $name {
346 type Target = WithSpan;
347
348 fn deref(&self) -> &Self::Target {
349 unsafe { &*(self as *const Self as *const WithSpan) }
350 }
351 }
352
353 impl DerefMut for $name {
354 fn deref_mut(&mut self) -> &mut Self::Target {
355 unsafe { &mut *(self as *mut Self as *mut WithSpan) }
356 }
357 }
358 };
359
360 ($name:ident/$len:tt) => {};
361}
362
363macro_rules! define_punctuation_structs {
364 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
365 $(
366 #[repr(C)]
367 #[$doc]
368 ///
369 /// Don't try to remember the name of this type &mdash; use the
370 /// [`Token!`] macro instead.
371 ///
372 /// [`Token!`]: crate::token
373 pub struct $name {
374 pub spans: [Span; $len],
375 }
376
377 #[doc(hidden)]
378 #[allow(non_snake_case)]
379 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
380 $name {
381 spans: spans.into_spans(),
382 }
383 }
384
385 impl std::default::Default for $name {
386 fn default() -> Self {
387 $name {
388 spans: [Span::call_site(); $len],
389 }
390 }
391 }
392
393 #[cfg(feature = "clone-impls")]
394 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
395 impl Copy for $name {}
396
397 #[cfg(feature = "clone-impls")]
398 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
399 impl Clone for $name {
400 fn clone(&self) -> Self {
401 *self
402 }
403 }
404
405 #[cfg(feature = "extra-traits")]
406 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
407 impl Debug for $name {
408 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
409 f.write_str(stringify!($name))
410 }
411 }
412
413 #[cfg(feature = "extra-traits")]
414 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
415 impl cmp::Eq for $name {}
416
417 #[cfg(feature = "extra-traits")]
418 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
419 impl PartialEq for $name {
420 fn eq(&self, _other: &$name) -> bool {
421 true
422 }
423 }
424
425 #[cfg(feature = "extra-traits")]
426 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
427 impl Hash for $name {
428 fn hash<H: Hasher>(&self, _state: &mut H) {}
429 }
430
431 impl_deref_if_len_is_1!($name/$len);
432 )*
433 };
434}
435
436macro_rules! define_punctuation {
437 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
438 $(
439 define_punctuation_structs! {
440 $token pub struct $name/$len #[$doc]
441 }
442
443 #[cfg(feature = "printing")]
444 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
445 impl ToTokens for $name {
446 fn to_tokens(&self, tokens: &mut TokenStream) {
447 printing::punct($token, &self.spans, tokens);
448 }
449 }
450
451 #[cfg(feature = "parsing")]
452 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
453 impl Parse for $name {
454 fn parse(input: ParseStream) -> Result<Self> {
455 Ok($name {
456 spans: parsing::punct(input, $token)?,
457 })
458 }
459 }
460
461 #[cfg(feature = "parsing")]
462 impl Token for $name {
463 fn peek(cursor: Cursor) -> bool {
464 parsing::peek_punct(cursor, $token)
465 }
466
467 fn display() -> &'static str {
468 concat!("`", $token, "`")
469 }
470 }
471
472 #[cfg(feature = "parsing")]
473 impl private::Sealed for $name {}
474 )*
475 };
476}
477
478macro_rules! define_delimiters {
479 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
480 $(
481 #[$doc]
482 pub struct $name {
483 pub span: Span,
484 }
485
486 #[doc(hidden)]
487 #[allow(non_snake_case)]
488 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
489 $name {
490 span: span.into_spans()[0],
491 }
492 }
493
494 impl std::default::Default for $name {
495 fn default() -> Self {
496 $name {
497 span: Span::call_site(),
498 }
499 }
500 }
501
502 #[cfg(feature = "clone-impls")]
503 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
504 impl Copy for $name {}
505
506 #[cfg(feature = "clone-impls")]
507 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
508 impl Clone for $name {
509 fn clone(&self) -> Self {
510 *self
511 }
512 }
513
514 #[cfg(feature = "extra-traits")]
515 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
516 impl Debug for $name {
517 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
518 f.write_str(stringify!($name))
519 }
520 }
521
522 #[cfg(feature = "extra-traits")]
523 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
524 impl cmp::Eq for $name {}
525
526 #[cfg(feature = "extra-traits")]
527 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
528 impl PartialEq for $name {
529 fn eq(&self, _other: &$name) -> bool {
530 true
531 }
532 }
533
534 #[cfg(feature = "extra-traits")]
535 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
536 impl Hash for $name {
537 fn hash<H: Hasher>(&self, _state: &mut H) {}
538 }
539
540 impl $name {
541 #[cfg(feature = "printing")]
542 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
543 where
544 F: FnOnce(&mut TokenStream),
545 {
546 printing::delim($token, self.span, tokens, f);
547 }
548 }
549
550 #[cfg(feature = "parsing")]
551 impl private::Sealed for $name {}
552 )*
553 };
554}
555
556define_punctuation_structs! {
557 "_" pub struct Underscore/1 /// `_`
558}
559
560#[cfg(feature = "printing")]
561#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
562impl ToTokens for Underscore {
563 fn to_tokens(&self, tokens: &mut TokenStream) {
564 tokens.append(token:Ident::new(string:"_", self.span));
565 }
566}
567
568#[cfg(feature = "parsing")]
569#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
570impl Parse for Underscore {
571 fn parse(input: ParseStream) -> Result<Self> {
572 input.step(|cursor: StepCursor<'_, '_>| {
573 if let Some((ident: Ident, rest: Cursor<'_>)) = cursor.ident() {
574 if ident == "_" {
575 return Ok((Underscore(spans:ident.span()), rest));
576 }
577 }
578 if let Some((punct: Punct, rest: Cursor<'_>)) = cursor.punct() {
579 if punct.as_char() == '_' {
580 return Ok((Underscore(spans:punct.span()), rest));
581 }
582 }
583 Err(cursor.error(message:"expected `_`"))
584 })
585 }
586}
587
588#[cfg(feature = "parsing")]
589impl Token for Underscore {
590 fn peek(cursor: Cursor) -> bool {
591 if let Some((ident: Ident, _rest: Cursor<'_>)) = cursor.ident() {
592 return ident == "_";
593 }
594 if let Some((punct: Punct, _rest: Cursor<'_>)) = cursor.punct() {
595 return punct.as_char() == '_';
596 }
597 false
598 }
599
600 fn display() -> &'static str {
601 "`_`"
602 }
603}
604
605#[cfg(feature = "parsing")]
606impl private::Sealed for Underscore {}
607
608#[cfg(feature = "parsing")]
609impl Token for Paren {
610 fn peek(cursor: Cursor) -> bool {
611 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
612 }
613
614 fn display() -> &'static str {
615 "parentheses"
616 }
617}
618
619#[cfg(feature = "parsing")]
620impl Token for Brace {
621 fn peek(cursor: Cursor) -> bool {
622 lookahead::is_delimiter(cursor, Delimiter::Brace)
623 }
624
625 fn display() -> &'static str {
626 "curly braces"
627 }
628}
629
630#[cfg(feature = "parsing")]
631impl Token for Bracket {
632 fn peek(cursor: Cursor) -> bool {
633 lookahead::is_delimiter(cursor, Delimiter::Bracket)
634 }
635
636 fn display() -> &'static str {
637 "square brackets"
638 }
639}
640
641#[cfg(feature = "parsing")]
642impl Token for Group {
643 fn peek(cursor: Cursor) -> bool {
644 lookahead::is_delimiter(cursor, Delimiter::None)
645 }
646
647 fn display() -> &'static str {
648 "invisible group"
649 }
650}
651
652define_keywords! {
653 "abstract" pub struct Abstract /// `abstract`
654 "as" pub struct As /// `as`
655 "async" pub struct Async /// `async`
656 "auto" pub struct Auto /// `auto`
657 "await" pub struct Await /// `await`
658 "become" pub struct Become /// `become`
659 "box" pub struct Box /// `box`
660 "break" pub struct Break /// `break`
661 "const" pub struct Const /// `const`
662 "continue" pub struct Continue /// `continue`
663 "crate" pub struct Crate /// `crate`
664 "default" pub struct Default /// `default`
665 "do" pub struct Do /// `do`
666 "dyn" pub struct Dyn /// `dyn`
667 "else" pub struct Else /// `else`
668 "enum" pub struct Enum /// `enum`
669 "extern" pub struct Extern /// `extern`
670 "final" pub struct Final /// `final`
671 "fn" pub struct Fn /// `fn`
672 "for" pub struct For /// `for`
673 "if" pub struct If /// `if`
674 "impl" pub struct Impl /// `impl`
675 "in" pub struct In /// `in`
676 "let" pub struct Let /// `let`
677 "loop" pub struct Loop /// `loop`
678 "macro" pub struct Macro /// `macro`
679 "match" pub struct Match /// `match`
680 "mod" pub struct Mod /// `mod`
681 "move" pub struct Move /// `move`
682 "mut" pub struct Mut /// `mut`
683 "override" pub struct Override /// `override`
684 "priv" pub struct Priv /// `priv`
685 "pub" pub struct Pub /// `pub`
686 "ref" pub struct Ref /// `ref`
687 "return" pub struct Return /// `return`
688 "Self" pub struct SelfType /// `Self`
689 "self" pub struct SelfValue /// `self`
690 "static" pub struct Static /// `static`
691 "struct" pub struct Struct /// `struct`
692 "super" pub struct Super /// `super`
693 "trait" pub struct Trait /// `trait`
694 "try" pub struct Try /// `try`
695 "type" pub struct Type /// `type`
696 "typeof" pub struct Typeof /// `typeof`
697 "union" pub struct Union /// `union`
698 "unsafe" pub struct Unsafe /// `unsafe`
699 "unsized" pub struct Unsized /// `unsized`
700 "use" pub struct Use /// `use`
701 "virtual" pub struct Virtual /// `virtual`
702 "where" pub struct Where /// `where`
703 "while" pub struct While /// `while`
704 "yield" pub struct Yield /// `yield`
705}
706
707define_punctuation! {
708 "+" pub struct Add/1 /// `+`
709 "+=" pub struct AddEq/2 /// `+=`
710 "&" pub struct And/1 /// `&`
711 "&&" pub struct AndAnd/2 /// `&&`
712 "&=" pub struct AndEq/2 /// `&=`
713 "@" pub struct At/1 /// `@`
714 "!" pub struct Bang/1 /// `!`
715 "^" pub struct Caret/1 /// `^`
716 "^=" pub struct CaretEq/2 /// `^=`
717 ":" pub struct Colon/1 /// `:`
718 "::" pub struct Colon2/2 /// `::`
719 "," pub struct Comma/1 /// `,`
720 "/" pub struct Div/1 /// `/`
721 "/=" pub struct DivEq/2 /// `/=`
722 "$" pub struct Dollar/1 /// `$`
723 "." pub struct Dot/1 /// `.`
724 ".." pub struct Dot2/2 /// `..`
725 "..." pub struct Dot3/3 /// `...`
726 "..=" pub struct DotDotEq/3 /// `..=`
727 "=" pub struct Eq/1 /// `=`
728 "==" pub struct EqEq/2 /// `==`
729 ">=" pub struct Ge/2 /// `>=`
730 ">" pub struct Gt/1 /// `>`
731 "<=" pub struct Le/2 /// `<=`
732 "<" pub struct Lt/1 /// `<`
733 "*=" pub struct MulEq/2 /// `*=`
734 "!=" pub struct Ne/2 /// `!=`
735 "|" pub struct Or/1 /// `|`
736 "|=" pub struct OrEq/2 /// `|=`
737 "||" pub struct OrOr/2 /// `||`
738 "#" pub struct Pound/1 /// `#`
739 "?" pub struct Question/1 /// `?`
740 "->" pub struct RArrow/2 /// `->`
741 "<-" pub struct LArrow/2 /// `<-`
742 "%" pub struct Rem/1 /// `%`
743 "%=" pub struct RemEq/2 /// `%=`
744 "=>" pub struct FatArrow/2 /// `=>`
745 ";" pub struct Semi/1 /// `;`
746 "<<" pub struct Shl/2 /// `<<`
747 "<<=" pub struct ShlEq/3 /// `<<=`
748 ">>" pub struct Shr/2 /// `>>`
749 ">>=" pub struct ShrEq/3 /// `>>=`
750 "*" pub struct Star/1 /// `*`
751 "-" pub struct Sub/1 /// `-`
752 "-=" pub struct SubEq/2 /// `-=`
753 "~" pub struct Tilde/1 /// `~`
754}
755
756define_delimiters! {
757 "{" pub struct Brace /// `{...}`
758 "[" pub struct Bracket /// `[...]`
759 "(" pub struct Paren /// `(...)`
760 " " pub struct Group /// None-delimited group
761}
762
763macro_rules! export_token_macro {
764 ($($await_rule:tt)*) => {
765 /// A type-macro that expands to the name of the Rust type representation of a
766 /// given token.
767 ///
768 /// See the [token module] documentation for details and examples.
769 ///
770 /// [token module]: crate::token
771 // Unfortunate duplication due to a rustdoc bug.
772 // https://github.com/rust-lang/rust/issues/45939
773 #[macro_export]
774 macro_rules! Token {
775 [abstract] => { $crate::token::Abstract };
776 [as] => { $crate::token::As };
777 [async] => { $crate::token::Async };
778 [auto] => { $crate::token::Auto };
779 $($await_rule => { $crate::token::Await };)*
780 [become] => { $crate::token::Become };
781 [box] => { $crate::token::Box };
782 [break] => { $crate::token::Break };
783 [const] => { $crate::token::Const };
784 [continue] => { $crate::token::Continue };
785 [crate] => { $crate::token::Crate };
786 [default] => { $crate::token::Default };
787 [do] => { $crate::token::Do };
788 [dyn] => { $crate::token::Dyn };
789 [else] => { $crate::token::Else };
790 [enum] => { $crate::token::Enum };
791 [extern] => { $crate::token::Extern };
792 [final] => { $crate::token::Final };
793 [fn] => { $crate::token::Fn };
794 [for] => { $crate::token::For };
795 [if] => { $crate::token::If };
796 [impl] => { $crate::token::Impl };
797 [in] => { $crate::token::In };
798 [let] => { $crate::token::Let };
799 [loop] => { $crate::token::Loop };
800 [macro] => { $crate::token::Macro };
801 [match] => { $crate::token::Match };
802 [mod] => { $crate::token::Mod };
803 [move] => { $crate::token::Move };
804 [mut] => { $crate::token::Mut };
805 [override] => { $crate::token::Override };
806 [priv] => { $crate::token::Priv };
807 [pub] => { $crate::token::Pub };
808 [ref] => { $crate::token::Ref };
809 [return] => { $crate::token::Return };
810 [Self] => { $crate::token::SelfType };
811 [self] => { $crate::token::SelfValue };
812 [static] => { $crate::token::Static };
813 [struct] => { $crate::token::Struct };
814 [super] => { $crate::token::Super };
815 [trait] => { $crate::token::Trait };
816 [try] => { $crate::token::Try };
817 [type] => { $crate::token::Type };
818 [typeof] => { $crate::token::Typeof };
819 [union] => { $crate::token::Union };
820 [unsafe] => { $crate::token::Unsafe };
821 [unsized] => { $crate::token::Unsized };
822 [use] => { $crate::token::Use };
823 [virtual] => { $crate::token::Virtual };
824 [where] => { $crate::token::Where };
825 [while] => { $crate::token::While };
826 [yield] => { $crate::token::Yield };
827 [+] => { $crate::token::Add };
828 [+=] => { $crate::token::AddEq };
829 [&] => { $crate::token::And };
830 [&&] => { $crate::token::AndAnd };
831 [&=] => { $crate::token::AndEq };
832 [@] => { $crate::token::At };
833 [!] => { $crate::token::Bang };
834 [^] => { $crate::token::Caret };
835 [^=] => { $crate::token::CaretEq };
836 [:] => { $crate::token::Colon };
837 [::] => { $crate::token::Colon2 };
838 [,] => { $crate::token::Comma };
839 [/] => { $crate::token::Div };
840 [/=] => { $crate::token::DivEq };
841 [$] => { $crate::token::Dollar };
842 [.] => { $crate::token::Dot };
843 [..] => { $crate::token::Dot2 };
844 [...] => { $crate::token::Dot3 };
845 [..=] => { $crate::token::DotDotEq };
846 [=] => { $crate::token::Eq };
847 [==] => { $crate::token::EqEq };
848 [>=] => { $crate::token::Ge };
849 [>] => { $crate::token::Gt };
850 [<=] => { $crate::token::Le };
851 [<] => { $crate::token::Lt };
852 [*=] => { $crate::token::MulEq };
853 [!=] => { $crate::token::Ne };
854 [|] => { $crate::token::Or };
855 [|=] => { $crate::token::OrEq };
856 [||] => { $crate::token::OrOr };
857 [#] => { $crate::token::Pound };
858 [?] => { $crate::token::Question };
859 [->] => { $crate::token::RArrow };
860 [<-] => { $crate::token::LArrow };
861 [%] => { $crate::token::Rem };
862 [%=] => { $crate::token::RemEq };
863 [=>] => { $crate::token::FatArrow };
864 [;] => { $crate::token::Semi };
865 [<<] => { $crate::token::Shl };
866 [<<=] => { $crate::token::ShlEq };
867 [>>] => { $crate::token::Shr };
868 [>>=] => { $crate::token::ShrEq };
869 [*] => { $crate::token::Star };
870 [-] => { $crate::token::Sub };
871 [-=] => { $crate::token::SubEq };
872 [~] => { $crate::token::Tilde };
873 [_] => { $crate::token::Underscore };
874 }
875 };
876}
877
878// Old rustc does not permit `await` appearing anywhere in the source file.
879// https://github.com/rust-lang/rust/issues/57919
880// We put the Token![await] rule in a place that is not lexed by old rustc.
881#[cfg(not(syn_omit_await_from_token_macro))]
882include!("await.rs"); // export_token_macro! {[await]}
883#[cfg(syn_omit_await_from_token_macro)]
884export_token_macro! {}
885
886// Not public API.
887#[doc(hidden)]
888#[cfg(feature = "parsing")]
889pub mod parsing {
890 use crate::buffer::Cursor;
891 use crate::error::{Error, Result};
892 use crate::parse::ParseStream;
893 use crate::span::FromSpans;
894 use proc_macro2::{Spacing, Span};
895
896 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
897 input.step(|cursor| {
898 if let Some((ident, rest)) = cursor.ident() {
899 if ident == token {
900 return Ok((ident.span(), rest));
901 }
902 }
903 Err(cursor.error(format!("expected `{}`", token)))
904 })
905 }
906
907 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
908 if let Some((ident, _rest)) = cursor.ident() {
909 ident == token
910 } else {
911 false
912 }
913 }
914
915 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
916 let mut spans = [input.span(); 3];
917 punct_helper(input, token, &mut spans)?;
918 Ok(S::from_spans(&spans))
919 }
920
921 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
922 input.step(|cursor| {
923 let mut cursor = *cursor;
924 assert!(token.len() <= spans.len());
925
926 for (i, ch) in token.chars().enumerate() {
927 match cursor.punct() {
928 Some((punct, rest)) => {
929 spans[i] = punct.span();
930 if punct.as_char() != ch {
931 break;
932 } else if i == token.len() - 1 {
933 return Ok(((), rest));
934 } else if punct.spacing() != Spacing::Joint {
935 break;
936 }
937 cursor = rest;
938 }
939 None => break,
940 }
941 }
942
943 Err(Error::new(spans[0], format!("expected `{}`", token)))
944 })
945 }
946
947 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
948 for (i, ch) in token.chars().enumerate() {
949 match cursor.punct() {
950 Some((punct, rest)) => {
951 if punct.as_char() != ch {
952 break;
953 } else if i == token.len() - 1 {
954 return true;
955 } else if punct.spacing() != Spacing::Joint {
956 break;
957 }
958 cursor = rest;
959 }
960 None => break,
961 }
962 }
963 false
964 }
965}
966
967// Not public API.
968#[doc(hidden)]
969#[cfg(feature = "printing")]
970pub mod printing {
971 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
972 use quote::TokenStreamExt;
973
974 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
975 assert_eq!(s.len(), spans.len());
976
977 let mut chars = s.chars();
978 let mut spans = spans.iter();
979 let ch = chars.next_back().unwrap();
980 let span = spans.next_back().unwrap();
981 for (ch, span) in chars.zip(spans) {
982 let mut op = Punct::new(ch, Spacing::Joint);
983 op.set_span(*span);
984 tokens.append(op);
985 }
986
987 let mut op = Punct::new(ch, Spacing::Alone);
988 op.set_span(*span);
989 tokens.append(op);
990 }
991
992 pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
993 tokens.append(Ident::new(s, span));
994 }
995
996 pub fn delim<F>(s: &str, span: Span, tokens: &mut TokenStream, f: F)
997 where
998 F: FnOnce(&mut TokenStream),
999 {
1000 let delim = match s {
1001 "(" => Delimiter::Parenthesis,
1002 "[" => Delimiter::Bracket,
1003 "{" => Delimiter::Brace,
1004 " " => Delimiter::None,
1005 _ => panic!("unknown delimiter: {}", s),
1006 };
1007 let mut inner = TokenStream::new();
1008 f(&mut inner);
1009 let mut g = Group::new(delim, inner);
1010 g.set_span(span);
1011 tokens.append(g);
1012 }
1013}
1014