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