]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/token.rs
Make lifetime nonterminals closer to identifier nonterminals
[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::cell::Cell;
29 use std::{cmp, fmt};
30 use rustc_data_structures::sync::Lrc;
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, usize), /* raw str delimited by n hash symbols */
77     ByteStr(ast::Name),
78     ByteStrRaw(ast::Name, usize), /* 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
94 fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
95     let ident_token: Token = Ident(ident, is_raw);
96
97     !ident_token.is_reserved_ident() ||
98     ident_token.is_path_segment_keyword() ||
99     [
100         keywords::Do.name(),
101         keywords::Box.name(),
102         keywords::Break.name(),
103         keywords::Continue.name(),
104         keywords::False.name(),
105         keywords::For.name(),
106         keywords::If.name(),
107         keywords::Loop.name(),
108         keywords::Match.name(),
109         keywords::Move.name(),
110         keywords::Return.name(),
111         keywords::True.name(),
112         keywords::Unsafe.name(),
113         keywords::While.name(),
114         keywords::Yield.name(),
115         keywords::Static.name(),
116     ].contains(&ident.name)
117 }
118
119 fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
120     let ident_token: Token = Ident(ident, is_raw);
121
122     !ident_token.is_reserved_ident() ||
123     ident_token.is_path_segment_keyword() ||
124     [
125         keywords::Underscore.name(),
126         keywords::For.name(),
127         keywords::Impl.name(),
128         keywords::Fn.name(),
129         keywords::Unsafe.name(),
130         keywords::Extern.name(),
131         keywords::Typeof.name(),
132     ].contains(&ident.name)
133 }
134
135 pub fn is_path_segment_keyword(id: ast::Ident) -> bool {
136     id.name == keywords::Super.name() ||
137     id.name == keywords::SelfValue.name() ||
138     id.name == keywords::SelfType.name() ||
139     id.name == keywords::Extern.name() ||
140     id.name == keywords::Crate.name() ||
141     id.name == keywords::CrateRoot.name() ||
142     id.name == keywords::DollarCrate.name()
143 }
144
145 // We see this identifier in a normal identifier position, like variable name or a type.
146 // How was it written originally? Did it use the raw form? Let's try to guess.
147 pub fn is_raw_guess(ident: ast::Ident) -> bool {
148     ident.name != keywords::Invalid.name() &&
149     is_reserved_ident(ident) && !is_path_segment_keyword(ident)
150 }
151
152 // Returns true for reserved identifiers used internally for elided lifetimes,
153 // unnamed method parameters, crate root module, error recovery etc.
154 pub fn is_special_ident(id: ast::Ident) -> bool {
155     id.name <= keywords::Underscore.name()
156 }
157
158 /// Returns `true` if the token is a keyword used in the language.
159 pub fn is_used_keyword(id: ast::Ident) -> bool {
160     id.name >= keywords::As.name() && id.name <= keywords::While.name()
161 }
162
163 /// Returns `true` if the token is a keyword reserved for possible future use.
164 pub fn is_unused_keyword(id: ast::Ident) -> bool {
165     id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name()
166 }
167
168 /// Returns `true` if the token is either a special identifier or a keyword.
169 pub fn is_reserved_ident(id: ast::Ident) -> bool {
170     is_special_ident(id) || is_used_keyword(id) || is_unused_keyword(id)
171 }
172
173 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
174 pub enum Token {
175     /* Expression-operator symbols. */
176     Eq,
177     Lt,
178     Le,
179     EqEq,
180     Ne,
181     Ge,
182     Gt,
183     AndAnd,
184     OrOr,
185     Not,
186     Tilde,
187     BinOp(BinOpToken),
188     BinOpEq(BinOpToken),
189
190     /* Structural symbols */
191     At,
192     Dot,
193     DotDot,
194     DotDotDot,
195     DotDotEq,
196     DotEq, // HACK(durka42) never produced by the parser, only used for libproc_macro
197     Comma,
198     Semi,
199     Colon,
200     ModSep,
201     RArrow,
202     LArrow,
203     FatArrow,
204     Pound,
205     Dollar,
206     Question,
207     /// An opening delimiter, eg. `{`
208     OpenDelim(DelimToken),
209     /// A closing delimiter, eg. `}`
210     CloseDelim(DelimToken),
211
212     /* Literals */
213     Literal(Lit, Option<ast::Name>),
214
215     /* Name components */
216     Ident(ast::Ident, /* is_raw */ bool),
217     Lifetime(ast::Ident),
218
219     // The `LazyTokenStream` is a pure function of the `Nonterminal`,
220     // and so the `LazyTokenStream` can be ignored by Eq, Hash, etc.
221     Interpolated(Lrc<(Nonterminal, LazyTokenStream)>),
222     // Can be expanded into several tokens.
223     /// Doc comment
224     DocComment(ast::Name),
225
226     // Junk. These carry no data because we don't really care about the data
227     // they *would* carry, and don't really want to allocate a new ident for
228     // them. Instead, users could extract that from the associated span.
229
230     /// Whitespace
231     Whitespace,
232     /// Comment
233     Comment,
234     Shebang(ast::Name),
235
236     Eof,
237 }
238
239 impl Token {
240     pub fn interpolated(nt: Nonterminal) -> Token {
241         Token::Interpolated(Lrc::new((nt, LazyTokenStream::new())))
242     }
243
244     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
245     pub fn from_ast_ident(ident: ast::Ident) -> Token {
246         Ident(ident, is_raw_guess(ident))
247     }
248
249     /// Returns `true` if the token starts with '>'.
250     pub fn is_like_gt(&self) -> bool {
251         match *self {
252             BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
253             _ => false,
254         }
255     }
256
257     /// Returns `true` if the token can appear at the start of an expression.
258     pub fn can_begin_expr(&self) -> bool {
259         match *self {
260             Ident(ident, is_raw)              =>
261                 ident_can_begin_expr(ident, is_raw), // value name or keyword
262             OpenDelim(..)                     | // tuple, array or block
263             Literal(..)                       | // literal
264             Not                               | // operator not
265             BinOp(Minus)                      | // unary minus
266             BinOp(Star)                       | // dereference
267             BinOp(Or) | OrOr                  | // closure
268             BinOp(And)                        | // reference
269             AndAnd                            | // double reference
270             // DotDotDot is no longer supported, but we need some way to display the error
271             DotDot | DotDotDot | DotDotEq     | // range notation
272             Lt | BinOp(Shl)                   | // associated path
273             ModSep                            | // global path
274             Pound                             => true, // expression attributes
275             Interpolated(ref nt) => match nt.0 {
276                 NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true,
277                 _ => false,
278             },
279             _ => false,
280         }
281     }
282
283     /// Returns `true` if the token can appear at the start of a type.
284     pub fn can_begin_type(&self) -> bool {
285         match *self {
286             Ident(ident, is_raw)        =>
287                 ident_can_begin_type(ident, is_raw), // type name or keyword
288             OpenDelim(Paren)            | // tuple
289             OpenDelim(Bracket)          | // array
290             Not                         | // never
291             BinOp(Star)                 | // raw pointer
292             BinOp(And)                  | // reference
293             AndAnd                      | // double reference
294             Question                    | // maybe bound in trait object
295             Lifetime(..)                | // lifetime bound in trait object
296             Lt | BinOp(Shl)             | // associated path
297             ModSep                      => true, // global path
298             Interpolated(ref nt) => match nt.0 {
299                 NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true,
300                 _ => false,
301             },
302             _ => false,
303         }
304     }
305
306     /// Returns `true` if the token can appear at the start of a generic bound.
307     pub fn can_begin_bound(&self) -> bool {
308         self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
309         self == &Question || self == &OpenDelim(Paren)
310     }
311
312     /// Returns `true` if the token is any literal
313     pub fn is_lit(&self) -> bool {
314         match *self {
315             Literal(..) => true,
316             _           => false,
317         }
318     }
319
320     /// Returns an identifier if this token is an identifier.
321     pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
322         match *self {
323             Ident(ident, is_raw) => Some((ident, is_raw)),
324             Interpolated(ref nt) => match nt.0 {
325                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
326                 _ => None,
327             },
328             _ => None,
329         }
330     }
331     /// Returns a lifetime identifier if this token is a lifetime.
332     pub fn lifetime(&self) -> Option<ast::Ident> {
333         match *self {
334             Lifetime(ident) => Some(ident),
335             Interpolated(ref nt) => match nt.0 {
336                 NtLifetime(ident) => Some(ident),
337                 _ => None,
338             },
339             _ => None,
340         }
341     }
342     /// Returns `true` if the token is an identifier.
343     pub fn is_ident(&self) -> bool {
344         self.ident().is_some()
345     }
346     /// Returns `true` if the token is a lifetime.
347     pub fn is_lifetime(&self) -> bool {
348         self.lifetime().is_some()
349     }
350
351     /// Returns `true` if the token is a documentation comment.
352     pub fn is_doc_comment(&self) -> bool {
353         match *self {
354             DocComment(..)   => true,
355             _                => false,
356         }
357     }
358
359     /// Returns `true` if the token is interpolated.
360     pub fn is_interpolated(&self) -> bool {
361         match *self {
362             Interpolated(..) => true,
363             _                => false,
364         }
365     }
366
367     /// Returns `true` if the token is an interpolated path.
368     pub fn is_path(&self) -> bool {
369         if let Interpolated(ref nt) = *self {
370             if let NtPath(..) = nt.0 {
371                 return true;
372             }
373         }
374         false
375     }
376
377     /// Returns `true` if the token is either the `mut` or `const` keyword.
378     pub fn is_mutability(&self) -> bool {
379         self.is_keyword(keywords::Mut) ||
380         self.is_keyword(keywords::Const)
381     }
382
383     pub fn is_qpath_start(&self) -> bool {
384         self == &Lt || self == &BinOp(Shl)
385     }
386
387     pub fn is_path_start(&self) -> bool {
388         self == &ModSep || self.is_qpath_start() || self.is_path() ||
389         self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident()
390     }
391
392     /// Returns `true` if the token is a given keyword, `kw`.
393     pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
394         self.ident().map(|(ident, is_raw)| ident.name == kw.name() && !is_raw).unwrap_or(false)
395     }
396
397     pub fn is_path_segment_keyword(&self) -> bool {
398         match self.ident() {
399             Some((id, false)) => is_path_segment_keyword(id),
400             _ => false,
401         }
402     }
403
404     // Returns true for reserved identifiers used internally for elided lifetimes,
405     // unnamed method parameters, crate root module, error recovery etc.
406     pub fn is_special_ident(&self) -> bool {
407         match self.ident() {
408             Some((id, false)) => is_special_ident(id),
409             _ => false,
410         }
411     }
412
413     /// Returns `true` if the token is a keyword used in the language.
414     pub fn is_used_keyword(&self) -> bool {
415         match self.ident() {
416             Some((id, false)) => is_used_keyword(id),
417             _ => false,
418         }
419     }
420
421     /// Returns `true` if the token is a keyword reserved for possible future use.
422     pub fn is_unused_keyword(&self) -> bool {
423         match self.ident() {
424             Some((id, false)) => is_unused_keyword(id),
425             _ => false,
426         }
427     }
428
429     /// Returns `true` if the token is either a special identifier or a keyword.
430     pub fn is_reserved_ident(&self) -> bool {
431         match self.ident() {
432             Some((id, false)) => is_reserved_ident(id),
433             _ => false,
434         }
435     }
436
437     pub fn glue(self, joint: Token) -> Option<Token> {
438         Some(match self {
439             Eq => match joint {
440                 Eq => EqEq,
441                 Gt => FatArrow,
442                 _ => return None,
443             },
444             Lt => match joint {
445                 Eq => Le,
446                 Lt => BinOp(Shl),
447                 Le => BinOpEq(Shl),
448                 BinOp(Minus) => LArrow,
449                 _ => return None,
450             },
451             Gt => match joint {
452                 Eq => Ge,
453                 Gt => BinOp(Shr),
454                 Ge => BinOpEq(Shr),
455                 _ => return None,
456             },
457             Not => match joint {
458                 Eq => Ne,
459                 _ => return None,
460             },
461             BinOp(op) => match joint {
462                 Eq => BinOpEq(op),
463                 BinOp(And) if op == And => AndAnd,
464                 BinOp(Or) if op == Or => OrOr,
465                 Gt if op == Minus => RArrow,
466                 _ => return None,
467             },
468             Dot => match joint {
469                 Dot => DotDot,
470                 DotDot => DotDotDot,
471                 DotEq => DotDotEq,
472                 _ => return None,
473             },
474             DotDot => match joint {
475                 Dot => DotDotDot,
476                 Eq => DotDotEq,
477                 _ => return None,
478             },
479             Colon => match joint {
480                 Colon => ModSep,
481                 _ => return None,
482             },
483
484             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
485             DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
486             Question | OpenDelim(..) | CloseDelim(..) => return None,
487
488             Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
489             Whitespace | Comment | Shebang(..) | Eof => return None,
490         })
491     }
492
493     /// Returns tokens that are likely to be typed accidentally instead of the current token.
494     /// Enables better error recovery when the wrong token is found.
495     pub fn similar_tokens(&self) -> Option<Vec<Token>> {
496         match *self {
497             Comma => Some(vec![Dot, Lt]),
498             Semi => Some(vec![Colon]),
499             _ => None
500         }
501     }
502
503     pub fn interpolated_to_tokenstream(&self, sess: &ParseSess, span: Span)
504         -> TokenStream
505     {
506         let nt = match *self {
507             Token::Interpolated(ref nt) => nt,
508             _ => panic!("only works on interpolated tokens"),
509         };
510
511         // An `Interpolated` token means that we have a `Nonterminal`
512         // which is often a parsed AST item. At this point we now need
513         // to convert the parsed AST to an actual token stream, e.g.
514         // un-parse it basically.
515         //
516         // Unfortunately there's not really a great way to do that in a
517         // guaranteed lossless fashion right now. The fallback here is
518         // to just stringify the AST node and reparse it, but this loses
519         // all span information.
520         //
521         // As a result, some AST nodes are annotated with the token
522         // stream they came from. Attempt to extract these lossless
523         // token streams before we fall back to the stringification.
524         let mut tokens = None;
525
526         match nt.0 {
527             Nonterminal::NtItem(ref item) => {
528                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
529             }
530             Nonterminal::NtTraitItem(ref item) => {
531                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
532             }
533             Nonterminal::NtImplItem(ref item) => {
534                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
535             }
536             Nonterminal::NtIdent(ident, is_raw) => {
537                 let token = Token::Ident(ident, is_raw);
538                 tokens = Some(TokenTree::Token(ident.span, token).into());
539             }
540             Nonterminal::NtLifetime(ident) => {
541                 let token = Token::Lifetime(ident);
542                 tokens = Some(TokenTree::Token(ident.span, token).into());
543             }
544             Nonterminal::NtTT(ref tt) => {
545                 tokens = Some(tt.clone().into());
546             }
547             _ => {}
548         }
549
550         tokens.unwrap_or_else(|| {
551             nt.1.force(|| {
552                 // FIXME(jseyfried): Avoid this pretty-print + reparse hack
553                 let source = pprust::token_to_string(self);
554                 parse_stream_from_source_str(FileName::MacroExpansion, source, sess, Some(span))
555             })
556         })
557     }
558 }
559
560 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
561 /// For interpolation during macro expansion.
562 pub enum Nonterminal {
563     NtItem(P<ast::Item>),
564     NtBlock(P<ast::Block>),
565     NtStmt(ast::Stmt),
566     NtPat(P<ast::Pat>),
567     NtExpr(P<ast::Expr>),
568     NtTy(P<ast::Ty>),
569     NtIdent(ast::Ident, /* is_raw */ bool),
570     NtLifetime(ast::Ident),
571     /// Stuff inside brackets for attributes
572     NtMeta(ast::MetaItem),
573     NtPath(ast::Path),
574     NtVis(ast::Visibility),
575     NtTT(TokenTree),
576     // These are not exposed to macros, but are used by quasiquote.
577     NtArm(ast::Arm),
578     NtImplItem(ast::ImplItem),
579     NtTraitItem(ast::TraitItem),
580     NtForeignItem(ast::ForeignItem),
581     NtGenerics(ast::Generics),
582     NtWhereClause(ast::WhereClause),
583     NtArg(ast::Arg),
584 }
585
586 impl fmt::Debug for Nonterminal {
587     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
588         match *self {
589             NtItem(..) => f.pad("NtItem(..)"),
590             NtBlock(..) => f.pad("NtBlock(..)"),
591             NtStmt(..) => f.pad("NtStmt(..)"),
592             NtPat(..) => f.pad("NtPat(..)"),
593             NtExpr(..) => f.pad("NtExpr(..)"),
594             NtTy(..) => f.pad("NtTy(..)"),
595             NtIdent(..) => f.pad("NtIdent(..)"),
596             NtMeta(..) => f.pad("NtMeta(..)"),
597             NtPath(..) => f.pad("NtPath(..)"),
598             NtTT(..) => f.pad("NtTT(..)"),
599             NtArm(..) => f.pad("NtArm(..)"),
600             NtImplItem(..) => f.pad("NtImplItem(..)"),
601             NtTraitItem(..) => f.pad("NtTraitItem(..)"),
602             NtForeignItem(..) => f.pad("NtForeignItem(..)"),
603             NtGenerics(..) => f.pad("NtGenerics(..)"),
604             NtWhereClause(..) => f.pad("NtWhereClause(..)"),
605             NtArg(..) => f.pad("NtArg(..)"),
606             NtVis(..) => f.pad("NtVis(..)"),
607             NtLifetime(..) => f.pad("NtLifetime(..)"),
608         }
609     }
610 }
611
612 pub fn is_op(tok: &Token) -> bool {
613     match *tok {
614         OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) |
615         Ident(..) | Lifetime(..) | Interpolated(..) |
616         Whitespace | Comment | Shebang(..) | Eof => false,
617         _ => true,
618     }
619 }
620
621 pub struct LazyTokenStream(Cell<Option<TokenStream>>);
622
623 impl Clone for LazyTokenStream {
624     fn clone(&self) -> Self {
625         let opt_stream = self.0.take();
626         self.0.set(opt_stream.clone());
627         LazyTokenStream(Cell::new(opt_stream))
628     }
629 }
630
631 impl cmp::Eq for LazyTokenStream {}
632 impl PartialEq for LazyTokenStream {
633     fn eq(&self, _other: &LazyTokenStream) -> bool {
634         true
635     }
636 }
637
638 impl fmt::Debug for LazyTokenStream {
639     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
640         fmt::Debug::fmt(&self.clone().0.into_inner(), f)
641     }
642 }
643
644 impl LazyTokenStream {
645     pub fn new() -> Self {
646         LazyTokenStream(Cell::new(None))
647     }
648
649     pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream {
650         let mut opt_stream = self.0.take();
651         if opt_stream.is_none() {
652             opt_stream = Some(f());
653         }
654         self.0.set(opt_stream.clone());
655         opt_stream.clone().unwrap()
656     }
657 }
658
659 impl Encodable for LazyTokenStream {
660     fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
661         Ok(())
662     }
663 }
664
665 impl Decodable for LazyTokenStream {
666     fn decode<D: Decoder>(_: &mut D) -> Result<LazyTokenStream, D::Error> {
667         Ok(LazyTokenStream::new())
668     }
669 }
670
671 impl ::std::hash::Hash for LazyTokenStream {
672     fn hash<H: ::std::hash::Hasher>(&self, _hasher: &mut H) {}
673 }
674
675 fn prepend_attrs(sess: &ParseSess,
676                  attrs: &[ast::Attribute],
677                  tokens: Option<&tokenstream::TokenStream>,
678                  span: syntax_pos::Span)
679     -> Option<tokenstream::TokenStream>
680 {
681     let tokens = tokens?;
682     if attrs.len() == 0 {
683         return Some(tokens.clone())
684     }
685     let mut builder = tokenstream::TokenStreamBuilder::new();
686     for attr in attrs {
687         assert_eq!(attr.style, ast::AttrStyle::Outer,
688                    "inner attributes should prevent cached tokens from existing");
689         // FIXME: Avoid this pretty-print + reparse hack as bove
690         let name = FileName::MacroExpansion;
691         let source = pprust::attr_to_string(attr);
692         let stream = parse_stream_from_source_str(name, source, sess, Some(span));
693         builder.push(stream);
694     }
695     builder.push(tokens.clone());
696     Some(builder.build())
697 }