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