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