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