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