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