]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/token.rs
a06bf9fae7c2958e2132e9533cca171d40913866
[rust.git] / src / libsyntax / parse / token.rs
1 pub use BinOpToken::*;
2 pub use Nonterminal::*;
3 pub use DelimToken::*;
4 pub use LitKind::*;
5 pub use TokenKind::*;
6
7 use crate::ast::{self};
8 use crate::parse::ParseSess;
9 use crate::print::pprust;
10 use crate::ptr::P;
11 use crate::symbol::kw;
12 use crate::syntax::parse::parse_stream_from_source_str;
13 use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree};
14
15 use syntax_pos::symbol::{self, Symbol};
16 use syntax_pos::{self, Span, FileName};
17 use log::info;
18
19 use std::fmt;
20 use std::mem;
21 use std::ops::Deref;
22 #[cfg(target_arch = "x86_64")]
23 use rustc_data_structures::static_assert_size;
24 use rustc_data_structures::sync::Lrc;
25
26 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
27 pub enum BinOpToken {
28     Plus,
29     Minus,
30     Star,
31     Slash,
32     Percent,
33     Caret,
34     And,
35     Or,
36     Shl,
37     Shr,
38 }
39
40 /// A delimiter token.
41 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
42 pub enum DelimToken {
43     /// A round parenthesis (i.e., `(` or `)`).
44     Paren,
45     /// A square bracket (i.e., `[` or `]`).
46     Bracket,
47     /// A curly brace (i.e., `{` or `}`).
48     Brace,
49     /// An empty delimiter.
50     NoDelim,
51 }
52
53 impl DelimToken {
54     pub fn len(self) -> usize {
55         if self == NoDelim { 0 } else { 1 }
56     }
57
58     pub fn is_empty(self) -> bool {
59         self == NoDelim
60     }
61 }
62
63 #[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
64 pub enum LitKind {
65     Bool, // AST only, must never appear in a `Token`
66     Byte,
67     Char,
68     Integer,
69     Float,
70     Str,
71     StrRaw(u16), // raw string delimited by `n` hash symbols
72     ByteStr,
73     ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols
74     Err,
75 }
76
77 /// A literal token.
78 #[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
79 pub struct Lit {
80     pub kind: LitKind,
81     pub symbol: Symbol,
82     pub suffix: Option<Symbol>,
83 }
84
85 impl LitKind {
86     /// An English article for the literal token kind.
87     crate fn article(self) -> &'static str {
88         match self {
89             Integer | Err => "an",
90             _ => "a",
91         }
92     }
93
94     crate fn descr(self) -> &'static str {
95         match self {
96             Bool => panic!("literal token contains `Lit::Bool`"),
97             Byte => "byte",
98             Char => "char",
99             Integer => "integer",
100             Float => "float",
101             Str | StrRaw(..) => "string",
102             ByteStr | ByteStrRaw(..) => "byte string",
103             Err => "error",
104         }
105     }
106
107     crate fn may_have_suffix(self) -> bool {
108         match self {
109             Integer | Float | Err => true,
110             _ => false,
111         }
112     }
113 }
114
115 impl Lit {
116     pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
117         Lit { kind, symbol, suffix }
118     }
119 }
120
121 pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
122     let ident_token: TokenKind = Ident(ident, is_raw);
123
124     !ident_token.is_reserved_ident() ||
125     ident_token.is_path_segment_keyword() ||
126     [
127         kw::Async,
128
129         // FIXME: remove when `await!(..)` syntax is removed
130         // https://github.com/rust-lang/rust/issues/60610
131         kw::Await,
132
133         kw::Do,
134         kw::Box,
135         kw::Break,
136         kw::Continue,
137         kw::False,
138         kw::For,
139         kw::If,
140         kw::Loop,
141         kw::Match,
142         kw::Move,
143         kw::Return,
144         kw::True,
145         kw::Unsafe,
146         kw::While,
147         kw::Yield,
148         kw::Static,
149     ].contains(&ident.name)
150 }
151
152 fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
153     let ident_token: TokenKind = Ident(ident, is_raw);
154
155     !ident_token.is_reserved_ident() ||
156     ident_token.is_path_segment_keyword() ||
157     [
158         kw::Underscore,
159         kw::For,
160         kw::Impl,
161         kw::Fn,
162         kw::Unsafe,
163         kw::Extern,
164         kw::Typeof,
165         kw::Dyn,
166     ].contains(&ident.name)
167 }
168
169 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
170 pub enum TokenKind {
171     /* Expression-operator symbols. */
172     Eq,
173     Lt,
174     Le,
175     EqEq,
176     Ne,
177     Ge,
178     Gt,
179     AndAnd,
180     OrOr,
181     Not,
182     Tilde,
183     BinOp(BinOpToken),
184     BinOpEq(BinOpToken),
185
186     /* Structural symbols */
187     At,
188     Dot,
189     DotDot,
190     DotDotDot,
191     DotDotEq,
192     Comma,
193     Semi,
194     Colon,
195     ModSep,
196     RArrow,
197     LArrow,
198     FatArrow,
199     Pound,
200     Dollar,
201     Question,
202     /// Used by proc macros for representing lifetimes, not generated by lexer right now.
203     SingleQuote,
204     /// An opening delimiter (e.g., `{`).
205     OpenDelim(DelimToken),
206     /// A closing delimiter (e.g., `}`).
207     CloseDelim(DelimToken),
208
209     /* Literals */
210     Literal(Lit),
211
212     /* Name components */
213     Ident(ast::Ident, /* is_raw */ bool),
214     Lifetime(ast::Ident),
215
216     Interpolated(Lrc<Nonterminal>),
217
218     // Can be expanded into several tokens.
219     /// A doc comment.
220     DocComment(ast::Name),
221
222     // Junk. These carry no data because we don't really care about the data
223     // they *would* carry, and don't really want to allocate a new ident for
224     // them. Instead, users could extract that from the associated span.
225
226     /// Whitespace.
227     Whitespace,
228     /// A comment.
229     Comment,
230     Shebang(ast::Name),
231
232     Eof,
233 }
234
235 // `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
236 #[cfg(target_arch = "x86_64")]
237 static_assert_size!(TokenKind, 16);
238
239 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
240 pub struct Token {
241     pub kind: TokenKind,
242     pub span: Span,
243 }
244
245 impl TokenKind {
246     /// Recovers a `TokenKind` from an `ast::Ident`. This creates a raw identifier if necessary.
247     pub fn from_ast_ident(ident: ast::Ident) -> TokenKind {
248         Ident(ident, ident.is_raw_guess())
249     }
250
251     crate fn is_like_plus(&self) -> bool {
252         match *self {
253             BinOp(Plus) | BinOpEq(Plus) => true,
254             _ => false,
255         }
256     }
257
258     /// Returns `true` if the token can appear at the start of an expression.
259     crate fn can_begin_expr(&self) -> bool {
260         match *self {
261             Ident(ident, is_raw)              =>
262                 ident_can_begin_expr(ident, is_raw), // value name or keyword
263             OpenDelim(..)                     | // tuple, array or block
264             Literal(..)                       | // literal
265             Not                               | // operator not
266             BinOp(Minus)                      | // unary minus
267             BinOp(Star)                       | // dereference
268             BinOp(Or) | OrOr                  | // closure
269             BinOp(And)                        | // reference
270             AndAnd                            | // double reference
271             // DotDotDot is no longer supported, but we need some way to display the error
272             DotDot | DotDotDot | DotDotEq     | // range notation
273             Lt | BinOp(Shl)                   | // associated path
274             ModSep                            | // global path
275             Lifetime(..)                      | // labeled loop
276             Pound                             => true, // expression attributes
277             Interpolated(ref nt) => match **nt {
278                 NtLiteral(..) |
279                 NtIdent(..)   |
280                 NtExpr(..)    |
281                 NtBlock(..)   |
282                 NtPath(..)    |
283                 NtLifetime(..) => true,
284                 _ => false,
285             },
286             _ => false,
287         }
288     }
289
290     /// Returns `true` if the token can appear at the start of a type.
291     crate fn can_begin_type(&self) -> bool {
292         match *self {
293             Ident(ident, is_raw)        =>
294                 ident_can_begin_type(ident, is_raw), // type name or keyword
295             OpenDelim(Paren)            | // tuple
296             OpenDelim(Bracket)          | // array
297             Not                         | // never
298             BinOp(Star)                 | // raw pointer
299             BinOp(And)                  | // reference
300             AndAnd                      | // double reference
301             Question                    | // maybe bound in trait object
302             Lifetime(..)                | // lifetime bound in trait object
303             Lt | BinOp(Shl)             | // associated path
304             ModSep                      => true, // global path
305             Interpolated(ref nt) => match **nt {
306                 NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true,
307                 _ => false,
308             },
309             _ => false,
310         }
311     }
312
313     /// Returns `true` if the token can appear at the start of a const param.
314     pub fn can_begin_const_arg(&self) -> bool {
315         match self {
316             OpenDelim(Brace) => true,
317             Interpolated(ref nt) => match **nt {
318                 NtExpr(..) => true,
319                 NtBlock(..) => true,
320                 NtLiteral(..) => true,
321                 _ => false,
322             }
323             _ => self.can_begin_literal_or_bool(),
324         }
325     }
326
327     /// Returns `true` if the token can appear at the start of a generic bound.
328     crate fn can_begin_bound(&self) -> bool {
329         self.is_path_start() || self.is_lifetime() || self.is_keyword(kw::For) ||
330         self == &Question || self == &OpenDelim(Paren)
331     }
332
333     pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
334         Literal(Lit::new(kind, symbol, suffix))
335     }
336
337     /// Returns `true` if the token is any literal
338     crate fn is_lit(&self) -> bool {
339         match *self {
340             Literal(..) => true,
341             _           => false,
342         }
343     }
344
345     crate fn expect_lit(&self) -> Lit {
346         match *self {
347             Literal(lit) => lit,
348             _=> panic!("`expect_lit` called on non-literal"),
349         }
350     }
351
352     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
353     /// for example a '-42', or one of the boolean idents).
354     crate fn can_begin_literal_or_bool(&self) -> bool {
355         match *self {
356             Literal(..)  => true,
357             BinOp(Minus) => true,
358             Ident(ident, false) if ident.name == kw::True => true,
359             Ident(ident, false) if ident.name == kw::False => true,
360             Interpolated(ref nt) => match **nt {
361                 NtLiteral(..) => true,
362                 _             => false,
363             },
364             _            => false,
365         }
366     }
367
368     /// Returns an identifier if this token is an identifier.
369     pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
370         match *self {
371             Ident(ident, is_raw) => Some((ident, is_raw)),
372             Interpolated(ref nt) => match **nt {
373                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
374                 _ => None,
375             },
376             _ => None,
377         }
378     }
379     /// Returns a lifetime identifier if this token is a lifetime.
380     pub fn lifetime(&self) -> Option<ast::Ident> {
381         match *self {
382             Lifetime(ident) => Some(ident),
383             Interpolated(ref nt) => match **nt {
384                 NtLifetime(ident) => Some(ident),
385                 _ => None,
386             },
387             _ => None,
388         }
389     }
390     /// Returns `true` if the token is an identifier.
391     pub fn is_ident(&self) -> bool {
392         self.ident().is_some()
393     }
394     /// Returns `true` if the token is a lifetime.
395     crate fn is_lifetime(&self) -> bool {
396         self.lifetime().is_some()
397     }
398
399     /// Returns `true` if the token is a identifier whose name is the given
400     /// string slice.
401     crate fn is_ident_named(&self, name: Symbol) -> bool {
402         match self.ident() {
403             Some((ident, _)) => ident.name == name,
404             None => false
405         }
406     }
407
408     /// Returns `true` if the token is an interpolated path.
409     fn is_path(&self) -> bool {
410         if let Interpolated(ref nt) = *self {
411             if let NtPath(..) = **nt {
412                 return true;
413             }
414         }
415         false
416     }
417
418     /// Returns `true` if the token is either the `mut` or `const` keyword.
419     crate fn is_mutability(&self) -> bool {
420         self.is_keyword(kw::Mut) ||
421         self.is_keyword(kw::Const)
422     }
423
424     crate fn is_qpath_start(&self) -> bool {
425         self == &Lt || self == &BinOp(Shl)
426     }
427
428     crate fn is_path_start(&self) -> bool {
429         self == &ModSep || self.is_qpath_start() || self.is_path() ||
430         self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident()
431     }
432
433     /// Returns `true` if the token is a given keyword, `kw`.
434     pub fn is_keyword(&self, kw: Symbol) -> bool {
435         self.ident().map(|(ident, is_raw)| ident.name == kw && !is_raw).unwrap_or(false)
436     }
437
438     pub fn is_path_segment_keyword(&self) -> bool {
439         match self.ident() {
440             Some((id, false)) => id.is_path_segment_keyword(),
441             _ => false,
442         }
443     }
444
445     // Returns true for reserved identifiers used internally for elided lifetimes,
446     // unnamed method parameters, crate root module, error recovery etc.
447     pub fn is_special_ident(&self) -> bool {
448         match self.ident() {
449             Some((id, false)) => id.is_special(),
450             _ => false,
451         }
452     }
453
454     /// Returns `true` if the token is a keyword used in the language.
455     crate fn is_used_keyword(&self) -> bool {
456         match self.ident() {
457             Some((id, false)) => id.is_used_keyword(),
458             _ => false,
459         }
460     }
461
462     /// Returns `true` if the token is a keyword reserved for possible future use.
463     crate fn is_unused_keyword(&self) -> bool {
464         match self.ident() {
465             Some((id, false)) => id.is_unused_keyword(),
466             _ => false,
467         }
468     }
469
470     /// Returns `true` if the token is either a special identifier or a keyword.
471     pub fn is_reserved_ident(&self) -> bool {
472         match self.ident() {
473             Some((id, false)) => id.is_reserved(),
474             _ => false,
475         }
476     }
477
478     crate fn glue(self, joint: TokenKind) -> Option<TokenKind> {
479         Some(match self {
480             Eq => match joint {
481                 Eq => EqEq,
482                 Gt => FatArrow,
483                 _ => return None,
484             },
485             Lt => match joint {
486                 Eq => Le,
487                 Lt => BinOp(Shl),
488                 Le => BinOpEq(Shl),
489                 BinOp(Minus) => LArrow,
490                 _ => return None,
491             },
492             Gt => match joint {
493                 Eq => Ge,
494                 Gt => BinOp(Shr),
495                 Ge => BinOpEq(Shr),
496                 _ => return None,
497             },
498             Not => match joint {
499                 Eq => Ne,
500                 _ => return None,
501             },
502             BinOp(op) => match joint {
503                 Eq => BinOpEq(op),
504                 BinOp(And) if op == And => AndAnd,
505                 BinOp(Or) if op == Or => OrOr,
506                 Gt if op == Minus => RArrow,
507                 _ => return None,
508             },
509             Dot => match joint {
510                 Dot => DotDot,
511                 DotDot => DotDotDot,
512                 _ => return None,
513             },
514             DotDot => match joint {
515                 Dot => DotDotDot,
516                 Eq => DotDotEq,
517                 _ => return None,
518             },
519             Colon => match joint {
520                 Colon => ModSep,
521                 _ => return None,
522             },
523             SingleQuote => match joint {
524                 Ident(ident, false) => {
525                     let name = Symbol::intern(&format!("'{}", ident));
526                     Lifetime(symbol::Ident {
527                         name,
528                         span: ident.span,
529                     })
530                 }
531                 _ => return None,
532             },
533
534             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot |
535             DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
536             Question | OpenDelim(..) | CloseDelim(..) |
537             Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
538             Whitespace | Comment | Shebang(..) | Eof => return None,
539         })
540     }
541
542     /// Returns tokens that are likely to be typed accidentally instead of the current token.
543     /// Enables better error recovery when the wrong token is found.
544     crate fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
545         match *self {
546             Comma => Some(vec![Dot, Lt, Semi]),
547             Semi => Some(vec![Colon, Comma]),
548             _ => None
549         }
550     }
551
552     // See comments in `Nonterminal::to_tokenstream` for why we care about
553     // *probably* equal here rather than actual equality
554     crate fn probably_equal_for_proc_macro(&self, other: &TokenKind) -> bool {
555         if mem::discriminant(self) != mem::discriminant(other) {
556             return false
557         }
558         match (self, other) {
559             (&Eq, &Eq) |
560             (&Lt, &Lt) |
561             (&Le, &Le) |
562             (&EqEq, &EqEq) |
563             (&Ne, &Ne) |
564             (&Ge, &Ge) |
565             (&Gt, &Gt) |
566             (&AndAnd, &AndAnd) |
567             (&OrOr, &OrOr) |
568             (&Not, &Not) |
569             (&Tilde, &Tilde) |
570             (&At, &At) |
571             (&Dot, &Dot) |
572             (&DotDot, &DotDot) |
573             (&DotDotDot, &DotDotDot) |
574             (&DotDotEq, &DotDotEq) |
575             (&Comma, &Comma) |
576             (&Semi, &Semi) |
577             (&Colon, &Colon) |
578             (&ModSep, &ModSep) |
579             (&RArrow, &RArrow) |
580             (&LArrow, &LArrow) |
581             (&FatArrow, &FatArrow) |
582             (&Pound, &Pound) |
583             (&Dollar, &Dollar) |
584             (&Question, &Question) |
585             (&Whitespace, &Whitespace) |
586             (&Comment, &Comment) |
587             (&Eof, &Eof) => true,
588
589             (&BinOp(a), &BinOp(b)) |
590             (&BinOpEq(a), &BinOpEq(b)) => a == b,
591
592             (&OpenDelim(a), &OpenDelim(b)) |
593             (&CloseDelim(a), &CloseDelim(b)) => a == b,
594
595             (&DocComment(a), &DocComment(b)) |
596             (&Shebang(a), &Shebang(b)) => a == b,
597
598             (&Literal(a), &Literal(b)) => a == b,
599
600             (&Lifetime(a), &Lifetime(b)) => a.name == b.name,
601             (&Ident(a, b), &Ident(c, d)) => b == d && (a.name == c.name ||
602                                                        a.name == kw::DollarCrate ||
603                                                        c.name == kw::DollarCrate),
604
605             (&Interpolated(_), &Interpolated(_)) => false,
606
607             _ => panic!("forgot to add a token?"),
608         }
609     }
610 }
611
612 impl PartialEq<TokenKind> for Token {
613     fn eq(&self, rhs: &TokenKind) -> bool {
614         self.kind == *rhs
615     }
616 }
617
618 // FIXME: Remove this after all necessary methods are moved from `TokenKind` to `Token`.
619 impl Deref for Token {
620     type Target = TokenKind;
621     fn deref(&self) -> &Self::Target {
622         &self.kind
623     }
624 }
625
626 #[derive(Clone, RustcEncodable, RustcDecodable)]
627 /// For interpolation during macro expansion.
628 pub enum Nonterminal {
629     NtItem(P<ast::Item>),
630     NtBlock(P<ast::Block>),
631     NtStmt(ast::Stmt),
632     NtPat(P<ast::Pat>),
633     NtExpr(P<ast::Expr>),
634     NtTy(P<ast::Ty>),
635     NtIdent(ast::Ident, /* is_raw */ bool),
636     NtLifetime(ast::Ident),
637     NtLiteral(P<ast::Expr>),
638     /// Stuff inside brackets for attributes
639     NtMeta(ast::MetaItem),
640     NtPath(ast::Path),
641     NtVis(ast::Visibility),
642     NtTT(TokenTree),
643     // Used only for passing items to proc macro attributes (they are not
644     // strictly necessary for that, `Annotatable` can be converted into
645     // tokens directly, but doing that naively regresses pretty-printing).
646     NtTraitItem(ast::TraitItem),
647     NtImplItem(ast::ImplItem),
648     NtForeignItem(ast::ForeignItem),
649 }
650
651 impl PartialEq for Nonterminal {
652     fn eq(&self, rhs: &Self) -> bool {
653         match (self, rhs) {
654             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) =>
655                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs,
656             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
657             (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
658             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
659             // correctly based on data from AST. This will prevent them from matching each other
660             // in macros. The comparison will become possible only when each nonterminal has an
661             // attached token stream from which it was parsed.
662             _ => false,
663         }
664     }
665 }
666
667 impl fmt::Debug for Nonterminal {
668     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
669         match *self {
670             NtItem(..) => f.pad("NtItem(..)"),
671             NtBlock(..) => f.pad("NtBlock(..)"),
672             NtStmt(..) => f.pad("NtStmt(..)"),
673             NtPat(..) => f.pad("NtPat(..)"),
674             NtExpr(..) => f.pad("NtExpr(..)"),
675             NtTy(..) => f.pad("NtTy(..)"),
676             NtIdent(..) => f.pad("NtIdent(..)"),
677             NtLiteral(..) => f.pad("NtLiteral(..)"),
678             NtMeta(..) => f.pad("NtMeta(..)"),
679             NtPath(..) => f.pad("NtPath(..)"),
680             NtTT(..) => f.pad("NtTT(..)"),
681             NtImplItem(..) => f.pad("NtImplItem(..)"),
682             NtTraitItem(..) => f.pad("NtTraitItem(..)"),
683             NtForeignItem(..) => f.pad("NtForeignItem(..)"),
684             NtVis(..) => f.pad("NtVis(..)"),
685             NtLifetime(..) => f.pad("NtLifetime(..)"),
686         }
687     }
688 }
689
690 impl Nonterminal {
691     pub fn to_tokenstream(&self, sess: &ParseSess, span: Span) -> TokenStream {
692         // A `Nonterminal` is often a parsed AST item. At this point we now
693         // need to convert the parsed AST to an actual token stream, e.g.
694         // un-parse it basically.
695         //
696         // Unfortunately there's not really a great way to do that in a
697         // guaranteed lossless fashion right now. The fallback here is to just
698         // stringify the AST node and reparse it, but this loses all span
699         // information.
700         //
701         // As a result, some AST nodes are annotated with the token stream they
702         // came from. Here we attempt to extract these lossless token streams
703         // before we fall back to the stringification.
704         let tokens = match *self {
705             Nonterminal::NtItem(ref item) => {
706                 prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
707             }
708             Nonterminal::NtTraitItem(ref item) => {
709                 prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
710             }
711             Nonterminal::NtImplItem(ref item) => {
712                 prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
713             }
714             Nonterminal::NtIdent(ident, is_raw) => {
715                 let token = Ident(ident, is_raw);
716                 Some(TokenTree::token(ident.span, token).into())
717             }
718             Nonterminal::NtLifetime(ident) => {
719                 let token = Lifetime(ident);
720                 Some(TokenTree::token(ident.span, token).into())
721             }
722             Nonterminal::NtTT(ref tt) => {
723                 Some(tt.clone().into())
724             }
725             _ => None,
726         };
727
728         // FIXME(#43081): Avoid this pretty-print + reparse hack
729         let source = pprust::nonterminal_to_string(self);
730         let filename = FileName::macro_expansion_source_code(&source);
731         let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span));
732
733         // During early phases of the compiler the AST could get modified
734         // directly (e.g., attributes added or removed) and the internal cache
735         // of tokens my not be invalidated or updated. Consequently if the
736         // "lossless" token stream disagrees with our actual stringification
737         // (which has historically been much more battle-tested) then we go
738         // with the lossy stream anyway (losing span information).
739         //
740         // Note that the comparison isn't `==` here to avoid comparing spans,
741         // but it *also* is a "probable" equality which is a pretty weird
742         // definition. We mostly want to catch actual changes to the AST
743         // like a `#[cfg]` being processed or some weird `macro_rules!`
744         // expansion.
745         //
746         // What we *don't* want to catch is the fact that a user-defined
747         // literal like `0xf` is stringified as `15`, causing the cached token
748         // stream to not be literal `==` token-wise (ignoring spans) to the
749         // token stream we got from stringification.
750         //
751         // Instead the "probably equal" check here is "does each token
752         // recursively have the same discriminant?" We basically don't look at
753         // the token values here and assume that such fine grained token stream
754         // modifications, including adding/removing typically non-semantic
755         // tokens such as extra braces and commas, don't happen.
756         if let Some(tokens) = tokens {
757             if tokens.probably_equal_for_proc_macro(&tokens_for_real) {
758                 return tokens
759             }
760             info!("cached tokens found, but they're not \"probably equal\", \
761                    going with stringified version");
762         }
763         return tokens_for_real
764     }
765 }
766
767 crate fn is_op(tok: &TokenKind) -> bool {
768     match *tok {
769         OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) |
770         Ident(..) | Lifetime(..) | Interpolated(..) |
771         Whitespace | Comment | Shebang(..) | Eof => false,
772         _ => true,
773     }
774 }
775
776 fn prepend_attrs(sess: &ParseSess,
777                  attrs: &[ast::Attribute],
778                  tokens: Option<&tokenstream::TokenStream>,
779                  span: syntax_pos::Span)
780     -> Option<tokenstream::TokenStream>
781 {
782     let tokens = tokens?;
783     if attrs.len() == 0 {
784         return Some(tokens.clone())
785     }
786     let mut builder = tokenstream::TokenStreamBuilder::new();
787     for attr in attrs {
788         assert_eq!(attr.style, ast::AttrStyle::Outer,
789                    "inner attributes should prevent cached tokens from existing");
790
791         let source = pprust::attr_to_string(attr);
792         let macro_filename = FileName::macro_expansion_source_code(&source);
793         if attr.is_sugared_doc {
794             let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
795             builder.push(stream);
796             continue
797         }
798
799         // synthesize # [ $path $tokens ] manually here
800         let mut brackets = tokenstream::TokenStreamBuilder::new();
801
802         // For simple paths, push the identifier directly
803         if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() {
804             let ident = attr.path.segments[0].ident;
805             let token = Ident(ident, ident.as_str().starts_with("r#"));
806             brackets.push(tokenstream::TokenTree::token(ident.span, token));
807
808         // ... and for more complicated paths, fall back to a reparse hack that
809         // should eventually be removed.
810         } else {
811             let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
812             brackets.push(stream);
813         }
814
815         brackets.push(attr.tokens.clone());
816
817         // The span we list here for `#` and for `[ ... ]` are both wrong in
818         // that it encompasses more than each token, but it hopefully is "good
819         // enough" for now at least.
820         builder.push(tokenstream::TokenTree::token(attr.span, Pound));
821         let delim_span = DelimSpan::from_single(attr.span);
822         builder.push(tokenstream::TokenTree::Delimited(
823             delim_span, DelimToken::Bracket, brackets.build().into()));
824     }
825     builder.push(tokens.clone());
826     Some(builder.build())
827 }