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