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