]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/token.rs
'label can start expressions
[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     /// An opening delimiter, eg. `{`
214     OpenDelim(DelimToken),
215     /// A closing delimiter, eg. `}`
216     CloseDelim(DelimToken),
217
218     /* Literals */
219     Literal(Lit, Option<ast::Name>),
220
221     /* Name components */
222     Ident(ast::Ident, /* is_raw */ bool),
223     Lifetime(ast::Ident),
224
225     // The `LazyTokenStream` is a pure function of the `Nonterminal`,
226     // and so the `LazyTokenStream` can be ignored by Eq, Hash, etc.
227     Interpolated(Lrc<(Nonterminal, LazyTokenStream)>),
228     // Can be expanded into several tokens.
229     /// Doc comment
230     DocComment(ast::Name),
231
232     // Junk. These carry no data because we don't really care about the data
233     // they *would* carry, and don't really want to allocate a new ident for
234     // them. Instead, users could extract that from the associated span.
235
236     /// Whitespace
237     Whitespace,
238     /// Comment
239     Comment,
240     Shebang(ast::Name),
241
242     Eof,
243 }
244
245 impl Token {
246     pub fn interpolated(nt: Nonterminal) -> Token {
247         Token::Interpolated(Lrc::new((nt, LazyTokenStream::new())))
248     }
249
250     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
251     pub fn from_ast_ident(ident: ast::Ident) -> Token {
252         Ident(ident, is_raw_guess(ident))
253     }
254
255     /// Returns `true` if the token starts with '>'.
256     pub fn is_like_gt(&self) -> bool {
257         match *self {
258             BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
259             _ => false,
260         }
261     }
262
263     /// Returns `true` if the token can appear at the start of an expression.
264     pub fn can_begin_expr(&self) -> bool {
265         match *self {
266             Ident(ident, is_raw)              =>
267                 ident_can_begin_expr(ident, is_raw), // value name or keyword
268             OpenDelim(..)                     | // tuple, array or block
269             Literal(..)                       | // literal
270             Not                               | // operator not
271             BinOp(Minus)                      | // unary minus
272             BinOp(Star)                       | // dereference
273             BinOp(Or) | OrOr                  | // closure
274             BinOp(And)                        | // reference
275             AndAnd                            | // double reference
276             // DotDotDot is no longer supported, but we need some way to display the error
277             DotDot | DotDotDot | DotDotEq     | // range notation
278             Lt | BinOp(Shl)                   | // associated path
279             ModSep                            | // global path
280             Lifetime(..)                      | // labeled loop
281             Pound                             => true, // expression attributes
282             Interpolated(ref nt) => match nt.0 {
283                 NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) | NtLifetime(..) => true,
284                 _ => false,
285             },
286             _ => false,
287         }
288     }
289
290     /// Returns `true` if the token can appear at the start of a type.
291     pub fn can_begin_type(&self) -> bool {
292         match *self {
293             Ident(ident, is_raw)        =>
294                 ident_can_begin_type(ident, is_raw), // type name or keyword
295             OpenDelim(Paren)            | // tuple
296             OpenDelim(Bracket)          | // array
297             Not                         | // never
298             BinOp(Star)                 | // raw pointer
299             BinOp(And)                  | // reference
300             AndAnd                      | // double reference
301             Question                    | // maybe bound in trait object
302             Lifetime(..)                | // lifetime bound in trait object
303             Lt | BinOp(Shl)             | // associated path
304             ModSep                      => true, // global path
305             Interpolated(ref nt) => match nt.0 {
306                 NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true,
307                 _ => false,
308             },
309             _ => false,
310         }
311     }
312
313     /// Returns `true` if the token can appear at the start of a generic bound.
314     pub fn can_begin_bound(&self) -> bool {
315         self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
316         self == &Question || self == &OpenDelim(Paren)
317     }
318
319     /// Returns `true` if the token is any literal
320     pub fn is_lit(&self) -> bool {
321         match *self {
322             Literal(..) => true,
323             _           => false,
324         }
325     }
326
327     /// Returns an identifier if this token is an identifier.
328     pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
329         match *self {
330             Ident(ident, is_raw) => Some((ident, is_raw)),
331             Interpolated(ref nt) => match nt.0 {
332                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
333                 _ => None,
334             },
335             _ => None,
336         }
337     }
338     /// Returns a lifetime identifier if this token is a lifetime.
339     pub fn lifetime(&self) -> Option<ast::Ident> {
340         match *self {
341             Lifetime(ident) => Some(ident),
342             Interpolated(ref nt) => match nt.0 {
343                 NtLifetime(ident) => Some(ident),
344                 _ => None,
345             },
346             _ => None,
347         }
348     }
349     /// Returns `true` if the token is an identifier.
350     pub fn is_ident(&self) -> bool {
351         self.ident().is_some()
352     }
353     /// Returns `true` if the token is a lifetime.
354     pub fn is_lifetime(&self) -> bool {
355         self.lifetime().is_some()
356     }
357
358     /// Returns `true` if the token is a identifier whose name is the given
359     /// string slice.
360     pub fn is_ident_named(&self, name: &str) -> bool {
361         match self.ident() {
362             Some((ident, _)) => ident.name.as_str() == name,
363             None => false
364         }
365     }
366
367     /// Returns `true` if the token is a documentation comment.
368     pub fn is_doc_comment(&self) -> bool {
369         match *self {
370             DocComment(..)   => true,
371             _                => false,
372         }
373     }
374
375     /// Returns `true` if the token is interpolated.
376     pub fn is_interpolated(&self) -> bool {
377         match *self {
378             Interpolated(..) => true,
379             _                => false,
380         }
381     }
382
383     /// Returns `true` if the token is an interpolated path.
384     pub fn is_path(&self) -> bool {
385         if let Interpolated(ref nt) = *self {
386             if let NtPath(..) = nt.0 {
387                 return true;
388             }
389         }
390         false
391     }
392
393     /// Returns `true` if the token is either the `mut` or `const` keyword.
394     pub fn is_mutability(&self) -> bool {
395         self.is_keyword(keywords::Mut) ||
396         self.is_keyword(keywords::Const)
397     }
398
399     pub fn is_qpath_start(&self) -> bool {
400         self == &Lt || self == &BinOp(Shl)
401     }
402
403     pub fn is_path_start(&self) -> bool {
404         self == &ModSep || self.is_qpath_start() || self.is_path() ||
405         self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident()
406     }
407
408     /// Returns `true` if the token is a given keyword, `kw`.
409     pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
410         self.ident().map(|(ident, is_raw)| ident.name == kw.name() && !is_raw).unwrap_or(false)
411     }
412
413     pub fn is_path_segment_keyword(&self) -> bool {
414         match self.ident() {
415             Some((id, false)) => is_path_segment_keyword(id),
416             _ => false,
417         }
418     }
419
420     // Returns true for reserved identifiers used internally for elided lifetimes,
421     // unnamed method parameters, crate root module, error recovery etc.
422     pub fn is_special_ident(&self) -> bool {
423         match self.ident() {
424             Some((id, false)) => is_special_ident(id),
425             _ => false,
426         }
427     }
428
429     /// Returns `true` if the token is a keyword used in the language.
430     pub fn is_used_keyword(&self) -> bool {
431         match self.ident() {
432             Some((id, false)) => is_used_keyword(id),
433             _ => false,
434         }
435     }
436
437     /// Returns `true` if the token is a keyword reserved for possible future use.
438     pub fn is_unused_keyword(&self) -> bool {
439         match self.ident() {
440             Some((id, false)) => is_unused_keyword(id),
441             _ => false,
442         }
443     }
444
445     /// Returns `true` if the token is either a special identifier or a keyword.
446     pub fn is_reserved_ident(&self) -> bool {
447         match self.ident() {
448             Some((id, false)) => is_reserved_ident(id),
449             _ => false,
450         }
451     }
452
453     pub fn glue(self, joint: Token) -> Option<Token> {
454         Some(match self {
455             Eq => match joint {
456                 Eq => EqEq,
457                 Gt => FatArrow,
458                 _ => return None,
459             },
460             Lt => match joint {
461                 Eq => Le,
462                 Lt => BinOp(Shl),
463                 Le => BinOpEq(Shl),
464                 BinOp(Minus) => LArrow,
465                 _ => return None,
466             },
467             Gt => match joint {
468                 Eq => Ge,
469                 Gt => BinOp(Shr),
470                 Ge => BinOpEq(Shr),
471                 _ => return None,
472             },
473             Not => match joint {
474                 Eq => Ne,
475                 _ => return None,
476             },
477             BinOp(op) => match joint {
478                 Eq => BinOpEq(op),
479                 BinOp(And) if op == And => AndAnd,
480                 BinOp(Or) if op == Or => OrOr,
481                 Gt if op == Minus => RArrow,
482                 _ => return None,
483             },
484             Dot => match joint {
485                 Dot => DotDot,
486                 DotDot => DotDotDot,
487                 DotEq => DotDotEq,
488                 _ => return None,
489             },
490             DotDot => match joint {
491                 Dot => DotDotDot,
492                 Eq => DotDotEq,
493                 _ => return None,
494             },
495             Colon => match joint {
496                 Colon => ModSep,
497                 _ => return None,
498             },
499
500             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
501             DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
502             Question | OpenDelim(..) | CloseDelim(..) => return None,
503
504             Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
505             Whitespace | Comment | Shebang(..) | Eof => return None,
506         })
507     }
508
509     /// Returns tokens that are likely to be typed accidentally instead of the current token.
510     /// Enables better error recovery when the wrong token is found.
511     pub fn similar_tokens(&self) -> Option<Vec<Token>> {
512         match *self {
513             Comma => Some(vec![Dot, Lt]),
514             Semi => Some(vec![Colon]),
515             _ => None
516         }
517     }
518
519     pub fn interpolated_to_tokenstream(&self, sess: &ParseSess, span: Span)
520         -> TokenStream
521     {
522         let nt = match *self {
523             Token::Interpolated(ref nt) => nt,
524             _ => panic!("only works on interpolated tokens"),
525         };
526
527         // An `Interpolated` token means that we have a `Nonterminal`
528         // which is often a parsed AST item. At this point we now need
529         // to convert the parsed AST to an actual token stream, e.g.
530         // un-parse it basically.
531         //
532         // Unfortunately there's not really a great way to do that in a
533         // guaranteed lossless fashion right now. The fallback here is
534         // to just stringify the AST node and reparse it, but this loses
535         // all span information.
536         //
537         // As a result, some AST nodes are annotated with the token
538         // stream they came from. Here we attempt to extract these
539         // lossless token streams before we fall back to the
540         // stringification.
541         let mut tokens = None;
542
543         match nt.0 {
544             Nonterminal::NtItem(ref item) => {
545                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
546             }
547             Nonterminal::NtTraitItem(ref item) => {
548                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
549             }
550             Nonterminal::NtImplItem(ref item) => {
551                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
552             }
553             Nonterminal::NtIdent(ident, is_raw) => {
554                 let token = Token::Ident(ident, is_raw);
555                 tokens = Some(TokenTree::Token(ident.span, token).into());
556             }
557             Nonterminal::NtLifetime(ident) => {
558                 let token = Token::Lifetime(ident);
559                 tokens = Some(TokenTree::Token(ident.span, token).into());
560             }
561             Nonterminal::NtTT(ref tt) => {
562                 tokens = Some(tt.clone().into());
563             }
564             _ => {}
565         }
566
567         let tokens_for_real = nt.1.force(|| {
568             // FIXME(#43081): Avoid this pretty-print + reparse hack
569             let source = pprust::token_to_string(self);
570             parse_stream_from_source_str(FileName::MacroExpansion, source, sess, Some(span))
571         });
572
573         // During early phases of the compiler the AST could get modified
574         // directly (e.g. attributes added or removed) and the internal cache
575         // of tokens my not be invalidated or updated. Consequently if the
576         // "lossless" token stream disagrees with our actual stringification
577         // (which has historically been much more battle-tested) then we go
578         // with the lossy stream anyway (losing span information).
579         //
580         // Note that the comparison isn't `==` here to avoid comparing spans,
581         // but it *also* is a "probable" equality which is a pretty weird
582         // definition. We mostly want to catch actual changes to the AST
583         // like a `#[cfg]` being processed or some weird `macro_rules!`
584         // expansion.
585         //
586         // What we *don't* want to catch is the fact that a user-defined
587         // literal like `0xf` is stringified as `15`, causing the cached token
588         // stream to not be literal `==` token-wise (ignoring spans) to the
589         // token stream we got from stringification.
590         //
591         // Instead the "probably equal" check here is "does each token
592         // recursively have the same discriminant?" We basically don't look at
593         // the token values here and assume that such fine grained modifications
594         // of token streams doesn't happen.
595         if let Some(tokens) = tokens {
596             if tokens.probably_equal_for_proc_macro(&tokens_for_real) {
597                 return tokens
598             }
599         }
600         return tokens_for_real
601     }
602
603     // See comments in `interpolated_to_tokenstream` for why we care about
604     // *probably* equal here rather than actual equality
605     pub fn probably_equal_for_proc_macro(&self, other: &Token) -> bool {
606         if mem::discriminant(self) != mem::discriminant(other) {
607             return false
608         }
609         match (self, other) {
610             (&Eq, &Eq) |
611             (&Lt, &Lt) |
612             (&Le, &Le) |
613             (&EqEq, &EqEq) |
614             (&Ne, &Ne) |
615             (&Ge, &Ge) |
616             (&Gt, &Gt) |
617             (&AndAnd, &AndAnd) |
618             (&OrOr, &OrOr) |
619             (&Not, &Not) |
620             (&Tilde, &Tilde) |
621             (&At, &At) |
622             (&Dot, &Dot) |
623             (&DotDot, &DotDot) |
624             (&DotDotDot, &DotDotDot) |
625             (&DotDotEq, &DotDotEq) |
626             (&DotEq, &DotEq) |
627             (&Comma, &Comma) |
628             (&Semi, &Semi) |
629             (&Colon, &Colon) |
630             (&ModSep, &ModSep) |
631             (&RArrow, &RArrow) |
632             (&LArrow, &LArrow) |
633             (&FatArrow, &FatArrow) |
634             (&Pound, &Pound) |
635             (&Dollar, &Dollar) |
636             (&Question, &Question) |
637             (&Whitespace, &Whitespace) |
638             (&Comment, &Comment) |
639             (&Eof, &Eof) => true,
640
641             (&BinOp(a), &BinOp(b)) |
642             (&BinOpEq(a), &BinOpEq(b)) => a == b,
643
644             (&OpenDelim(a), &OpenDelim(b)) |
645             (&CloseDelim(a), &CloseDelim(b)) => a == b,
646
647             (&DocComment(a), &DocComment(b)) |
648             (&Shebang(a), &Shebang(b)) => a == b,
649
650             (&Lifetime(a), &Lifetime(b)) => a.name == b.name,
651             (&Ident(a, b), &Ident(c, d)) => a.name == c.name && b == d,
652
653             (&Literal(ref a, b), &Literal(ref c, d)) => {
654                 b == d && a.probably_equal_for_proc_macro(c)
655             }
656
657             (&Interpolated(_), &Interpolated(_)) => false,
658
659             _ => panic!("forgot to add a token?"),
660         }
661     }
662 }
663
664 #[derive(Clone, RustcEncodable, RustcDecodable, Eq, Hash)]
665 /// For interpolation during macro expansion.
666 pub enum Nonterminal {
667     NtItem(P<ast::Item>),
668     NtBlock(P<ast::Block>),
669     NtStmt(ast::Stmt),
670     NtPat(P<ast::Pat>),
671     NtExpr(P<ast::Expr>),
672     NtTy(P<ast::Ty>),
673     NtIdent(ast::Ident, /* is_raw */ bool),
674     NtLifetime(ast::Ident),
675     /// Stuff inside brackets for attributes
676     NtMeta(ast::MetaItem),
677     NtPath(ast::Path),
678     NtVis(ast::Visibility),
679     NtTT(TokenTree),
680     // These are not exposed to macros, but are used by quasiquote.
681     NtArm(ast::Arm),
682     NtImplItem(ast::ImplItem),
683     NtTraitItem(ast::TraitItem),
684     NtForeignItem(ast::ForeignItem),
685     NtGenerics(ast::Generics),
686     NtWhereClause(ast::WhereClause),
687     NtArg(ast::Arg),
688 }
689
690 impl PartialEq for Nonterminal {
691     fn eq(&self, rhs: &Self) -> bool {
692         match (self, rhs) {
693             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) =>
694                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs,
695             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
696             (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
697             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
698             // correctly based on data from AST. This will prevent them from matching each other
699             // in macros. The comparison will become possible only when each nonterminal has an
700             // attached token stream from which it was parsed.
701             _ => false,
702         }
703     }
704 }
705
706 impl fmt::Debug for Nonterminal {
707     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
708         match *self {
709             NtItem(..) => f.pad("NtItem(..)"),
710             NtBlock(..) => f.pad("NtBlock(..)"),
711             NtStmt(..) => f.pad("NtStmt(..)"),
712             NtPat(..) => f.pad("NtPat(..)"),
713             NtExpr(..) => f.pad("NtExpr(..)"),
714             NtTy(..) => f.pad("NtTy(..)"),
715             NtIdent(..) => f.pad("NtIdent(..)"),
716             NtMeta(..) => f.pad("NtMeta(..)"),
717             NtPath(..) => f.pad("NtPath(..)"),
718             NtTT(..) => f.pad("NtTT(..)"),
719             NtArm(..) => f.pad("NtArm(..)"),
720             NtImplItem(..) => f.pad("NtImplItem(..)"),
721             NtTraitItem(..) => f.pad("NtTraitItem(..)"),
722             NtForeignItem(..) => f.pad("NtForeignItem(..)"),
723             NtGenerics(..) => f.pad("NtGenerics(..)"),
724             NtWhereClause(..) => f.pad("NtWhereClause(..)"),
725             NtArg(..) => f.pad("NtArg(..)"),
726             NtVis(..) => f.pad("NtVis(..)"),
727             NtLifetime(..) => f.pad("NtLifetime(..)"),
728         }
729     }
730 }
731
732 pub fn is_op(tok: &Token) -> bool {
733     match *tok {
734         OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) |
735         Ident(..) | Lifetime(..) | Interpolated(..) |
736         Whitespace | Comment | Shebang(..) | Eof => false,
737         _ => true,
738     }
739 }
740
741 #[derive(Clone)]
742 pub struct LazyTokenStream(Lock<Option<TokenStream>>);
743
744 impl cmp::Eq for LazyTokenStream {}
745 impl PartialEq for LazyTokenStream {
746     fn eq(&self, _other: &LazyTokenStream) -> bool {
747         true
748     }
749 }
750
751 impl fmt::Debug for LazyTokenStream {
752     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
753         fmt::Debug::fmt(&self.clone().0.into_inner(), f)
754     }
755 }
756
757 impl LazyTokenStream {
758     pub fn new() -> Self {
759         LazyTokenStream(Lock::new(None))
760     }
761
762     pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream {
763         let mut opt_stream = self.0.lock();
764         if opt_stream.is_none() {
765             *opt_stream = Some(f());
766         }
767         opt_stream.clone().unwrap()
768     }
769 }
770
771 impl Encodable for LazyTokenStream {
772     fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
773         Ok(())
774     }
775 }
776
777 impl Decodable for LazyTokenStream {
778     fn decode<D: Decoder>(_: &mut D) -> Result<LazyTokenStream, D::Error> {
779         Ok(LazyTokenStream::new())
780     }
781 }
782
783 impl ::std::hash::Hash for LazyTokenStream {
784     fn hash<H: ::std::hash::Hasher>(&self, _hasher: &mut H) {}
785 }
786
787 fn prepend_attrs(sess: &ParseSess,
788                  attrs: &[ast::Attribute],
789                  tokens: Option<&tokenstream::TokenStream>,
790                  span: syntax_pos::Span)
791     -> Option<tokenstream::TokenStream>
792 {
793     let tokens = tokens?;
794     if attrs.len() == 0 {
795         return Some(tokens.clone())
796     }
797     let mut builder = tokenstream::TokenStreamBuilder::new();
798     for attr in attrs {
799         assert_eq!(attr.style, ast::AttrStyle::Outer,
800                    "inner attributes should prevent cached tokens from existing");
801         // FIXME: Avoid this pretty-print + reparse hack as bove
802         let name = FileName::MacroExpansion;
803         let source = pprust::attr_to_string(attr);
804         let stream = parse_stream_from_source_str(name, source, sess, Some(span));
805         builder.push(stream);
806     }
807     builder.push(tokens.clone());
808     Some(builder.build())
809 }