1use std;
92#[cfg(feature = "extra-traits")]
93use std::cmp;
94#[cfg(feature = "extra-traits")]
95use std::fmt::{self, Debug};
96#[cfg(feature = "extra-traits")]
97use std::hash::{Hash, Hasher};
98use std::ops::{Deref, DerefMut};
99
100#[cfg(feature = "parsing")]
101use proc_macro2::Delimiter;
102#[cfg(any(feature = "parsing", feature = "printing"))]
103use proc_macro2::Ident;
104use proc_macro2::Span;
105#[cfg(feature = "printing")]
106use proc_macro2::TokenStream;
107#[cfg(feature = "printing")]
108use quote::{ToTokens, TokenStreamExt};
109
110use self::private::WithSpan;
111#[cfg(feature = "parsing")]
112use buffer::Cursor;
113#[cfg(feature = "parsing")]
114use error::Result;
115#[cfg(any(feature = "full", feature = "derive"))]
116#[cfg(feature = "parsing")]
117use lifetime::Lifetime;
118#[cfg(any(feature = "full", feature = "derive"))]
119#[cfg(feature = "parsing")]
120use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
121#[cfg(feature = "parsing")]
122use lookahead;
123#[cfg(feature = "parsing")]
124use parse::{Parse, ParseStream};
125use span::IntoSpans;
126
127#[cfg(feature = "parsing")]
131pub trait Token: private::Sealed {
132 #[doc(hidden)]
134 fn peek(cursor: Cursor) -> bool;
135
136 #[doc(hidden)]
138 fn display() -> &'static str;
139}
140
141mod private {
142 use proc_macro2::Span;
143
144 #[cfg(feature = "parsing")]
145 pub trait Sealed {}
146
147 #[repr(C)]
150 pub struct WithSpan {
151 pub span: Span,
152 }
153}
154
155#[cfg(feature = "parsing")]
156impl private::Sealed for Ident {}
157
158#[cfg(any(feature = "full", feature = "derive"))]
159#[cfg(feature = "parsing")]
160fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
161 use std::cell::Cell;
162 use std::rc::Rc;
163
164 let scope = Span::call_site();
165 let unexpected = Rc::new(Cell::new(None));
166 let buffer = ::private::new_parse_buffer(scope, cursor, unexpected);
167 peek(&buffer)
168}
169
170#[cfg(any(feature = "full", feature = "derive"))]
171macro_rules! impl_token {
172 ($name:ident $display:expr) => {
173 #[cfg(feature = "parsing")]
174 impl Token for $name {
175 fn peek(cursor: Cursor) -> bool {
176 fn peek(input: ParseStream) -> bool {
177 <$name as Parse>::parse(input).is_ok()
178 }
179 peek_impl(cursor, peek)
180 }
181
182 fn display() -> &'static str {
183 $display
184 }
185 }
186
187 #[cfg(feature = "parsing")]
188 impl private::Sealed for $name {}
189 };
190}
191
192#[cfg(any(feature = "full", feature = "derive"))]
193impl_token!(Lifetime "lifetime");
194#[cfg(any(feature = "full", feature = "derive"))]
195impl_token!(Lit "literal");
196#[cfg(any(feature = "full", feature = "derive"))]
197impl_token!(LitStr "string literal");
198#[cfg(any(feature = "full", feature = "derive"))]
199impl_token!(LitByteStr "byte string literal");
200#[cfg(any(feature = "full", feature = "derive"))]
201impl_token!(LitByte "byte literal");
202#[cfg(any(feature = "full", feature = "derive"))]
203impl_token!(LitChar "character literal");
204#[cfg(any(feature = "full", feature = "derive"))]
205impl_token!(LitInt "integer literal");
206#[cfg(any(feature = "full", feature = "derive"))]
207impl_token!(LitFloat "floating point literal");
208#[cfg(any(feature = "full", feature = "derive"))]
209impl_token!(LitBool "boolean literal");
210
211#[cfg(feature = "parsing")]
213#[doc(hidden)]
214pub trait CustomKeyword {
215 fn ident() -> &'static str;
216 fn display() -> &'static str;
217}
218
219#[cfg(feature = "parsing")]
220impl<K: CustomKeyword> private::Sealed for K {}
221
222#[cfg(feature = "parsing")]
223impl<K: CustomKeyword> Token for K {
224 fn peek(cursor: Cursor) -> bool {
225 parsing::peek_keyword(cursor, K::ident())
226 }
227
228 fn display() -> &'static str {
229 K::display()
230 }
231}
232
233macro_rules! define_keywords {
234 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
235 $(
236 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
237 #[$doc]
238 pub struct $name {
244 pub span: Span,
245 }
246
247 #[doc(hidden)]
248 #[allow(non_snake_case)]
249 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
250 $name {
251 span: span.into_spans()[0],
252 }
253 }
254
255 impl std::default::Default for $name {
256 fn default() -> Self {
257 $name {
258 span: Span::call_site(),
259 }
260 }
261 }
262
263 #[cfg(feature = "extra-traits")]
264 impl Debug for $name {
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 f.write_str(stringify!($name))
267 }
268 }
269
270 #[cfg(feature = "extra-traits")]
271 impl cmp::Eq for $name {}
272
273 #[cfg(feature = "extra-traits")]
274 impl PartialEq for $name {
275 fn eq(&self, _other: &$name) -> bool {
276 true
277 }
278 }
279
280 #[cfg(feature = "extra-traits")]
281 impl Hash for $name {
282 fn hash<H: Hasher>(&self, _state: &mut H) {}
283 }
284
285 #[cfg(feature = "printing")]
286 impl ToTokens for $name {
287 fn to_tokens(&self, tokens: &mut TokenStream) {
288 printing::keyword($token, self.span, tokens);
289 }
290 }
291
292 #[cfg(feature = "parsing")]
293 impl Parse for $name {
294 fn parse(input: ParseStream) -> Result<Self> {
295 Ok($name {
296 span: parsing::keyword(input, $token)?,
297 })
298 }
299 }
300
301 #[cfg(feature = "parsing")]
302 impl Token for $name {
303 fn peek(cursor: Cursor) -> bool {
304 parsing::peek_keyword(cursor, $token)
305 }
306
307 fn display() -> &'static str {
308 concat!("`", $token, "`")
309 }
310 }
311
312 #[cfg(feature = "parsing")]
313 impl private::Sealed for $name {}
314 )*
315 };
316}
317
318macro_rules! impl_deref_if_len_is_1 {
319 ($name:ident/1) => {
320 impl Deref for $name {
321 type Target = WithSpan;
322
323 fn deref(&self) -> &Self::Target {
324 unsafe { &*(self as *const Self as *const WithSpan) }
325 }
326 }
327
328 impl DerefMut for $name {
329 fn deref_mut(&mut self) -> &mut Self::Target {
330 unsafe { &mut *(self as *mut Self as *mut WithSpan) }
331 }
332 }
333 };
334
335 ($name:ident/$len:tt) => {};
336}
337
338macro_rules! define_punctuation_structs {
339 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
340 $(
341 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
342 #[repr(C)]
343 #[$doc]
344 pub struct $name {
350 pub spans: [Span; $len],
351 }
352
353 #[doc(hidden)]
354 #[allow(non_snake_case)]
355 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
356 $name {
357 spans: spans.into_spans(),
358 }
359 }
360
361 impl std::default::Default for $name {
362 fn default() -> Self {
363 $name {
364 spans: [Span::call_site(); $len],
365 }
366 }
367 }
368
369 #[cfg(feature = "extra-traits")]
370 impl Debug for $name {
371 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372 f.write_str(stringify!($name))
373 }
374 }
375
376 #[cfg(feature = "extra-traits")]
377 impl cmp::Eq for $name {}
378
379 #[cfg(feature = "extra-traits")]
380 impl PartialEq for $name {
381 fn eq(&self, _other: &$name) -> bool {
382 true
383 }
384 }
385
386 #[cfg(feature = "extra-traits")]
387 impl Hash for $name {
388 fn hash<H: Hasher>(&self, _state: &mut H) {}
389 }
390
391 impl_deref_if_len_is_1!($name/$len);
392 )*
393 };
394}
395
396macro_rules! define_punctuation {
397 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
398 $(
399 define_punctuation_structs! {
400 $token pub struct $name/$len #[$doc]
401 }
402
403 #[cfg(feature = "printing")]
404 impl ToTokens for $name {
405 fn to_tokens(&self, tokens: &mut TokenStream) {
406 printing::punct($token, &self.spans, tokens);
407 }
408 }
409
410 #[cfg(feature = "parsing")]
411 impl Parse for $name {
412 fn parse(input: ParseStream) -> Result<Self> {
413 Ok($name {
414 spans: parsing::punct(input, $token)?,
415 })
416 }
417 }
418
419 #[cfg(feature = "parsing")]
420 impl Token for $name {
421 fn peek(cursor: Cursor) -> bool {
422 parsing::peek_punct(cursor, $token)
423 }
424
425 fn display() -> &'static str {
426 concat!("`", $token, "`")
427 }
428 }
429
430 #[cfg(feature = "parsing")]
431 impl private::Sealed for $name {}
432 )*
433 };
434}
435
436macro_rules! define_delimiters {
437 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
438 $(
439 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
440 #[$doc]
441 pub struct $name {
442 pub span: Span,
443 }
444
445 #[doc(hidden)]
446 #[allow(non_snake_case)]
447 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
448 $name {
449 span: span.into_spans()[0],
450 }
451 }
452
453 impl std::default::Default for $name {
454 fn default() -> Self {
455 $name {
456 span: Span::call_site(),
457 }
458 }
459 }
460
461 #[cfg(feature = "extra-traits")]
462 impl Debug for $name {
463 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
464 f.write_str(stringify!($name))
465 }
466 }
467
468 #[cfg(feature = "extra-traits")]
469 impl cmp::Eq for $name {}
470
471 #[cfg(feature = "extra-traits")]
472 impl PartialEq for $name {
473 fn eq(&self, _other: &$name) -> bool {
474 true
475 }
476 }
477
478 #[cfg(feature = "extra-traits")]
479 impl Hash for $name {
480 fn hash<H: Hasher>(&self, _state: &mut H) {}
481 }
482
483 impl $name {
484 #[cfg(feature = "printing")]
485 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
486 where
487 F: FnOnce(&mut TokenStream),
488 {
489 printing::delim($token, self.span, tokens, f);
490 }
491 }
492
493 #[cfg(feature = "parsing")]
494 impl private::Sealed for $name {}
495 )*
496 };
497}
498
499define_punctuation_structs! {
500 "_" pub struct Underscore/1 }
502
503#[cfg(feature = "printing")]
504impl ToTokens for Underscore {
505 fn to_tokens(&self, tokens: &mut TokenStream) {
506 tokens.append(Ident::new("_", self.span));
507 }
508}
509
510#[cfg(feature = "parsing")]
511impl Parse for Underscore {
512 fn parse(input: ParseStream) -> Result<Self> {
513 input.step(|cursor| {
514 if let Some((ident, rest)) = cursor.ident() {
515 if ident == "_" {
516 return Ok((Underscore(ident.span()), rest));
517 }
518 }
519 if let Some((punct, rest)) = cursor.punct() {
520 if punct.as_char() == '_' {
521 return Ok((Underscore(punct.span()), rest));
522 }
523 }
524 Err(cursor.error("expected `_`"))
525 })
526 }
527}
528
529#[cfg(feature = "parsing")]
530impl Token for Underscore {
531 fn peek(cursor: Cursor) -> bool {
532 if let Some((ident, _rest)) = cursor.ident() {
533 return ident == "_";
534 }
535 if let Some((punct, _rest)) = cursor.punct() {
536 return punct.as_char() == '_';
537 }
538 false
539 }
540
541 fn display() -> &'static str {
542 "`_`"
543 }
544}
545
546#[cfg(feature = "parsing")]
547impl private::Sealed for Underscore {}
548
549#[cfg(feature = "parsing")]
550impl Token for Paren {
551 fn peek(cursor: Cursor) -> bool {
552 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
553 }
554
555 fn display() -> &'static str {
556 "parentheses"
557 }
558}
559
560#[cfg(feature = "parsing")]
561impl Token for Brace {
562 fn peek(cursor: Cursor) -> bool {
563 lookahead::is_delimiter(cursor, Delimiter::Brace)
564 }
565
566 fn display() -> &'static str {
567 "curly braces"
568 }
569}
570
571#[cfg(feature = "parsing")]
572impl Token for Bracket {
573 fn peek(cursor: Cursor) -> bool {
574 lookahead::is_delimiter(cursor, Delimiter::Bracket)
575 }
576
577 fn display() -> &'static str {
578 "square brackets"
579 }
580}
581
582#[cfg(feature = "parsing")]
583impl Token for Group {
584 fn peek(cursor: Cursor) -> bool {
585 lookahead::is_delimiter(cursor, Delimiter::None)
586 }
587
588 fn display() -> &'static str {
589 "invisible group"
590 }
591}
592
593define_keywords! {
594 "abstract" pub struct Abstract "as" pub struct As "async" pub struct Async "auto" pub struct Auto "become" pub struct Become "box" pub struct Box "break" pub struct Break "const" pub struct Const "continue" pub struct Continue "crate" pub struct Crate "default" pub struct Default "do" pub struct Do "dyn" pub struct Dyn "else" pub struct Else "enum" pub struct Enum "existential" pub struct Existential "extern" pub struct Extern "final" pub struct Final "fn" pub struct Fn "for" pub struct For "if" pub struct If "impl" pub struct Impl "in" pub struct In "let" pub struct Let "loop" pub struct Loop "macro" pub struct Macro "match" pub struct Match "mod" pub struct Mod "move" pub struct Move "mut" pub struct Mut "override" pub struct Override "priv" pub struct Priv "pub" pub struct Pub "ref" pub struct Ref "return" pub struct Return "Self" pub struct SelfType "self" pub struct SelfValue "static" pub struct Static "struct" pub struct Struct "super" pub struct Super "trait" pub struct Trait "try" pub struct Try "type" pub struct Type "typeof" pub struct Typeof "union" pub struct Union "unsafe" pub struct Unsafe "unsized" pub struct Unsized "use" pub struct Use "virtual" pub struct Virtual "where" pub struct Where "while" pub struct While "yield" pub struct Yield }
647
648define_punctuation! {
649 "+" pub struct Add/1 "+=" pub struct AddEq/2 "&" pub struct And/1 "&&" pub struct AndAnd/2 "&=" pub struct AndEq/2 "@" pub struct At/1 "!" pub struct Bang/1 "^" pub struct Caret/1 "^=" pub struct CaretEq/2 ":" pub struct Colon/1 "::" pub struct Colon2/2 "," pub struct Comma/1 "/" pub struct Div/1 "/=" pub struct DivEq/2 "$" pub struct Dollar/1 "." pub struct Dot/1 ".." pub struct Dot2/2 "..." pub struct Dot3/3 "..=" pub struct DotDotEq/3 "=" pub struct Eq/1 "==" pub struct EqEq/2 ">=" pub struct Ge/2 ">" pub struct Gt/1 "<=" pub struct Le/2 "<" pub struct Lt/1 "*=" pub struct MulEq/2 "!=" pub struct Ne/2 "|" pub struct Or/1 "|=" pub struct OrEq/2 "||" pub struct OrOr/2 "#" pub struct Pound/1 "?" pub struct Question/1 "->" pub struct RArrow/2 "<-" pub struct LArrow/2 "%" pub struct Rem/1 "%=" pub struct RemEq/2 "=>" pub struct FatArrow/2 ";" pub struct Semi/1 "<<" pub struct Shl/2 "<<=" pub struct ShlEq/3 ">>" pub struct Shr/2 ">>=" pub struct ShrEq/3 "*" pub struct Star/1 "-" pub struct Sub/1 "-=" pub struct SubEq/2 "~" pub struct Tilde/1 }
696
697define_delimiters! {
698 "{" pub struct Brace "[" pub struct Bracket "(" pub struct Paren " " pub struct Group }
703
704#[macro_export]
713#[cfg_attr(rustfmt, rustfmt_skip)]
714macro_rules! Token {
715 (abstract) => { $crate::token::Abstract };
716 (as) => { $crate::token::As };
717 (async) => { $crate::token::Async };
718 (auto) => { $crate::token::Auto };
719 (become) => { $crate::token::Become };
720 (box) => { $crate::token::Box };
721 (break) => { $crate::token::Break };
722 (const) => { $crate::token::Const };
723 (continue) => { $crate::token::Continue };
724 (crate) => { $crate::token::Crate };
725 (default) => { $crate::token::Default };
726 (do) => { $crate::token::Do };
727 (dyn) => { $crate::token::Dyn };
728 (else) => { $crate::token::Else };
729 (enum) => { $crate::token::Enum };
730 (existential) => { $crate::token::Existential };
731 (extern) => { $crate::token::Extern };
732 (final) => { $crate::token::Final };
733 (fn) => { $crate::token::Fn };
734 (for) => { $crate::token::For };
735 (if) => { $crate::token::If };
736 (impl) => { $crate::token::Impl };
737 (in) => { $crate::token::In };
738 (let) => { $crate::token::Let };
739 (loop) => { $crate::token::Loop };
740 (macro) => { $crate::token::Macro };
741 (match) => { $crate::token::Match };
742 (mod) => { $crate::token::Mod };
743 (move) => { $crate::token::Move };
744 (mut) => { $crate::token::Mut };
745 (override) => { $crate::token::Override };
746 (priv) => { $crate::token::Priv };
747 (pub) => { $crate::token::Pub };
748 (ref) => { $crate::token::Ref };
749 (return) => { $crate::token::Return };
750 (Self) => { $crate::token::SelfType };
751 (self) => { $crate::token::SelfValue };
752 (static) => { $crate::token::Static };
753 (struct) => { $crate::token::Struct };
754 (super) => { $crate::token::Super };
755 (trait) => { $crate::token::Trait };
756 (try) => { $crate::token::Try };
757 (type) => { $crate::token::Type };
758 (typeof) => { $crate::token::Typeof };
759 (union) => { $crate::token::Union };
760 (unsafe) => { $crate::token::Unsafe };
761 (unsized) => { $crate::token::Unsized };
762 (use) => { $crate::token::Use };
763 (virtual) => { $crate::token::Virtual };
764 (where) => { $crate::token::Where };
765 (while) => { $crate::token::While };
766 (yield) => { $crate::token::Yield };
767 (+) => { $crate::token::Add };
768 (+=) => { $crate::token::AddEq };
769 (&) => { $crate::token::And };
770 (&&) => { $crate::token::AndAnd };
771 (&=) => { $crate::token::AndEq };
772 (@) => { $crate::token::At };
773 (!) => { $crate::token::Bang };
774 (^) => { $crate::token::Caret };
775 (^=) => { $crate::token::CaretEq };
776 (:) => { $crate::token::Colon };
777 (::) => { $crate::token::Colon2 };
778 (,) => { $crate::token::Comma };
779 (/) => { $crate::token::Div };
780 (/=) => { $crate::token::DivEq };
781 (.) => { $crate::token::Dot };
782 (..) => { $crate::token::Dot2 };
783 (...) => { $crate::token::Dot3 };
784 (..=) => { $crate::token::DotDotEq };
785 (=) => { $crate::token::Eq };
786 (==) => { $crate::token::EqEq };
787 (>=) => { $crate::token::Ge };
788 (>) => { $crate::token::Gt };
789 (<=) => { $crate::token::Le };
790 (<) => { $crate::token::Lt };
791 (*=) => { $crate::token::MulEq };
792 (!=) => { $crate::token::Ne };
793 (|) => { $crate::token::Or };
794 (|=) => { $crate::token::OrEq };
795 (||) => { $crate::token::OrOr };
796 (#) => { $crate::token::Pound };
797 (?) => { $crate::token::Question };
798 (->) => { $crate::token::RArrow };
799 (<-) => { $crate::token::LArrow };
800 (%) => { $crate::token::Rem };
801 (%=) => { $crate::token::RemEq };
802 (=>) => { $crate::token::FatArrow };
803 (;) => { $crate::token::Semi };
804 (<<) => { $crate::token::Shl };
805 (<<=) => { $crate::token::ShlEq };
806 (>>) => { $crate::token::Shr };
807 (>>=) => { $crate::token::ShrEq };
808 (*) => { $crate::token::Star };
809 (-) => { $crate::token::Sub };
810 (-=) => { $crate::token::SubEq };
811 (~) => { $crate::token::Tilde };
812 (_) => { $crate::token::Underscore };
813}
814
815#[doc(hidden)]
818pub use self::SelfType as CapSelf;
819#[doc(hidden)]
820pub use self::SelfValue as Self_;
821
822#[cfg(feature = "parsing")]
823mod parsing {
824 use proc_macro2::{Spacing, Span};
825
826 use buffer::Cursor;
827 use error::{Error, Result};
828 use parse::ParseStream;
829 use span::FromSpans;
830
831 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
832 input.step(|cursor| {
833 if let Some((ident, rest)) = cursor.ident() {
834 if ident == token {
835 return Ok((ident.span(), rest));
836 }
837 }
838 Err(cursor.error(format!("expected `{}`", token)))
839 })
840 }
841
842 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
843 if let Some((ident, _rest)) = cursor.ident() {
844 ident == token
845 } else {
846 false
847 }
848 }
849
850 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
851 let mut spans = [input.cursor().span(); 3];
852 punct_helper(input, token, &mut spans)?;
853 Ok(S::from_spans(&spans))
854 }
855
856 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
857 input.step(|cursor| {
858 let mut cursor = *cursor;
859 assert!(token.len() <= spans.len());
860
861 for (i, ch) in token.chars().enumerate() {
862 match cursor.punct() {
863 Some((punct, rest)) => {
864 spans[i] = punct.span();
865 if punct.as_char() != ch {
866 break;
867 } else if i == token.len() - 1 {
868 return Ok(((), rest));
869 } else if punct.spacing() != Spacing::Joint {
870 break;
871 }
872 cursor = rest;
873 }
874 None => break,
875 }
876 }
877
878 Err(Error::new(spans[0], format!("expected `{}`", token)))
879 })
880 }
881
882 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
883 for (i, ch) in token.chars().enumerate() {
884 match cursor.punct() {
885 Some((punct, rest)) => {
886 if punct.as_char() != ch {
887 break;
888 } else if i == token.len() - 1 {
889 return true;
890 } else if punct.spacing() != Spacing::Joint {
891 break;
892 }
893 cursor = rest;
894 }
895 None => break,
896 }
897 }
898 false
899 }
900}
901
902#[cfg(feature = "printing")]
903mod printing {
904 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
905 use quote::TokenStreamExt;
906
907 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
908 assert_eq!(s.len(), spans.len());
909
910 let mut chars = s.chars();
911 let mut spans = spans.iter();
912 let ch = chars.next_back().unwrap();
913 let span = spans.next_back().unwrap();
914 for (ch, span) in chars.zip(spans) {
915 let mut op = Punct::new(ch, Spacing::Joint);
916 op.set_span(*span);
917 tokens.append(op);
918 }
919
920 let mut op = Punct::new(ch, Spacing::Alone);
921 op.set_span(*span);
922 tokens.append(op);
923 }
924
925 pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
926 tokens.append(Ident::new(s, span));
927 }
928
929 pub fn delim<F>(s: &str, span: Span, tokens: &mut TokenStream, f: F)
930 where
931 F: FnOnce(&mut TokenStream),
932 {
933 let delim = match s {
934 "(" => Delimiter::Parenthesis,
935 "[" => Delimiter::Bracket,
936 "{" => Delimiter::Brace,
937 " " => Delimiter::None,
938 _ => panic!("unknown delimiter: {}", s),
939 };
940 let mut inner = TokenStream::new();
941 f(&mut inner);
942 let mut g = Group::new(delim, inner);
943 g.set_span(span);
944 tokens.append(g);
945 }
946}