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 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
505 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
506 where
507 F: FnOnce(&mut TokenStream),
508 {
509 let mut inner = TokenStream::new();
510 f(&mut inner);
511 printing::delim(Delimiter::$delim, self.span.join(), tokens, inner);
512 }
513 }
514
515 #[cfg(feature = "parsing")]
516 impl private::Sealed for $name {}
517 )*
518 };
519}
520
521define_punctuation_structs! {
522 "_" pub struct Underscore/1 }
524
525#[cfg(feature = "printing")]
526#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
527impl ToTokens for Underscore {
528 fn to_tokens(&self, tokens: &mut TokenStream) {
529 tokens.append(Ident::new("_", self.span));
530 }
531}
532
533#[cfg(feature = "parsing")]
534#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
535impl Parse for Underscore {
536 fn parse(input: ParseStream) -> Result<Self> {
537 input.step(|cursor| {
538 if let Some((ident, rest)) = cursor.ident() {
539 if ident == "_" {
540 return Ok((Underscore(ident.span()), rest));
541 }
542 }
543 if let Some((punct, rest)) = cursor.punct() {
544 if punct.as_char() == '_' {
545 return Ok((Underscore(punct.span()), rest));
546 }
547 }
548 Err(cursor.error("expected `_`"))
549 })
550 }
551}
552
553#[cfg(feature = "parsing")]
554impl Token for Underscore {
555 fn peek(cursor: Cursor) -> bool {
556 if let Some((ident, _rest)) = cursor.ident() {
557 return ident == "_";
558 }
559 if let Some((punct, _rest)) = cursor.punct() {
560 return punct.as_char() == '_';
561 }
562 false
563 }
564
565 fn display() -> &'static str {
566 "`_`"
567 }
568}
569
570#[cfg(feature = "parsing")]
571impl private::Sealed for Underscore {}
572
573pub struct Group {
575 pub span: Span,
576}
577
578#[doc(hidden)]
579#[allow(non_snake_case)]
580pub fn Group<S: IntoSpans<Span>>(span: S) -> Group {
581 Group {
582 span: span.into_spans(),
583 }
584}
585
586impl std::default::Default for Group {
587 fn default() -> Self {
588 Group {
589 span: Span::call_site(),
590 }
591 }
592}
593
594#[cfg(feature = "clone-impls")]
595#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
596impl Copy for Group {}
597
598#[cfg(feature = "clone-impls")]
599#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
600impl Clone for Group {
601 fn clone(&self) -> Self {
602 *self
603 }
604}
605
606#[cfg(feature = "extra-traits")]
607#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
608impl Debug for Group {
609 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
610 f.write_str("Group")
611 }
612}
613
614#[cfg(feature = "extra-traits")]
615#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
616impl cmp::Eq for Group {}
617
618#[cfg(feature = "extra-traits")]
619#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
620impl PartialEq for Group {
621 fn eq(&self, _other: &Group) -> bool {
622 true
623 }
624}
625
626#[cfg(feature = "extra-traits")]
627#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
628impl Hash for Group {
629 fn hash<H: Hasher>(&self, _state: &mut H) {}
630}
631
632impl Group {
633 #[cfg(feature = "printing")]
634 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
635 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
636 where
637 F: FnOnce(&mut TokenStream),
638 {
639 let mut inner = TokenStream::new();
640 f(&mut inner);
641 printing::delim(Delimiter::None, self.span, tokens, inner);
642 }
643}
644
645#[cfg(feature = "parsing")]
646impl private::Sealed for Group {}
647
648#[cfg(feature = "parsing")]
649impl Token for Paren {
650 fn peek(cursor: Cursor) -> bool {
651 cursor.group(Delimiter::Parenthesis).is_some()
652 }
653
654 fn display() -> &'static str {
655 "parentheses"
656 }
657}
658
659#[cfg(feature = "parsing")]
660impl Token for Brace {
661 fn peek(cursor: Cursor) -> bool {
662 cursor.group(Delimiter::Brace).is_some()
663 }
664
665 fn display() -> &'static str {
666 "curly braces"
667 }
668}
669
670#[cfg(feature = "parsing")]
671impl Token for Bracket {
672 fn peek(cursor: Cursor) -> bool {
673 cursor.group(Delimiter::Bracket).is_some()
674 }
675
676 fn display() -> &'static str {
677 "square brackets"
678 }
679}
680
681#[cfg(feature = "parsing")]
682impl Token for Group {
683 fn peek(cursor: Cursor) -> bool {
684 cursor.group(Delimiter::None).is_some()
685 }
686
687 fn display() -> &'static str {
688 "invisible group"
689 }
690}
691
692define_keywords! {
693 "abstract" pub struct Abstract
694 "as" pub struct As
695 "async" pub struct Async
696 "auto" pub struct Auto
697 "await" pub struct Await
698 "become" pub struct Become
699 "box" pub struct Box
700 "break" pub struct Break
701 "const" pub struct Const
702 "continue" pub struct Continue
703 "crate" pub struct Crate
704 "default" pub struct Default
705 "do" pub struct Do
706 "dyn" pub struct Dyn
707 "else" pub struct Else
708 "enum" pub struct Enum
709 "extern" pub struct Extern
710 "final" pub struct Final
711 "fn" pub struct Fn
712 "for" pub struct For
713 "if" pub struct If
714 "impl" pub struct Impl
715 "in" pub struct In
716 "let" pub struct Let
717 "loop" pub struct Loop
718 "macro" pub struct Macro
719 "match" pub struct Match
720 "mod" pub struct Mod
721 "move" pub struct Move
722 "mut" pub struct Mut
723 "override" pub struct Override
724 "priv" pub struct Priv
725 "pub" pub struct Pub
726 "raw" pub struct Raw
727 "ref" pub struct Ref
728 "return" pub struct Return
729 "Self" pub struct SelfType
730 "self" pub struct SelfValue
731 "static" pub struct Static
732 "struct" pub struct Struct
733 "super" pub struct Super
734 "trait" pub struct Trait
735 "try" pub struct Try
736 "type" pub struct Type
737 "typeof" pub struct Typeof
738 "union" pub struct Union
739 "unsafe" pub struct Unsafe
740 "unsized" pub struct Unsized
741 "use" pub struct Use
742 "virtual" pub struct Virtual
743 "where" pub struct Where
744 "while" pub struct While
745 "yield" pub struct Yield
746}
747
748define_punctuation! {
749 "&" 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 }
796
797define_delimiters! {
798 Brace pub struct Brace Bracket pub struct Bracket Parenthesis pub struct Paren }
802
803#[macro_export]
871macro_rules! Token {
872 [abstract] => { $crate::token::Abstract };
873 [as] => { $crate::token::As };
874 [async] => { $crate::token::Async };
875 [auto] => { $crate::token::Auto };
876 [await] => { $crate::token::Await };
877 [become] => { $crate::token::Become };
878 [box] => { $crate::token::Box };
879 [break] => { $crate::token::Break };
880 [const] => { $crate::token::Const };
881 [continue] => { $crate::token::Continue };
882 [crate] => { $crate::token::Crate };
883 [default] => { $crate::token::Default };
884 [do] => { $crate::token::Do };
885 [dyn] => { $crate::token::Dyn };
886 [else] => { $crate::token::Else };
887 [enum] => { $crate::token::Enum };
888 [extern] => { $crate::token::Extern };
889 [final] => { $crate::token::Final };
890 [fn] => { $crate::token::Fn };
891 [for] => { $crate::token::For };
892 [if] => { $crate::token::If };
893 [impl] => { $crate::token::Impl };
894 [in] => { $crate::token::In };
895 [let] => { $crate::token::Let };
896 [loop] => { $crate::token::Loop };
897 [macro] => { $crate::token::Macro };
898 [match] => { $crate::token::Match };
899 [mod] => { $crate::token::Mod };
900 [move] => { $crate::token::Move };
901 [mut] => { $crate::token::Mut };
902 [override] => { $crate::token::Override };
903 [priv] => { $crate::token::Priv };
904 [pub] => { $crate::token::Pub };
905 [raw] => { $crate::token::Raw };
906 [ref] => { $crate::token::Ref };
907 [return] => { $crate::token::Return };
908 [Self] => { $crate::token::SelfType };
909 [self] => { $crate::token::SelfValue };
910 [static] => { $crate::token::Static };
911 [struct] => { $crate::token::Struct };
912 [super] => { $crate::token::Super };
913 [trait] => { $crate::token::Trait };
914 [try] => { $crate::token::Try };
915 [type] => { $crate::token::Type };
916 [typeof] => { $crate::token::Typeof };
917 [union] => { $crate::token::Union };
918 [unsafe] => { $crate::token::Unsafe };
919 [unsized] => { $crate::token::Unsized };
920 [use] => { $crate::token::Use };
921 [virtual] => { $crate::token::Virtual };
922 [where] => { $crate::token::Where };
923 [while] => { $crate::token::While };
924 [yield] => { $crate::token::Yield };
925 [&] => { $crate::token::And };
926 [&&] => { $crate::token::AndAnd };
927 [&=] => { $crate::token::AndEq };
928 [@] => { $crate::token::At };
929 [^] => { $crate::token::Caret };
930 [^=] => { $crate::token::CaretEq };
931 [:] => { $crate::token::Colon };
932 [,] => { $crate::token::Comma };
933 [$] => { $crate::token::Dollar };
934 [.] => { $crate::token::Dot };
935 [..] => { $crate::token::DotDot };
936 [...] => { $crate::token::DotDotDot };
937 [..=] => { $crate::token::DotDotEq };
938 [=] => { $crate::token::Eq };
939 [==] => { $crate::token::EqEq };
940 [=>] => { $crate::token::FatArrow };
941 [>=] => { $crate::token::Ge };
942 [>] => { $crate::token::Gt };
943 [<-] => { $crate::token::LArrow };
944 [<=] => { $crate::token::Le };
945 [<] => { $crate::token::Lt };
946 [-] => { $crate::token::Minus };
947 [-=] => { $crate::token::MinusEq };
948 [!=] => { $crate::token::Ne };
949 [!] => { $crate::token::Not };
950 [|] => { $crate::token::Or };
951 [|=] => { $crate::token::OrEq };
952 [||] => { $crate::token::OrOr };
953 [::] => { $crate::token::PathSep };
954 [%] => { $crate::token::Percent };
955 [%=] => { $crate::token::PercentEq };
956 [+] => { $crate::token::Plus };
957 [+=] => { $crate::token::PlusEq };
958 [#] => { $crate::token::Pound };
959 [?] => { $crate::token::Question };
960 [->] => { $crate::token::RArrow };
961 [;] => { $crate::token::Semi };
962 [<<] => { $crate::token::Shl };
963 [<<=] => { $crate::token::ShlEq };
964 [>>] => { $crate::token::Shr };
965 [>>=] => { $crate::token::ShrEq };
966 [/] => { $crate::token::Slash };
967 [/=] => { $crate::token::SlashEq };
968 [*] => { $crate::token::Star };
969 [*=] => { $crate::token::StarEq };
970 [~] => { $crate::token::Tilde };
971 [_] => { $crate::token::Underscore };
972}
973
974#[doc(hidden)]
976#[cfg(feature = "parsing")]
977pub(crate) mod parsing {
978 use crate::buffer::Cursor;
979 use crate::error::{Error, Result};
980 use crate::parse::ParseStream;
981 use proc_macro2::{Spacing, Span};
982
983 pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> {
984 input.step(|cursor| {
985 if let Some((ident, rest)) = cursor.ident() {
986 if ident == token {
987 return Ok((ident.span(), rest));
988 }
989 }
990 Err(cursor.error(format!("expected `{}`", token)))
991 })
992 }
993
994 pub(crate) fn peek_keyword(cursor: Cursor, token: &str) -> bool {
995 if let Some((ident, _rest)) = cursor.ident() {
996 ident == token
997 } else {
998 false
999 }
1000 }
1001
1002 #[doc(hidden)]
1003 pub fn punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]> {
1004 let mut spans = [input.span(); N];
1005 punct_helper(input, token, &mut spans)?;
1006 Ok(spans)
1007 }
1008
1009 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()> {
1010 input.step(|cursor| {
1011 let mut cursor = *cursor;
1012 assert_eq!(token.len(), spans.len());
1013
1014 for (i, ch) in token.chars().enumerate() {
1015 match cursor.punct() {
1016 Some((punct, rest)) => {
1017 spans[i] = punct.span();
1018 if punct.as_char() != ch {
1019 break;
1020 } else if i == token.len() - 1 {
1021 return Ok(((), rest));
1022 } else if punct.spacing() != Spacing::Joint {
1023 break;
1024 }
1025 cursor = rest;
1026 }
1027 None => break,
1028 }
1029 }
1030
1031 Err(Error::new(spans[0], format!("expected `{}`", token)))
1032 })
1033 }
1034
1035 #[doc(hidden)]
1036 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
1037 for (i, ch) in token.chars().enumerate() {
1038 match cursor.punct() {
1039 Some((punct, rest)) => {
1040 if punct.as_char() != ch {
1041 break;
1042 } else if i == token.len() - 1 {
1043 return true;
1044 } else if punct.spacing() != Spacing::Joint {
1045 break;
1046 }
1047 cursor = rest;
1048 }
1049 None => break,
1050 }
1051 }
1052 false
1053 }
1054}
1055
1056#[doc(hidden)]
1058#[cfg(feature = "printing")]
1059pub(crate) mod printing {
1060 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
1061 use quote::TokenStreamExt;
1062
1063 #[doc(hidden)]
1064 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
1065 assert_eq!(s.len(), spans.len());
1066
1067 let mut chars = s.chars();
1068 let mut spans = spans.iter();
1069 let ch = chars.next_back().unwrap();
1070 let span = spans.next_back().unwrap();
1071 for (ch, span) in chars.zip(spans) {
1072 let mut op = Punct::new(ch, Spacing::Joint);
1073 op.set_span(*span);
1074 tokens.append(op);
1075 }
1076
1077 let mut op = Punct::new(ch, Spacing::Alone);
1078 op.set_span(*span);
1079 tokens.append(op);
1080 }
1081
1082 pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
1083 tokens.append(Ident::new(s, span));
1084 }
1085
1086 pub(crate) fn delim(
1087 delim: Delimiter,
1088 span: Span,
1089 tokens: &mut TokenStream,
1090 inner: TokenStream,
1091 ) {
1092 let mut g = Group::new(delim, inner);
1093 g.set_span(span);
1094 tokens.append(g);
1095 }
1096}