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)] 130 fn peek(cursor: Cursor) -> bool; 131 132 // Not public API. 133 #[doc(hidden)] 134 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 { 157 fn peek(cursor: Cursor) -> bool; 158 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 { 194 fn peek(cursor: Cursor) -> bool { 195 <Self as CustomToken>::peek(cursor) 196 } 197 198 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 { 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 { 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 { 557 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 567 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)] 582 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 { 589 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 { 603 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 { 611 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 { 623 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 { 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")))] 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 { 652 fn peek(cursor: Cursor) -> bool { 653 cursor.group(Delimiter::Parenthesis).is_some() 654 } 655 656 fn display() -> &'static str { 657 "parentheses" 658 } 659 } 660 661 #[cfg(feature = "parsing")] 662 impl Token for Brace { 663 fn peek(cursor: Cursor) -> bool { 664 cursor.group(Delimiter::Brace).is_some() 665 } 666 667 fn display() -> &'static str { 668 "curly braces" 669 } 670 } 671 672 #[cfg(feature = "parsing")] 673 impl Token for Bracket { 674 fn peek(cursor: Cursor) -> bool { 675 cursor.group(Delimiter::Bracket).is_some() 676 } 677 678 fn display() -> &'static str { 679 "square brackets" 680 } 681 } 682 683 #[cfg(feature = "parsing")] 684 impl Token for Group { 685 fn peek(cursor: Cursor) -> bool { 686 cursor.group(Delimiter::None).is_some() 687 } 688 689 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 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 996 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)] 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 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)] 1038 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)] 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 1084 pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) { 1085 tokens.append(Ident::new(s, span)); 1086 } 1087 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