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`
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
91 #[cfg(feature = "parsing")]
92 pub(crate) use self::private::CustomToken;
93 use self::private::WithSpan;
94 #[cfg(feature = "parsing")]
95 use crate::buffer::Cursor;
96 #[cfg(feature = "parsing")]
97 use crate::error::Result;
98 #[cfg(feature = "parsing")]
99 use crate::lifetime::Lifetime;
100 #[cfg(feature = "parsing")]
101 use crate::parse::{Parse, ParseStream};
102 use crate::span::IntoSpans;
103 use proc_macro2::extra::DelimSpan;
104 use proc_macro2::Span;
105 #[cfg(feature = "printing")]
106 use proc_macro2::TokenStream;
107 #[cfg(any(feature = "parsing", feature = "printing"))]
108 use proc_macro2::{Delimiter, Ident};
109 #[cfg(feature = "parsing")]
110 use proc_macro2::{Literal, Punct, TokenTree};
111 #[cfg(feature = "printing")]
112 use quote::{ToTokens, TokenStreamExt};
113 #[cfg(feature = "extra-traits")]
114 use std::cmp;
115 #[cfg(feature = "extra-traits")]
116 use std::fmt::{self, Debug};
117 #[cfg(feature = "extra-traits")]
118 use std::hash::{Hash, Hasher};
119 use std::ops::{Deref, DerefMut};
120
121 /// Marker trait for types that represent single tokens.
122 ///
123 /// This trait is sealed and cannot be implemented for types outside of Syn.
124 #[cfg(feature = "parsing")]
125 pub trait Token: private::Sealed {
126 // Not public API.
127 #[doc(hidden)]
peek(cursor: Cursor) -> bool128 fn peek(cursor: Cursor) -> bool;
129
130 // Not public API.
131 #[doc(hidden)]
display() -> &'static str132 fn display() -> &'static str;
133 }
134
135 pub(crate) mod private {
136 #[cfg(feature = "parsing")]
137 use crate::buffer::Cursor;
138 use proc_macro2::Span;
139
140 #[cfg(feature = "parsing")]
141 pub trait Sealed {}
142
143 /// Support writing `token.span` rather than `token.spans[0]` on tokens that
144 /// hold a single span.
145 #[repr(transparent)]
146 #[allow(unknown_lints, repr_transparent_external_private_fields)] // False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
147 pub struct WithSpan {
148 pub span: Span,
149 }
150
151 // Not public API.
152 #[doc(hidden)]
153 #[cfg(feature = "parsing")]
154 pub trait CustomToken {
peek(cursor: Cursor) -> bool155 fn peek(cursor: Cursor) -> bool;
display() -> &'static str156 fn display() -> &'static str;
157 }
158 }
159
160 #[cfg(feature = "parsing")]
161 impl private::Sealed for Ident {}
162
163 macro_rules! impl_low_level_token {
164 ($display:literal $($path:ident)::+ $get:ident) => {
165 #[cfg(feature = "parsing")]
166 impl Token for $($path)::+ {
167 fn peek(cursor: Cursor) -> bool {
168 cursor.$get().is_some()
169 }
170
171 fn display() -> &'static str {
172 $display
173 }
174 }
175
176 #[cfg(feature = "parsing")]
177 impl private::Sealed for $($path)::+ {}
178 };
179 }
180
181 impl_low_level_token!("punctuation token" Punct punct);
182 impl_low_level_token!("literal" Literal literal);
183 impl_low_level_token!("token" TokenTree token_tree);
184 impl_low_level_token!("group token" proc_macro2::Group any_group);
185 impl_low_level_token!("lifetime" Lifetime lifetime);
186
187 #[cfg(feature = "parsing")]
188 impl<T: CustomToken> private::Sealed for T {}
189
190 #[cfg(feature = "parsing")]
191 impl<T: CustomToken> Token for T {
peek(cursor: Cursor) -> bool192 fn peek(cursor: Cursor) -> bool {
193 <Self as CustomToken>::peek(cursor)
194 }
195
display() -> &'static str196 fn display() -> &'static str {
197 <Self as CustomToken>::display()
198 }
199 }
200
201 macro_rules! define_keywords {
202 ($($token:literal pub struct $name:ident)*) => {
203 $(
204 #[doc = concat!('`', $token, '`')]
205 ///
206 /// Don't try to remember the name of this type — use the
207 /// [`Token!`] macro instead.
208 ///
209 /// [`Token!`]: crate::token
210 pub struct $name {
211 pub span: Span,
212 }
213
214 #[doc(hidden)]
215 #[allow(non_snake_case)]
216 pub fn $name<S: IntoSpans<Span>>(span: S) -> $name {
217 $name {
218 span: span.into_spans(),
219 }
220 }
221
222 impl std::default::Default for $name {
223 fn default() -> Self {
224 $name {
225 span: Span::call_site(),
226 }
227 }
228 }
229
230 #[cfg(feature = "clone-impls")]
231 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
232 impl Copy for $name {}
233
234 #[cfg(feature = "clone-impls")]
235 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
236 impl Clone for $name {
237 fn clone(&self) -> Self {
238 *self
239 }
240 }
241
242 #[cfg(feature = "extra-traits")]
243 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
244 impl Debug for $name {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 f.write_str(stringify!($name))
247 }
248 }
249
250 #[cfg(feature = "extra-traits")]
251 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
252 impl cmp::Eq for $name {}
253
254 #[cfg(feature = "extra-traits")]
255 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
256 impl PartialEq for $name {
257 fn eq(&self, _other: &$name) -> bool {
258 true
259 }
260 }
261
262 #[cfg(feature = "extra-traits")]
263 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
264 impl Hash for $name {
265 fn hash<H: Hasher>(&self, _state: &mut H) {}
266 }
267
268 #[cfg(feature = "printing")]
269 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
270 impl ToTokens for $name {
271 fn to_tokens(&self, tokens: &mut TokenStream) {
272 printing::keyword($token, self.span, tokens);
273 }
274 }
275
276 #[cfg(feature = "parsing")]
277 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
278 impl Parse for $name {
279 fn parse(input: ParseStream) -> Result<Self> {
280 Ok($name {
281 span: parsing::keyword(input, $token)?,
282 })
283 }
284 }
285
286 #[cfg(feature = "parsing")]
287 impl Token for $name {
288 fn peek(cursor: Cursor) -> bool {
289 parsing::peek_keyword(cursor, $token)
290 }
291
292 fn display() -> &'static str {
293 concat!("`", $token, "`")
294 }
295 }
296
297 #[cfg(feature = "parsing")]
298 impl private::Sealed for $name {}
299 )*
300 };
301 }
302
303 macro_rules! impl_deref_if_len_is_1 {
304 ($name:ident/1) => {
305 impl Deref for $name {
306 type Target = WithSpan;
307
308 fn deref(&self) -> &Self::Target {
309 unsafe { &*(self as *const Self).cast::<WithSpan>() }
310 }
311 }
312
313 impl DerefMut for $name {
314 fn deref_mut(&mut self) -> &mut Self::Target {
315 unsafe { &mut *(self as *mut Self).cast::<WithSpan>() }
316 }
317 }
318 };
319
320 ($name:ident/$len:literal) => {};
321 }
322
323 macro_rules! define_punctuation_structs {
324 ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
325 $(
326 #[cfg_attr(not(doc), repr(transparent))]
327 #[allow(unknown_lints, repr_transparent_external_private_fields)] // False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
328 #[doc = concat!('`', $token, '`')]
329 ///
330 /// Usage:
331 #[doc = concat!($usage, '.')]
332 ///
333 /// Don't try to remember the name of this type — use the
334 /// [`Token!`] macro instead.
335 ///
336 /// [`Token!`]: crate::token
337 pub struct $name {
338 pub spans: [Span; $len],
339 }
340
341 #[doc(hidden)]
342 #[allow(non_snake_case)]
343 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
344 $name {
345 spans: spans.into_spans(),
346 }
347 }
348
349 impl std::default::Default for $name {
350 fn default() -> Self {
351 $name {
352 spans: [Span::call_site(); $len],
353 }
354 }
355 }
356
357 #[cfg(feature = "clone-impls")]
358 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
359 impl Copy for $name {}
360
361 #[cfg(feature = "clone-impls")]
362 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
363 impl Clone for $name {
364 fn clone(&self) -> Self {
365 *self
366 }
367 }
368
369 #[cfg(feature = "extra-traits")]
370 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
371 impl Debug for $name {
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 f.write_str(stringify!($name))
374 }
375 }
376
377 #[cfg(feature = "extra-traits")]
378 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
379 impl cmp::Eq for $name {}
380
381 #[cfg(feature = "extra-traits")]
382 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
383 impl PartialEq for $name {
384 fn eq(&self, _other: &$name) -> bool {
385 true
386 }
387 }
388
389 #[cfg(feature = "extra-traits")]
390 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
391 impl Hash for $name {
392 fn hash<H: Hasher>(&self, _state: &mut H) {}
393 }
394
395 impl_deref_if_len_is_1!($name/$len);
396 )*
397 };
398 }
399
400 macro_rules! define_punctuation {
401 ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
402 $(
403 define_punctuation_structs! {
404 $token pub struct $name/$len #[doc = $usage]
405 }
406
407 #[cfg(feature = "printing")]
408 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
409 impl ToTokens for $name {
410 fn to_tokens(&self, tokens: &mut TokenStream) {
411 printing::punct($token, &self.spans, tokens);
412 }
413 }
414
415 #[cfg(feature = "parsing")]
416 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
417 impl Parse for $name {
418 fn parse(input: ParseStream) -> Result<Self> {
419 Ok($name {
420 spans: parsing::punct(input, $token)?,
421 })
422 }
423 }
424
425 #[cfg(feature = "parsing")]
426 impl Token for $name {
427 fn peek(cursor: Cursor) -> bool {
428 parsing::peek_punct(cursor, $token)
429 }
430
431 fn display() -> &'static str {
432 concat!("`", $token, "`")
433 }
434 }
435
436 #[cfg(feature = "parsing")]
437 impl private::Sealed for $name {}
438 )*
439 };
440 }
441
442 macro_rules! define_delimiters {
443 ($($delim:ident pub struct $name:ident #[$doc:meta])*) => {
444 $(
445 #[$doc]
446 pub struct $name {
447 pub span: DelimSpan,
448 }
449
450 #[doc(hidden)]
451 #[allow(non_snake_case)]
452 pub fn $name<S: IntoSpans<DelimSpan>>(span: S) -> $name {
453 $name {
454 span: span.into_spans(),
455 }
456 }
457
458 impl std::default::Default for $name {
459 fn default() -> Self {
460 $name(Span::call_site())
461 }
462 }
463
464 #[cfg(feature = "clone-impls")]
465 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
466 impl Copy for $name {}
467
468 #[cfg(feature = "clone-impls")]
469 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
470 impl Clone for $name {
471 fn clone(&self) -> Self {
472 *self
473 }
474 }
475
476 #[cfg(feature = "extra-traits")]
477 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
478 impl Debug for $name {
479 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
480 f.write_str(stringify!($name))
481 }
482 }
483
484 #[cfg(feature = "extra-traits")]
485 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
486 impl cmp::Eq for $name {}
487
488 #[cfg(feature = "extra-traits")]
489 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
490 impl PartialEq for $name {
491 fn eq(&self, _other: &$name) -> bool {
492 true
493 }
494 }
495
496 #[cfg(feature = "extra-traits")]
497 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
498 impl Hash for $name {
499 fn hash<H: Hasher>(&self, _state: &mut H) {}
500 }
501
502 impl $name {
503 #[cfg(feature = "printing")]
504 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
505 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
506 where
507 F: FnOnce(&mut TokenStream),
508 {
509 let mut inner = TokenStream::new();
510 f(&mut inner);
511 printing::delim(Delimiter::$delim, self.span.join(), tokens, inner);
512 }
513 }
514
515 #[cfg(feature = "parsing")]
516 impl private::Sealed for $name {}
517 )*
518 };
519 }
520
521 define_punctuation_structs! {
522 "_" pub struct Underscore/1 /// wildcard patterns, inferred types, unnamed items in constants, extern crates, use declarations, and destructuring assignment
523 }
524
525 #[cfg(feature = "printing")]
526 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
527 impl ToTokens for Underscore {
to_tokens(&self, tokens: &mut TokenStream)528 fn to_tokens(&self, tokens: &mut TokenStream) {
529 tokens.append(Ident::new("_", self.span));
530 }
531 }
532
533 #[cfg(feature = "parsing")]
534 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
535 impl Parse for Underscore {
parse(input: ParseStream) -> Result<Self>536 fn parse(input: ParseStream) -> Result<Self> {
537 input.step(|cursor| {
538 if let Some((ident, rest)) = cursor.ident() {
539 if ident == "_" {
540 return Ok((Underscore(ident.span()), rest));
541 }
542 }
543 if let Some((punct, rest)) = cursor.punct() {
544 if punct.as_char() == '_' {
545 return Ok((Underscore(punct.span()), rest));
546 }
547 }
548 Err(cursor.error("expected `_`"))
549 })
550 }
551 }
552
553 #[cfg(feature = "parsing")]
554 impl Token for Underscore {
peek(cursor: Cursor) -> bool555 fn peek(cursor: Cursor) -> bool {
556 if let Some((ident, _rest)) = cursor.ident() {
557 return ident == "_";
558 }
559 if let Some((punct, _rest)) = cursor.punct() {
560 return punct.as_char() == '_';
561 }
562 false
563 }
564
display() -> &'static str565 fn display() -> &'static str {
566 "`_`"
567 }
568 }
569
570 #[cfg(feature = "parsing")]
571 impl private::Sealed for Underscore {}
572
573 /// None-delimited group
574 pub struct Group {
575 pub span: Span,
576 }
577
578 #[doc(hidden)]
579 #[allow(non_snake_case)]
Group<S: IntoSpans<Span>>(span: S) -> Group580 pub fn Group<S: IntoSpans<Span>>(span: S) -> Group {
581 Group {
582 span: span.into_spans(),
583 }
584 }
585
586 impl std::default::Default for Group {
default() -> Self587 fn default() -> Self {
588 Group {
589 span: Span::call_site(),
590 }
591 }
592 }
593
594 #[cfg(feature = "clone-impls")]
595 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
596 impl Copy for Group {}
597
598 #[cfg(feature = "clone-impls")]
599 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
600 impl Clone for Group {
clone(&self) -> Self601 fn clone(&self) -> Self {
602 *self
603 }
604 }
605
606 #[cfg(feature = "extra-traits")]
607 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
608 impl Debug for Group {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result609 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
610 f.write_str("Group")
611 }
612 }
613
614 #[cfg(feature = "extra-traits")]
615 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
616 impl cmp::Eq for Group {}
617
618 #[cfg(feature = "extra-traits")]
619 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
620 impl PartialEq for Group {
eq(&self, _other: &Group) -> bool621 fn eq(&self, _other: &Group) -> bool {
622 true
623 }
624 }
625
626 #[cfg(feature = "extra-traits")]
627 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
628 impl Hash for Group {
hash<H: Hasher>(&self, _state: &mut H)629 fn hash<H: Hasher>(&self, _state: &mut H) {}
630 }
631
632 impl Group {
633 #[cfg(feature = "printing")]
634 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
surround<F>(&self, tokens: &mut TokenStream, f: F) where F: FnOnce(&mut TokenStream),635 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
636 where
637 F: FnOnce(&mut TokenStream),
638 {
639 let mut inner = TokenStream::new();
640 f(&mut inner);
641 printing::delim(Delimiter::None, self.span, tokens, inner);
642 }
643 }
644
645 #[cfg(feature = "parsing")]
646 impl private::Sealed for Group {}
647
648 #[cfg(feature = "parsing")]
649 impl Token for Paren {
peek(cursor: Cursor) -> bool650 fn peek(cursor: Cursor) -> bool {
651 cursor.group(Delimiter::Parenthesis).is_some()
652 }
653
display() -> &'static str654 fn display() -> &'static str {
655 "parentheses"
656 }
657 }
658
659 #[cfg(feature = "parsing")]
660 impl Token for Brace {
peek(cursor: Cursor) -> bool661 fn peek(cursor: Cursor) -> bool {
662 cursor.group(Delimiter::Brace).is_some()
663 }
664
display() -> &'static str665 fn display() -> &'static str {
666 "curly braces"
667 }
668 }
669
670 #[cfg(feature = "parsing")]
671 impl Token for Bracket {
peek(cursor: Cursor) -> bool672 fn peek(cursor: Cursor) -> bool {
673 cursor.group(Delimiter::Bracket).is_some()
674 }
675
display() -> &'static str676 fn display() -> &'static str {
677 "square brackets"
678 }
679 }
680
681 #[cfg(feature = "parsing")]
682 impl Token for Group {
peek(cursor: Cursor) -> bool683 fn peek(cursor: Cursor) -> bool {
684 cursor.group(Delimiter::None).is_some()
685 }
686
display() -> &'static str687 fn display() -> &'static str {
688 "invisible group"
689 }
690 }
691
692 define_keywords! {
693 "abstract" pub struct Abstract
694 "as" pub struct As
695 "async" pub struct Async
696 "auto" pub struct Auto
697 "await" pub struct Await
698 "become" pub struct Become
699 "box" pub struct Box
700 "break" pub struct Break
701 "const" pub struct Const
702 "continue" pub struct Continue
703 "crate" pub struct Crate
704 "default" pub struct Default
705 "do" pub struct Do
706 "dyn" pub struct Dyn
707 "else" pub struct Else
708 "enum" pub struct Enum
709 "extern" pub struct Extern
710 "final" pub struct Final
711 "fn" pub struct Fn
712 "for" pub struct For
713 "if" pub struct If
714 "impl" pub struct Impl
715 "in" pub struct In
716 "let" pub struct Let
717 "loop" pub struct Loop
718 "macro" pub struct Macro
719 "match" pub struct Match
720 "mod" pub struct Mod
721 "move" pub struct Move
722 "mut" pub struct Mut
723 "override" pub struct Override
724 "priv" pub struct Priv
725 "pub" pub struct Pub
726 "raw" pub struct Raw
727 "ref" pub struct Ref
728 "return" pub struct Return
729 "Self" pub struct SelfType
730 "self" pub struct SelfValue
731 "static" pub struct Static
732 "struct" pub struct Struct
733 "super" pub struct Super
734 "trait" pub struct Trait
735 "try" pub struct Try
736 "type" pub struct Type
737 "typeof" pub struct Typeof
738 "union" pub struct Union
739 "unsafe" pub struct Unsafe
740 "unsized" pub struct Unsized
741 "use" pub struct Use
742 "virtual" pub struct Virtual
743 "where" pub struct Where
744 "while" pub struct While
745 "yield" pub struct Yield
746 }
747
748 define_punctuation! {
749 "&" pub struct And/1 /// bitwise and logical AND, borrow, references, reference patterns
750 "&&" pub struct AndAnd/2 /// lazy AND, borrow, references, reference patterns
751 "&=" pub struct AndEq/2 /// bitwise AND assignment
752 "@" pub struct At/1 /// subpattern binding
753 "^" pub struct Caret/1 /// bitwise and logical XOR
754 "^=" pub struct CaretEq/2 /// bitwise XOR assignment
755 ":" pub struct Colon/1 /// various separators
756 "," pub struct Comma/1 /// various separators
757 "$" pub struct Dollar/1 /// macros
758 "." pub struct Dot/1 /// field access, tuple index
759 ".." pub struct DotDot/2 /// range, struct expressions, patterns, range patterns
760 "..." pub struct DotDotDot/3 /// variadic functions, range patterns
761 "..=" pub struct DotDotEq/3 /// inclusive range, range patterns
762 "=" pub struct Eq/1 /// assignment, attributes, various type definitions
763 "==" pub struct EqEq/2 /// equal
764 "=>" pub struct FatArrow/2 /// match arms, macros
765 ">=" pub struct Ge/2 /// greater than or equal to, generics
766 ">" pub struct Gt/1 /// greater than, generics, paths
767 "<-" pub struct LArrow/2 /// unused
768 "<=" pub struct Le/2 /// less than or equal to
769 "<" pub struct Lt/1 /// less than, generics, paths
770 "-" pub struct Minus/1 /// subtraction, negation
771 "-=" pub struct MinusEq/2 /// subtraction assignment
772 "!=" pub struct Ne/2 /// not equal
773 "!" pub struct Not/1 /// bitwise and logical NOT, macro calls, inner attributes, never type, negative impls
774 "|" pub struct Or/1 /// bitwise and logical OR, closures, patterns in match, if let, and while let
775 "|=" pub struct OrEq/2 /// bitwise OR assignment
776 "||" pub struct OrOr/2 /// lazy OR, closures
777 "::" pub struct PathSep/2 /// path separator
778 "%" pub struct Percent/1 /// remainder
779 "%=" pub struct PercentEq/2 /// remainder assignment
780 "+" pub struct Plus/1 /// addition, trait bounds, macro Kleene matcher
781 "+=" pub struct PlusEq/2 /// addition assignment
782 "#" pub struct Pound/1 /// attributes
783 "?" pub struct Question/1 /// question mark operator, questionably sized, macro Kleene matcher
784 "->" pub struct RArrow/2 /// function return type, closure return type, function pointer type
785 ";" pub struct Semi/1 /// terminator for various items and statements, array types
786 "<<" pub struct Shl/2 /// shift left, nested generics
787 "<<=" pub struct ShlEq/3 /// shift left assignment
788 ">>" pub struct Shr/2 /// shift right, nested generics
789 ">>=" pub struct ShrEq/3 /// shift right assignment, nested generics
790 "/" pub struct Slash/1 /// division
791 "/=" pub struct SlashEq/2 /// division assignment
792 "*" pub struct Star/1 /// multiplication, dereference, raw pointers, macro Kleene matcher, use wildcards
793 "*=" pub struct StarEq/2 /// multiplication assignment
794 "~" pub struct Tilde/1 /// unused since before Rust 1.0
795 }
796
797 define_delimiters! {
798 Brace pub struct Brace /// `{`…`}`
799 Bracket pub struct Bracket /// `[`…`]`
800 Parenthesis pub struct Paren /// `(`…`)`
801 }
802
803 /// A type-macro that expands to the name of the Rust type representation of a
804 /// given token.
805 ///
806 /// As a type, `Token!` is commonly used in the type of struct fields, the type
807 /// of a `let` statement, or in turbofish for a `parse` function.
808 ///
809 /// ```
810 /// use syn::{Ident, Token};
811 /// use syn::parse::{Parse, ParseStream, Result};
812 ///
813 /// // `struct Foo;`
814 /// pub struct UnitStruct {
815 /// struct_token: Token![struct],
816 /// ident: Ident,
817 /// semi_token: Token![;],
818 /// }
819 ///
820 /// impl Parse for UnitStruct {
821 /// fn parse(input: ParseStream) -> Result<Self> {
822 /// let struct_token: Token![struct] = input.parse()?;
823 /// let ident: Ident = input.parse()?;
824 /// let semi_token = input.parse::<Token![;]>()?;
825 /// Ok(UnitStruct { struct_token, ident, semi_token })
826 /// }
827 /// }
828 /// ```
829 ///
830 /// As an expression, `Token!` is used for peeking tokens or instantiating
831 /// tokens from a span.
832 ///
833 /// ```
834 /// # use syn::{Ident, Token};
835 /// # use syn::parse::{Parse, ParseStream, Result};
836 /// #
837 /// # struct UnitStruct {
838 /// # struct_token: Token![struct],
839 /// # ident: Ident,
840 /// # semi_token: Token![;],
841 /// # }
842 /// #
843 /// # impl Parse for UnitStruct {
844 /// # fn parse(input: ParseStream) -> Result<Self> {
845 /// # unimplemented!()
846 /// # }
847 /// # }
848 /// #
849 /// fn make_unit_struct(name: Ident) -> UnitStruct {
850 /// let span = name.span();
851 /// UnitStruct {
852 /// struct_token: Token,
853 /// ident: name,
854 /// semi_token: Token,
855 /// }
856 /// }
857 ///
858 /// # fn parse(input: ParseStream) -> Result<()> {
859 /// if input.peek(Token![struct]) {
860 /// let unit_struct: UnitStruct = input.parse()?;
861 /// /* ... */
862 /// }
863 /// # Ok(())
864 /// # }
865 /// ```
866 ///
867 /// See the [token module] documentation for details and examples.
868 ///
869 /// [token module]: crate::token
870 #[macro_export]
871 macro_rules! Token {
872 [abstract] => { $crate::token::Abstract };
873 [as] => { $crate::token::As };
874 [async] => { $crate::token::Async };
875 [auto] => { $crate::token::Auto };
876 [await] => { $crate::token::Await };
877 [become] => { $crate::token::Become };
878 [box] => { $crate::token::Box };
879 [break] => { $crate::token::Break };
880 [const] => { $crate::token::Const };
881 [continue] => { $crate::token::Continue };
882 [crate] => { $crate::token::Crate };
883 [default] => { $crate::token::Default };
884 [do] => { $crate::token::Do };
885 [dyn] => { $crate::token::Dyn };
886 [else] => { $crate::token::Else };
887 [enum] => { $crate::token::Enum };
888 [extern] => { $crate::token::Extern };
889 [final] => { $crate::token::Final };
890 [fn] => { $crate::token::Fn };
891 [for] => { $crate::token::For };
892 [if] => { $crate::token::If };
893 [impl] => { $crate::token::Impl };
894 [in] => { $crate::token::In };
895 [let] => { $crate::token::Let };
896 [loop] => { $crate::token::Loop };
897 [macro] => { $crate::token::Macro };
898 [match] => { $crate::token::Match };
899 [mod] => { $crate::token::Mod };
900 [move] => { $crate::token::Move };
901 [mut] => { $crate::token::Mut };
902 [override] => { $crate::token::Override };
903 [priv] => { $crate::token::Priv };
904 [pub] => { $crate::token::Pub };
905 [raw] => { $crate::token::Raw };
906 [ref] => { $crate::token::Ref };
907 [return] => { $crate::token::Return };
908 [Self] => { $crate::token::SelfType };
909 [self] => { $crate::token::SelfValue };
910 [static] => { $crate::token::Static };
911 [struct] => { $crate::token::Struct };
912 [super] => { $crate::token::Super };
913 [trait] => { $crate::token::Trait };
914 [try] => { $crate::token::Try };
915 [type] => { $crate::token::Type };
916 [typeof] => { $crate::token::Typeof };
917 [union] => { $crate::token::Union };
918 [unsafe] => { $crate::token::Unsafe };
919 [unsized] => { $crate::token::Unsized };
920 [use] => { $crate::token::Use };
921 [virtual] => { $crate::token::Virtual };
922 [where] => { $crate::token::Where };
923 [while] => { $crate::token::While };
924 [yield] => { $crate::token::Yield };
925 [&] => { $crate::token::And };
926 [&&] => { $crate::token::AndAnd };
927 [&=] => { $crate::token::AndEq };
928 [@] => { $crate::token::At };
929 [^] => { $crate::token::Caret };
930 [^=] => { $crate::token::CaretEq };
931 [:] => { $crate::token::Colon };
932 [,] => { $crate::token::Comma };
933 [$] => { $crate::token::Dollar };
934 [.] => { $crate::token::Dot };
935 [..] => { $crate::token::DotDot };
936 [...] => { $crate::token::DotDotDot };
937 [..=] => { $crate::token::DotDotEq };
938 [=] => { $crate::token::Eq };
939 [==] => { $crate::token::EqEq };
940 [=>] => { $crate::token::FatArrow };
941 [>=] => { $crate::token::Ge };
942 [>] => { $crate::token::Gt };
943 [<-] => { $crate::token::LArrow };
944 [<=] => { $crate::token::Le };
945 [<] => { $crate::token::Lt };
946 [-] => { $crate::token::Minus };
947 [-=] => { $crate::token::MinusEq };
948 [!=] => { $crate::token::Ne };
949 [!] => { $crate::token::Not };
950 [|] => { $crate::token::Or };
951 [|=] => { $crate::token::OrEq };
952 [||] => { $crate::token::OrOr };
953 [::] => { $crate::token::PathSep };
954 [%] => { $crate::token::Percent };
955 [%=] => { $crate::token::PercentEq };
956 [+] => { $crate::token::Plus };
957 [+=] => { $crate::token::PlusEq };
958 [#] => { $crate::token::Pound };
959 [?] => { $crate::token::Question };
960 [->] => { $crate::token::RArrow };
961 [;] => { $crate::token::Semi };
962 [<<] => { $crate::token::Shl };
963 [<<=] => { $crate::token::ShlEq };
964 [>>] => { $crate::token::Shr };
965 [>>=] => { $crate::token::ShrEq };
966 [/] => { $crate::token::Slash };
967 [/=] => { $crate::token::SlashEq };
968 [*] => { $crate::token::Star };
969 [*=] => { $crate::token::StarEq };
970 [~] => { $crate::token::Tilde };
971 [_] => { $crate::token::Underscore };
972 }
973
974 // Not public API.
975 #[doc(hidden)]
976 #[cfg(feature = "parsing")]
977 pub(crate) mod parsing {
978 use crate::buffer::Cursor;
979 use crate::error::{Error, Result};
980 use crate::parse::ParseStream;
981 use proc_macro2::{Spacing, Span};
982
keyword(input: ParseStream, token: &str) -> Result<Span>983 pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> {
984 input.step(|cursor| {
985 if let Some((ident, rest)) = cursor.ident() {
986 if ident == token {
987 return Ok((ident.span(), rest));
988 }
989 }
990 Err(cursor.error(format!("expected `{}`", token)))
991 })
992 }
993
peek_keyword(cursor: Cursor, token: &str) -> bool994 pub(crate) fn peek_keyword(cursor: Cursor, token: &str) -> bool {
995 if let Some((ident, _rest)) = cursor.ident() {
996 ident == token
997 } else {
998 false
999 }
1000 }
1001
1002 #[doc(hidden)]
punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]>1003 pub fn punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]> {
1004 let mut spans = [input.span(); N];
1005 punct_helper(input, token, &mut spans)?;
1006 Ok(spans)
1007 }
1008
punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()>1009 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()> {
1010 input.step(|cursor| {
1011 let mut cursor = *cursor;
1012 assert_eq!(token.len(), spans.len());
1013
1014 for (i, ch) in token.chars().enumerate() {
1015 match cursor.punct() {
1016 Some((punct, rest)) => {
1017 spans[i] = punct.span();
1018 if punct.as_char() != ch {
1019 break;
1020 } else if i == token.len() - 1 {
1021 return Ok(((), rest));
1022 } else if punct.spacing() != Spacing::Joint {
1023 break;
1024 }
1025 cursor = rest;
1026 }
1027 None => break,
1028 }
1029 }
1030
1031 Err(Error::new(spans[0], format!("expected `{}`", token)))
1032 })
1033 }
1034
1035 #[doc(hidden)]
peek_punct(mut cursor: Cursor, token: &str) -> bool1036 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
1037 for (i, ch) in token.chars().enumerate() {
1038 match cursor.punct() {
1039 Some((punct, rest)) => {
1040 if punct.as_char() != ch {
1041 break;
1042 } else if i == token.len() - 1 {
1043 return true;
1044 } else if punct.spacing() != Spacing::Joint {
1045 break;
1046 }
1047 cursor = rest;
1048 }
1049 None => break,
1050 }
1051 }
1052 false
1053 }
1054 }
1055
1056 // Not public API.
1057 #[doc(hidden)]
1058 #[cfg(feature = "printing")]
1059 pub(crate) mod printing {
1060 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
1061 use quote::TokenStreamExt;
1062
1063 #[doc(hidden)]
punct(s: &str, spans: &[Span], tokens: &mut TokenStream)1064 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
1065 assert_eq!(s.len(), spans.len());
1066
1067 let mut chars = s.chars();
1068 let mut spans = spans.iter();
1069 let ch = chars.next_back().unwrap();
1070 let span = spans.next_back().unwrap();
1071 for (ch, span) in chars.zip(spans) {
1072 let mut op = Punct::new(ch, Spacing::Joint);
1073 op.set_span(*span);
1074 tokens.append(op);
1075 }
1076
1077 let mut op = Punct::new(ch, Spacing::Alone);
1078 op.set_span(*span);
1079 tokens.append(op);
1080 }
1081
keyword(s: &str, span: Span, tokens: &mut TokenStream)1082 pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
1083 tokens.append(Ident::new(s, span));
1084 }
1085
delim( delim: Delimiter, span: Span, tokens: &mut TokenStream, inner: TokenStream, )1086 pub(crate) fn delim(
1087 delim: Delimiter,
1088 span: Span,
1089 tokens: &mut TokenStream,
1090 inner: TokenStream,
1091 ) {
1092 let mut g = Group::new(delim, inner);
1093 g.set_span(span);
1094 tokens.append(g);
1095 }
1096 }
1097