1#[cfg(feature = "parsing")]
92pub(crate) use self::private::CustomToken;
93use self::private::WithSpan;
94#[cfg(feature = "parsing")]
95use crate::buffer::Cursor;
96#[cfg(feature = "parsing")]
97use crate::error::Result;
98#[cfg(feature = "parsing")]
99use crate::lifetime::Lifetime;
100#[cfg(feature = "parsing")]
101use crate::parse::{Parse, ParseStream};
102use crate::span::IntoSpans;
103use proc_macro2::extra::DelimSpan;
104use proc_macro2::Span;
105#[cfg(feature = "printing")]
106use proc_macro2::TokenStream;
107#[cfg(any(feature = "parsing", feature = "printing"))]
108use proc_macro2::{Delimiter, Ident};
109#[cfg(feature = "parsing")]
110use proc_macro2::{Literal, Punct, TokenTree};
111#[cfg(feature = "printing")]
112use quote::{ToTokens, TokenStreamExt};
113#[cfg(feature = "extra-traits")]
114use std::cmp;
115#[cfg(feature = "extra-traits")]
116use std::fmt::{self, Debug};
117#[cfg(feature = "extra-traits")]
118use std::hash::{Hash, Hasher};
119use std::ops::{Deref, DerefMut};
120
121#[cfg(feature = "parsing")]
125pub trait Token: private::Sealed {
126 #[doc(hidden)]
128 fn peek(cursor: Cursor) -> bool;
129
130 #[doc(hidden)]
132 fn display() -> &'static str;
133}
134
135pub(crate) mod private {
136 #[cfg(feature = "parsing")]
137 use crate::buffer::Cursor;
138 use proc_macro2::Span;
139
140 #[cfg(feature = "parsing")]
141 pub trait Sealed {}
142
143 #[repr(transparent)]
146 #[allow(unknown_lints, repr_transparent_external_private_fields)] pub struct WithSpan {
148 pub span: Span,
149 }
150
151 #[doc(hidden)]
153 #[cfg(feature = "parsing")]
154 pub trait CustomToken {
155 fn peek(cursor: Cursor) -> bool;
156 fn display() -> &'static str;
157 }
158}
159
160#[cfg(feature = "parsing")]
161impl private::Sealed for Ident {}
162
163macro_rules! impl_low_level_token {
164 ($display:literal $($path:ident)::+ $get:ident) => {
165 #[cfg(feature = "parsing")]
166 impl Token for $($path)::+ {
167 fn peek(cursor: Cursor) -> bool {
168 cursor.$get().is_some()
169 }
170
171 fn display() -> &'static str {
172 $display
173 }
174 }
175
176 #[cfg(feature = "parsing")]
177 impl private::Sealed for $($path)::+ {}
178 };
179}
180
181impl_low_level_token!("punctuation token" Punct punct);
182impl_low_level_token!("literal" Literal literal);
183impl_low_level_token!("token" TokenTree token_tree);
184impl_low_level_token!("group token" proc_macro2::Group any_group);
185impl_low_level_token!("lifetime" Lifetime lifetime);
186
187#[cfg(feature = "parsing")]
188impl<T: CustomToken> private::Sealed for T {}
189
190#[cfg(feature = "parsing")]
191impl<T: CustomToken> Token for T {
192 fn peek(cursor: Cursor) -> bool {
193 <Self as CustomToken>::peek(cursor)
194 }
195
196 fn display() -> &'static str {
197 <Self as CustomToken>::display()
198 }
199}
200
201macro_rules! define_keywords {
202 ($($token:literal pub struct $name:ident)*) => {
203 $(
204 #[doc = concat!('`', $token, '`')]
205 pub struct $name {
211 pub span: Span,
212 }
213
214 #[doc(hidden)]
215 #[allow(non_snake_case)]
216 pub fn $name<S: IntoSpans<Span>>(span: S) -> $name {
217 $name {
218 span: span.into_spans(),
219 }
220 }
221
222 impl std::default::Default for $name {
223 fn default() -> Self {
224 $name {
225 span: Span::call_site(),
226 }
227 }
228 }
229
230 #[cfg(feature = "clone-impls")]
231 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
232 impl Copy for $name {}
233
234 #[cfg(feature = "clone-impls")]
235 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
236 impl Clone for $name {
237 fn clone(&self) -> Self {
238 *self
239 }
240 }
241
242 #[cfg(feature = "extra-traits")]
243 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
244 impl Debug for $name {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 f.write_str(stringify!($name))
247 }
248 }
249
250 #[cfg(feature = "extra-traits")]
251 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
252 impl cmp::Eq for $name {}
253
254 #[cfg(feature = "extra-traits")]
255 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
256 impl PartialEq for $name {
257 fn eq(&self, _other: &$name) -> bool {
258 true
259 }
260 }
261
262 #[cfg(feature = "extra-traits")]
263 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
264 impl Hash for $name {
265 fn hash<H: Hasher>(&self, _state: &mut H) {}
266 }
267
268 #[cfg(feature = "printing")]
269 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
270 impl ToTokens for $name {
271 fn to_tokens(&self, tokens: &mut TokenStream) {
272 printing::keyword($token, self.span, tokens);
273 }
274 }
275
276 #[cfg(feature = "parsing")]
277 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
278 impl Parse for $name {
279 fn parse(input: ParseStream) -> Result<Self> {
280 Ok($name {
281 span: parsing::keyword(input, $token)?,
282 })
283 }
284 }
285
286 #[cfg(feature = "parsing")]
287 impl Token for $name {
288 fn peek(cursor: Cursor) -> bool {
289 parsing::peek_keyword(cursor, $token)
290 }
291
292 fn display() -> &'static str {
293 concat!("`", $token, "`")
294 }
295 }
296
297 #[cfg(feature = "parsing")]
298 impl private::Sealed for $name {}
299 )*
300 };
301}
302
303macro_rules! impl_deref_if_len_is_1 {
304 ($name:ident/1) => {
305 impl Deref for $name {
306 type Target = WithSpan;
307
308 fn deref(&self) -> &Self::Target {
309 unsafe { &*(self as *const Self).cast::<WithSpan>() }
310 }
311 }
312
313 impl DerefMut for $name {
314 fn deref_mut(&mut self) -> &mut Self::Target {
315 unsafe { &mut *(self as *mut Self).cast::<WithSpan>() }
316 }
317 }
318 };
319
320 ($name:ident/$len:literal) => {};
321}
322
323macro_rules! define_punctuation_structs {
324 ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
325 $(
326 #[cfg_attr(not(doc), repr(transparent))]
327 #[allow(unknown_lints, repr_transparent_external_private_fields)] #[doc = concat!('`', $token, '`')]
329 #[doc = concat!($usage, '.')]
332 pub struct $name {
338 pub spans: [Span; $len],
339 }
340
341 #[doc(hidden)]
342 #[allow(non_snake_case)]
343 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
344 $name {
345 spans: spans.into_spans(),
346 }
347 }
348
349 impl std::default::Default for $name {
350 fn default() -> Self {
351 $name {
352 spans: [Span::call_site(); $len],
353 }
354 }
355 }
356
357 #[cfg(feature = "clone-impls")]
358 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
359 impl Copy for $name {}
360
361 #[cfg(feature = "clone-impls")]
362 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
363 impl Clone for $name {
364 fn clone(&self) -> Self {
365 *self
366 }
367 }
368
369 #[cfg(feature = "extra-traits")]
370 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
371 impl Debug for $name {
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 f.write_str(stringify!($name))
374 }
375 }
376
377 #[cfg(feature = "extra-traits")]
378 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
379 impl cmp::Eq for $name {}
380
381 #[cfg(feature = "extra-traits")]
382 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
383 impl PartialEq for $name {
384 fn eq(&self, _other: &$name) -> bool {
385 true
386 }
387 }
388
389 #[cfg(feature = "extra-traits")]
390 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
391 impl Hash for $name {
392 fn hash<H: Hasher>(&self, _state: &mut H) {}
393 }
394
395 impl_deref_if_len_is_1!($name/$len);
396 )*
397 };
398}
399
400macro_rules! define_punctuation {
401 ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
402 $(
403 define_punctuation_structs! {
404 $token pub struct $name/$len #[doc = $usage]
405 }
406
407 #[cfg(feature = "printing")]
408 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
409 impl ToTokens for $name {
410 fn to_tokens(&self, tokens: &mut TokenStream) {
411 printing::punct($token, &self.spans, tokens);
412 }
413 }
414
415 #[cfg(feature = "parsing")]
416 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
417 impl Parse for $name {
418 fn parse(input: ParseStream) -> Result<Self> {
419 Ok($name {
420 spans: parsing::punct(input, $token)?,
421 })
422 }
423 }
424
425 #[cfg(feature = "parsing")]
426 impl Token for $name {
427 fn peek(cursor: Cursor) -> bool {
428 parsing::peek_punct(cursor, $token)
429 }
430
431 fn display() -> &'static str {
432 concat!("`", $token, "`")
433 }
434 }
435
436 #[cfg(feature = "parsing")]
437 impl private::Sealed for $name {}
438 )*
439 };
440}
441
442macro_rules! define_delimiters {
443 ($($delim:ident pub struct $name:ident #[$doc:meta])*) => {
444 $(
445 #[$doc]
446 pub struct $name {
447 pub span: DelimSpan,
448 }
449
450 #[doc(hidden)]
451 #[allow(non_snake_case)]
452 pub fn $name<S: IntoSpans<DelimSpan>>(span: S) -> $name {
453 $name {
454 span: span.into_spans(),
455 }
456 }
457
458 impl std::default::Default for $name {
459 fn default() -> Self {
460 $name(Span::call_site())
461 }
462 }
463
464 #[cfg(feature = "clone-impls")]
465 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
466 impl Copy for $name {}
467
468 #[cfg(feature = "clone-impls")]
469 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
470 impl Clone for $name {
471 fn clone(&self) -> Self {
472 *self
473 }
474 }
475
476 #[cfg(feature = "extra-traits")]
477 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
478 impl Debug for $name {
479 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
480 f.write_str(stringify!($name))
481 }
482 }
483
484 #[cfg(feature = "extra-traits")]
485 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
486 impl cmp::Eq for $name {}
487
488 #[cfg(feature = "extra-traits")]
489 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
490 impl PartialEq for $name {
491 fn eq(&self, _other: &$name) -> bool {
492 true
493 }
494 }
495
496 #[cfg(feature = "extra-traits")]
497 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
498 impl Hash for $name {
499 fn hash<H: Hasher>(&self, _state: &mut H) {}
500 }
501
502 impl $name {
503 #[cfg(feature = "printing")]
504 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
505 where
506 F: FnOnce(&mut TokenStream),
507 {
508 let mut inner = TokenStream::new();
509 f(&mut inner);
510 printing::delim(Delimiter::$delim, self.span.join(), tokens, inner);
511 }
512 }
513
514 #[cfg(feature = "parsing")]
515 impl private::Sealed for $name {}
516 )*
517 };
518}
519
520define_punctuation_structs! {
521 "_" pub struct Underscore/1 }
523
524#[cfg(feature = "printing")]
525#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
526impl ToTokens for Underscore {
527 fn to_tokens(&self, tokens: &mut TokenStream) {
528 tokens.append(Ident::new("_", self.span));
529 }
530}
531
532#[cfg(feature = "parsing")]
533#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
534impl Parse for Underscore {
535 fn parse(input: ParseStream) -> Result<Self> {
536 input.step(|cursor| {
537 if let Some((ident, rest)) = cursor.ident() {
538 if ident == "_" {
539 return Ok((Underscore(ident.span()), rest));
540 }
541 }
542 if let Some((punct, rest)) = cursor.punct() {
543 if punct.as_char() == '_' {
544 return Ok((Underscore(punct.span()), rest));
545 }
546 }
547 Err(cursor.error("expected `_`"))
548 })
549 }
550}
551
552#[cfg(feature = "parsing")]
553impl Token for Underscore {
554 fn peek(cursor: Cursor) -> bool {
555 if let Some((ident, _rest)) = cursor.ident() {
556 return ident == "_";
557 }
558 if let Some((punct, _rest)) = cursor.punct() {
559 return punct.as_char() == '_';
560 }
561 false
562 }
563
564 fn display() -> &'static str {
565 "`_`"
566 }
567}
568
569#[cfg(feature = "parsing")]
570impl private::Sealed for Underscore {}
571
572pub struct Group {
574 pub span: Span,
575}
576
577#[doc(hidden)]
578#[allow(non_snake_case)]
579pub fn Group<S: IntoSpans<Span>>(span: S) -> Group {
580 Group {
581 span: span.into_spans(),
582 }
583}
584
585impl std::default::Default for Group {
586 fn default() -> Self {
587 Group {
588 span: Span::call_site(),
589 }
590 }
591}
592
593#[cfg(feature = "clone-impls")]
594#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
595impl Copy for Group {}
596
597#[cfg(feature = "clone-impls")]
598#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
599impl Clone for Group {
600 fn clone(&self) -> Self {
601 *self
602 }
603}
604
605#[cfg(feature = "extra-traits")]
606#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
607impl Debug for Group {
608 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
609 f.write_str("Group")
610 }
611}
612
613#[cfg(feature = "extra-traits")]
614#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
615impl cmp::Eq for Group {}
616
617#[cfg(feature = "extra-traits")]
618#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
619impl PartialEq for Group {
620 fn eq(&self, _other: &Group) -> bool {
621 true
622 }
623}
624
625#[cfg(feature = "extra-traits")]
626#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
627impl Hash for Group {
628 fn hash<H: Hasher>(&self, _state: &mut H) {}
629}
630
631impl Group {
632 #[cfg(feature = "printing")]
633 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
634 where
635 F: FnOnce(&mut TokenStream),
636 {
637 let mut inner = TokenStream::new();
638 f(&mut inner);
639 printing::delim(Delimiter::None, self.span, tokens, inner);
640 }
641}
642
643#[cfg(feature = "parsing")]
644impl private::Sealed for Group {}
645
646#[cfg(feature = "parsing")]
647impl Token for Paren {
648 fn peek(cursor: Cursor) -> bool {
649 cursor.group(Delimiter::Parenthesis).is_some()
650 }
651
652 fn display() -> &'static str {
653 "parentheses"
654 }
655}
656
657#[cfg(feature = "parsing")]
658impl Token for Brace {
659 fn peek(cursor: Cursor) -> bool {
660 cursor.group(Delimiter::Brace).is_some()
661 }
662
663 fn display() -> &'static str {
664 "curly braces"
665 }
666}
667
668#[cfg(feature = "parsing")]
669impl Token for Bracket {
670 fn peek(cursor: Cursor) -> bool {
671 cursor.group(Delimiter::Bracket).is_some()
672 }
673
674 fn display() -> &'static str {
675 "square brackets"
676 }
677}
678
679#[cfg(feature = "parsing")]
680impl Token for Group {
681 fn peek(cursor: Cursor) -> bool {
682 cursor.group(Delimiter::None).is_some()
683 }
684
685 fn display() -> &'static str {
686 "invisible group"
687 }
688}
689
690define_keywords! {
691 "abstract" pub struct Abstract
692 "as" pub struct As
693 "async" pub struct Async
694 "auto" pub struct Auto
695 "await" pub struct Await
696 "become" pub struct Become
697 "box" pub struct Box
698 "break" pub struct Break
699 "const" pub struct Const
700 "continue" pub struct Continue
701 "crate" pub struct Crate
702 "default" pub struct Default
703 "do" pub struct Do
704 "dyn" pub struct Dyn
705 "else" pub struct Else
706 "enum" pub struct Enum
707 "extern" pub struct Extern
708 "final" pub struct Final
709 "fn" pub struct Fn
710 "for" pub struct For
711 "if" pub struct If
712 "impl" pub struct Impl
713 "in" pub struct In
714 "let" pub struct Let
715 "loop" pub struct Loop
716 "macro" pub struct Macro
717 "match" pub struct Match
718 "mod" pub struct Mod
719 "move" pub struct Move
720 "mut" pub struct Mut
721 "override" pub struct Override
722 "priv" pub struct Priv
723 "pub" pub struct Pub
724 "raw" pub struct Raw
725 "ref" pub struct Ref
726 "return" pub struct Return
727 "Self" pub struct SelfType
728 "self" pub struct SelfValue
729 "static" pub struct Static
730 "struct" pub struct Struct
731 "super" pub struct Super
732 "trait" pub struct Trait
733 "try" pub struct Try
734 "type" pub struct Type
735 "typeof" pub struct Typeof
736 "union" pub struct Union
737 "unsafe" pub struct Unsafe
738 "unsized" pub struct Unsized
739 "use" pub struct Use
740 "virtual" pub struct Virtual
741 "where" pub struct Where
742 "while" pub struct While
743 "yield" pub struct Yield
744}
745
746define_punctuation! {
747 "&" pub struct And/1 "&&" pub struct AndAnd/2 "&=" pub struct AndEq/2 "@" pub struct At/1 "^" pub struct Caret/1 "^=" pub struct CaretEq/2 ":" pub struct Colon/1 "," pub struct Comma/1 "$" pub struct Dollar/1 "." pub struct Dot/1 ".." pub struct DotDot/2 "..." pub struct DotDotDot/3 "..=" pub struct DotDotEq/3 "=" pub struct Eq/1 "==" pub struct EqEq/2 "=>" pub struct FatArrow/2 ">=" pub struct Ge/2 ">" pub struct Gt/1 "<-" pub struct LArrow/2 "<=" pub struct Le/2 "<" pub struct Lt/1 "-" pub struct Minus/1 "-=" pub struct MinusEq/2 "!=" pub struct Ne/2 "!" pub struct Not/1 "|" pub struct Or/1 "|=" pub struct OrEq/2 "||" pub struct OrOr/2 "::" pub struct PathSep/2 "%" pub struct Percent/1 "%=" pub struct PercentEq/2 "+" pub struct Plus/1 "+=" pub struct PlusEq/2 "#" pub struct Pound/1 "?" pub struct Question/1 "->" pub struct RArrow/2 ";" pub struct Semi/1 "<<" pub struct Shl/2 "<<=" pub struct ShlEq/3 ">>" pub struct Shr/2 ">>=" pub struct ShrEq/3 "/" pub struct Slash/1 "/=" pub struct SlashEq/2 "*" pub struct Star/1 "*=" pub struct StarEq/2 "~" pub struct Tilde/1 }
794
795define_delimiters! {
796 Brace pub struct Brace Bracket pub struct Bracket Parenthesis pub struct Paren }
800
801#[macro_export]
869macro_rules! Token {
870 [abstract] => { $crate::token::Abstract };
871 [as] => { $crate::token::As };
872 [async] => { $crate::token::Async };
873 [auto] => { $crate::token::Auto };
874 [await] => { $crate::token::Await };
875 [become] => { $crate::token::Become };
876 [box] => { $crate::token::Box };
877 [break] => { $crate::token::Break };
878 [const] => { $crate::token::Const };
879 [continue] => { $crate::token::Continue };
880 [crate] => { $crate::token::Crate };
881 [default] => { $crate::token::Default };
882 [do] => { $crate::token::Do };
883 [dyn] => { $crate::token::Dyn };
884 [else] => { $crate::token::Else };
885 [enum] => { $crate::token::Enum };
886 [extern] => { $crate::token::Extern };
887 [final] => { $crate::token::Final };
888 [fn] => { $crate::token::Fn };
889 [for] => { $crate::token::For };
890 [if] => { $crate::token::If };
891 [impl] => { $crate::token::Impl };
892 [in] => { $crate::token::In };
893 [let] => { $crate::token::Let };
894 [loop] => { $crate::token::Loop };
895 [macro] => { $crate::token::Macro };
896 [match] => { $crate::token::Match };
897 [mod] => { $crate::token::Mod };
898 [move] => { $crate::token::Move };
899 [mut] => { $crate::token::Mut };
900 [override] => { $crate::token::Override };
901 [priv] => { $crate::token::Priv };
902 [pub] => { $crate::token::Pub };
903 [raw] => { $crate::token::Raw };
904 [ref] => { $crate::token::Ref };
905 [return] => { $crate::token::Return };
906 [Self] => { $crate::token::SelfType };
907 [self] => { $crate::token::SelfValue };
908 [static] => { $crate::token::Static };
909 [struct] => { $crate::token::Struct };
910 [super] => { $crate::token::Super };
911 [trait] => { $crate::token::Trait };
912 [try] => { $crate::token::Try };
913 [type] => { $crate::token::Type };
914 [typeof] => { $crate::token::Typeof };
915 [union] => { $crate::token::Union };
916 [unsafe] => { $crate::token::Unsafe };
917 [unsized] => { $crate::token::Unsized };
918 [use] => { $crate::token::Use };
919 [virtual] => { $crate::token::Virtual };
920 [where] => { $crate::token::Where };
921 [while] => { $crate::token::While };
922 [yield] => { $crate::token::Yield };
923 [&] => { $crate::token::And };
924 [&&] => { $crate::token::AndAnd };
925 [&=] => { $crate::token::AndEq };
926 [@] => { $crate::token::At };
927 [^] => { $crate::token::Caret };
928 [^=] => { $crate::token::CaretEq };
929 [:] => { $crate::token::Colon };
930 [,] => { $crate::token::Comma };
931 [$] => { $crate::token::Dollar };
932 [.] => { $crate::token::Dot };
933 [..] => { $crate::token::DotDot };
934 [...] => { $crate::token::DotDotDot };
935 [..=] => { $crate::token::DotDotEq };
936 [=] => { $crate::token::Eq };
937 [==] => { $crate::token::EqEq };
938 [=>] => { $crate::token::FatArrow };
939 [>=] => { $crate::token::Ge };
940 [>] => { $crate::token::Gt };
941 [<-] => { $crate::token::LArrow };
942 [<=] => { $crate::token::Le };
943 [<] => { $crate::token::Lt };
944 [-] => { $crate::token::Minus };
945 [-=] => { $crate::token::MinusEq };
946 [!=] => { $crate::token::Ne };
947 [!] => { $crate::token::Not };
948 [|] => { $crate::token::Or };
949 [|=] => { $crate::token::OrEq };
950 [||] => { $crate::token::OrOr };
951 [::] => { $crate::token::PathSep };
952 [%] => { $crate::token::Percent };
953 [%=] => { $crate::token::PercentEq };
954 [+] => { $crate::token::Plus };
955 [+=] => { $crate::token::PlusEq };
956 [#] => { $crate::token::Pound };
957 [?] => { $crate::token::Question };
958 [->] => { $crate::token::RArrow };
959 [;] => { $crate::token::Semi };
960 [<<] => { $crate::token::Shl };
961 [<<=] => { $crate::token::ShlEq };
962 [>>] => { $crate::token::Shr };
963 [>>=] => { $crate::token::ShrEq };
964 [/] => { $crate::token::Slash };
965 [/=] => { $crate::token::SlashEq };
966 [*] => { $crate::token::Star };
967 [*=] => { $crate::token::StarEq };
968 [~] => { $crate::token::Tilde };
969 [_] => { $crate::token::Underscore };
970}
971
972#[doc(hidden)]
974#[cfg(feature = "parsing")]
975pub(crate) mod parsing {
976 use crate::buffer::Cursor;
977 use crate::error::{Error, Result};
978 use crate::parse::ParseStream;
979 use proc_macro2::{Spacing, Span};
980
981 pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> {
982 input.step(|cursor| {
983 if let Some((ident, rest)) = cursor.ident() {
984 if ident == token {
985 return Ok((ident.span(), rest));
986 }
987 }
988 Err(cursor.error(format!("expected `{}`", token)))
989 })
990 }
991
992 pub(crate) fn peek_keyword(cursor: Cursor, token: &str) -> bool {
993 if let Some((ident, _rest)) = cursor.ident() {
994 ident == token
995 } else {
996 false
997 }
998 }
999
1000 #[doc(hidden)]
1001 pub fn punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]> {
1002 let mut spans = [input.span(); N];
1003 punct_helper(input, token, &mut spans)?;
1004 Ok(spans)
1005 }
1006
1007 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()> {
1008 input.step(|cursor| {
1009 let mut cursor = *cursor;
1010 assert_eq!(token.len(), spans.len());
1011
1012 for (i, ch) in token.chars().enumerate() {
1013 match cursor.punct() {
1014 Some((punct, rest)) => {
1015 spans[i] = punct.span();
1016 if punct.as_char() != ch {
1017 break;
1018 } else if i == token.len() - 1 {
1019 return Ok(((), rest));
1020 } else if punct.spacing() != Spacing::Joint {
1021 break;
1022 }
1023 cursor = rest;
1024 }
1025 None => break,
1026 }
1027 }
1028
1029 Err(Error::new(spans[0], format!("expected `{}`", token)))
1030 })
1031 }
1032
1033 #[doc(hidden)]
1034 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
1035 for (i, ch) in token.chars().enumerate() {
1036 match cursor.punct() {
1037 Some((punct, rest)) => {
1038 if punct.as_char() != ch {
1039 break;
1040 } else if i == token.len() - 1 {
1041 return true;
1042 } else if punct.spacing() != Spacing::Joint {
1043 break;
1044 }
1045 cursor = rest;
1046 }
1047 None => break,
1048 }
1049 }
1050 false
1051 }
1052}
1053
1054#[doc(hidden)]
1056#[cfg(feature = "printing")]
1057pub(crate) mod printing {
1058 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
1059 use quote::TokenStreamExt;
1060
1061 #[doc(hidden)]
1062 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
1063 assert_eq!(s.len(), spans.len());
1064
1065 let mut chars = s.chars();
1066 let mut spans = spans.iter();
1067 let ch = chars.next_back().unwrap();
1068 let span = spans.next_back().unwrap();
1069 for (ch, span) in chars.zip(spans) {
1070 let mut op = Punct::new(ch, Spacing::Joint);
1071 op.set_span(*span);
1072 tokens.append(op);
1073 }
1074
1075 let mut op = Punct::new(ch, Spacing::Alone);
1076 op.set_span(*span);
1077 tokens.append(op);
1078 }
1079
1080 pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
1081 tokens.append(Ident::new(s, span));
1082 }
1083
1084 pub(crate) fn delim(
1085 delim: Delimiter,
1086 span: Span,
1087 tokens: &mut TokenStream,
1088 inner: TokenStream,
1089 ) {
1090 let mut g = Group::new(delim, inner);
1091 g.set_span(span);
1092 tokens.append(g);
1093 }
1094}