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