]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/quote.rs
Rollup merge of #29617 - steveklabnik:gh29591, r=alexcrichton
[rust.git] / src / libsyntax / ext / quote.rs
1 // Copyright 2015 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 use ast::{self, TokenTree};
12 use codemap::Span;
13 use ext::base::ExtCtxt;
14 use ext::base;
15 use ext::build::AstBuilder;
16 use parse::token::*;
17 use parse::token;
18 use ptr::P;
19
20 ///  Quasiquoting works via token trees.
21 ///
22 ///  This is registered as a set of expression syntax extension called quote!
23 ///  that lifts its argument token-tree to an AST representing the
24 ///  construction of the same token tree, with token::SubstNt interpreted
25 ///  as antiquotes (splices).
26
27 pub mod rt {
28     use ast;
29     use codemap::Spanned;
30     use ext::base::ExtCtxt;
31     use parse::{self, token, classify};
32     use ptr::P;
33     use std::rc::Rc;
34
35     use ast::{TokenTree, Expr};
36
37     pub use parse::new_parser_from_tts;
38     pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP};
39
40     pub trait ToTokens {
41         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
42     }
43
44     impl ToTokens for TokenTree {
45         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
46             vec!(self.clone())
47         }
48     }
49
50     impl<T: ToTokens> ToTokens for Vec<T> {
51         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
52             self.iter().flat_map(|t| t.to_tokens(cx)).collect()
53         }
54     }
55
56     impl<T: ToTokens> ToTokens for Spanned<T> {
57         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
58             // FIXME: use the span?
59             self.node.to_tokens(cx)
60         }
61     }
62
63     impl<T: ToTokens> ToTokens for Option<T> {
64         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
65             match self {
66                 &Some(ref t) => t.to_tokens(cx),
67                 &None => Vec::new(),
68             }
69         }
70     }
71
72     impl ToTokens for ast::Ident {
73         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
74             vec![TokenTree::Token(DUMMY_SP, token::Ident(*self, token::Plain))]
75         }
76     }
77
78     impl ToTokens for ast::Path {
79         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
80             vec![TokenTree::Token(DUMMY_SP,
81                                   token::Interpolated(token::NtPath(Box::new(self.clone()))))]
82         }
83     }
84
85     impl ToTokens for ast::Ty {
86         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
87             vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
88         }
89     }
90
91     impl ToTokens for ast::Block {
92         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
93             vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
94         }
95     }
96
97     impl ToTokens for ast::Generics {
98         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
99             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))]
100         }
101     }
102
103     impl ToTokens for ast::WhereClause {
104         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
105             vec![TokenTree::Token(DUMMY_SP,
106                                   token::Interpolated(token::NtWhereClause(self.clone())))]
107         }
108     }
109
110     impl ToTokens for P<ast::Item> {
111         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
112             vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))]
113         }
114     }
115
116     impl ToTokens for P<ast::ImplItem> {
117         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
118             vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
119         }
120     }
121
122     impl ToTokens for P<ast::TraitItem> {
123         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
124             vec![TokenTree::Token(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
125         }
126     }
127
128     impl ToTokens for P<ast::Stmt> {
129         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
130             let mut tts = vec![
131                 TokenTree::Token(self.span, token::Interpolated(token::NtStmt(self.clone())))
132             ];
133
134             // Some statements require a trailing semicolon.
135             if classify::stmt_ends_with_semi(&self.node) {
136                 tts.push(TokenTree::Token(self.span, token::Semi));
137             }
138
139             tts
140         }
141     }
142
143     impl ToTokens for P<ast::Expr> {
144         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
145             vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))]
146         }
147     }
148
149     impl ToTokens for P<ast::Pat> {
150         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
151             vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))]
152         }
153     }
154
155     impl ToTokens for ast::Arm {
156         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
157             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
158         }
159     }
160
161     macro_rules! impl_to_tokens_slice {
162         ($t: ty, $sep: expr) => {
163             impl ToTokens for [$t] {
164                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
165                     let mut v = vec![];
166                     for (i, x) in self.iter().enumerate() {
167                         if i > 0 {
168                             v.push_all(&$sep);
169                         }
170                         v.extend(x.to_tokens(cx));
171                     }
172                     v
173                 }
174             }
175         };
176     }
177
178     impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
179     impl_to_tokens_slice! { P<ast::Item>, [] }
180
181     impl ToTokens for P<ast::MetaItem> {
182         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
183             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
184         }
185     }
186
187     impl ToTokens for ast::Attribute {
188         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
189             let mut r = vec![];
190             // FIXME: The spans could be better
191             r.push(TokenTree::Token(self.span, token::Pound));
192             if self.node.style == ast::AttrStyle::Inner {
193                 r.push(TokenTree::Token(self.span, token::Not));
194             }
195             r.push(TokenTree::Delimited(self.span, Rc::new(ast::Delimited {
196                 delim: token::Bracket,
197                 open_span: self.span,
198                 tts: self.node.value.to_tokens(cx),
199                 close_span: self.span,
200             })));
201             r
202         }
203     }
204
205     impl ToTokens for str {
206         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
207             let lit = ast::LitStr(
208                 token::intern_and_get_ident(self), ast::CookedStr);
209             dummy_spanned(lit).to_tokens(cx)
210         }
211     }
212
213     impl ToTokens for () {
214         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
215             vec![TokenTree::Delimited(DUMMY_SP, Rc::new(ast::Delimited {
216                 delim: token::Paren,
217                 open_span: DUMMY_SP,
218                 tts: vec![],
219                 close_span: DUMMY_SP,
220             }))]
221         }
222     }
223
224     impl ToTokens for ast::Lit {
225         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
226             // FIXME: This is wrong
227             P(ast::Expr {
228                 id: ast::DUMMY_NODE_ID,
229                 node: ast::ExprLit(P(self.clone())),
230                 span: DUMMY_SP,
231             }).to_tokens(cx)
232         }
233     }
234
235     impl ToTokens for bool {
236         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
237             dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
238         }
239     }
240
241     impl ToTokens for char {
242         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
243             dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
244         }
245     }
246
247     macro_rules! impl_to_tokens_int {
248         (signed, $t:ty, $tag:expr) => (
249             impl ToTokens for $t {
250                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
251                     let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
252                                                                           ast::Sign::new(*self)));
253                     dummy_spanned(lit).to_tokens(cx)
254                 }
255             }
256         );
257         (unsigned, $t:ty, $tag:expr) => (
258             impl ToTokens for $t {
259                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
260                     let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
261                     dummy_spanned(lit).to_tokens(cx)
262                 }
263             }
264         );
265     }
266
267     impl_to_tokens_int! { signed, isize, ast::TyIs }
268     impl_to_tokens_int! { signed, i8,  ast::TyI8 }
269     impl_to_tokens_int! { signed, i16, ast::TyI16 }
270     impl_to_tokens_int! { signed, i32, ast::TyI32 }
271     impl_to_tokens_int! { signed, i64, ast::TyI64 }
272
273     impl_to_tokens_int! { unsigned, usize, ast::TyUs }
274     impl_to_tokens_int! { unsigned, u8,   ast::TyU8 }
275     impl_to_tokens_int! { unsigned, u16,  ast::TyU16 }
276     impl_to_tokens_int! { unsigned, u32,  ast::TyU32 }
277     impl_to_tokens_int! { unsigned, u64,  ast::TyU64 }
278
279     pub trait ExtParseUtils {
280         fn parse_item(&self, s: String) -> P<ast::Item>;
281         fn parse_expr(&self, s: String) -> P<ast::Expr>;
282         fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
283         fn parse_tts(&self, s: String) -> Vec<TokenTree>;
284     }
285
286     impl<'a> ExtParseUtils for ExtCtxt<'a> {
287
288         fn parse_item(&self, s: String) -> P<ast::Item> {
289             parse::parse_item_from_source_str(
290                 "<quote expansion>".to_string(),
291                 s,
292                 self.cfg(),
293                 self.parse_sess()).expect("parse error")
294         }
295
296         fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
297             parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
298                                               s,
299                                               self.cfg(),
300                                               self.parse_sess()).expect("parse error")
301         }
302
303         fn parse_expr(&self, s: String) -> P<ast::Expr> {
304             parse::parse_expr_from_source_str("<quote expansion>".to_string(),
305                                               s,
306                                               self.cfg(),
307                                               self.parse_sess())
308         }
309
310         fn parse_tts(&self, s: String) -> Vec<TokenTree> {
311             parse::parse_tts_from_source_str("<quote expansion>".to_string(),
312                                              s,
313                                              self.cfg(),
314                                              self.parse_sess())
315         }
316     }
317 }
318
319 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
320                                 sp: Span,
321                                 tts: &[TokenTree])
322                                 -> Box<base::MacResult+'cx> {
323     let (cx_expr, expr) = expand_tts(cx, sp, tts);
324     let expanded = expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]);
325     base::MacEager::expr(expanded)
326 }
327
328 pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
329                               sp: Span,
330                               tts: &[TokenTree])
331                               -> Box<base::MacResult+'cx> {
332     let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec!(), tts);
333     base::MacEager::expr(expanded)
334 }
335
336 pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt,
337                               sp: Span,
338                               tts: &[TokenTree])
339                               -> Box<base::MacResult+'cx> {
340     let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec!(), tts);
341     base::MacEager::expr(expanded)
342 }
343
344 pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
345                              sp: Span,
346                              tts: &[TokenTree])
347                              -> Box<base::MacResult+'cx> {
348     let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec!(), tts);
349     base::MacEager::expr(expanded)
350 }
351
352 pub fn expand_quote_arm(cx: &mut ExtCtxt,
353                         sp: Span,
354                         tts: &[TokenTree])
355                         -> Box<base::MacResult+'static> {
356     let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec!(), tts);
357     base::MacEager::expr(expanded)
358 }
359
360 pub fn expand_quote_ty(cx: &mut ExtCtxt,
361                        sp: Span,
362                        tts: &[TokenTree])
363                        -> Box<base::MacResult+'static> {
364     let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec!(), tts);
365     base::MacEager::expr(expanded)
366 }
367
368 pub fn expand_quote_stmt(cx: &mut ExtCtxt,
369                          sp: Span,
370                          tts: &[TokenTree])
371                          -> Box<base::MacResult+'static> {
372     let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec!(), tts);
373     base::MacEager::expr(expanded)
374 }
375
376 pub fn expand_quote_attr(cx: &mut ExtCtxt,
377                          sp: Span,
378                          tts: &[TokenTree])
379                          -> Box<base::MacResult+'static> {
380     let expanded = expand_parse_call(cx, sp, "parse_attribute_panic",
381                                     vec!(cx.expr_bool(sp, true)), tts);
382
383     base::MacEager::expr(expanded)
384 }
385
386 pub fn expand_quote_matcher(cx: &mut ExtCtxt,
387                             sp: Span,
388                             tts: &[TokenTree])
389                             -> Box<base::MacResult+'static> {
390     let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
391     let mut vector = mk_stmts_let(cx, sp);
392     vector.extend(statements_mk_tts(cx, &tts[..], true));
393     let block = cx.expr_block(
394         cx.block_all(sp,
395                      vector,
396                      Some(cx.expr_ident(sp, id_ext("tt")))));
397
398     let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
399     base::MacEager::expr(expanded)
400 }
401
402 fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> {
403     strs.iter().map(|str| str_to_ident(&(*str))).collect()
404 }
405
406 fn id_ext(str: &str) -> ast::Ident {
407     str_to_ident(str)
408 }
409
410 // Lift an ident to the expr that evaluates to that ident.
411 fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
412     let e_str = cx.expr_str(sp, ident.name.as_str());
413     cx.expr_method_call(sp,
414                         cx.expr_ident(sp, id_ext("ext_cx")),
415                         id_ext("ident_of"),
416                         vec!(e_str))
417 }
418
419 // Lift a name to the expr that evaluates to that name
420 fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
421     let e_str = cx.expr_str(sp, ident.name.as_str());
422     cx.expr_method_call(sp,
423                         cx.expr_ident(sp, id_ext("ext_cx")),
424                         id_ext("name_of"),
425                         vec!(e_str))
426 }
427
428 fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
429     let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext("TokenTree"), id_ext(name));
430     cx.expr_path(cx.path_global(sp, idents))
431 }
432
433 fn mk_ast_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
434     let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext(name));
435     cx.expr_path(cx.path_global(sp, idents))
436 }
437
438 fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
439     let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name));
440     cx.expr_path(cx.path_global(sp, idents))
441 }
442
443 fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
444     let name = match bop {
445         token::Plus     => "Plus",
446         token::Minus    => "Minus",
447         token::Star     => "Star",
448         token::Slash    => "Slash",
449         token::Percent  => "Percent",
450         token::Caret    => "Caret",
451         token::And      => "And",
452         token::Or       => "Or",
453         token::Shl      => "Shl",
454         token::Shr      => "Shr"
455     };
456     mk_token_path(cx, sp, name)
457 }
458
459 fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
460     let name = match delim {
461         token::Paren     => "Paren",
462         token::Bracket   => "Bracket",
463         token::Brace     => "Brace",
464     };
465     mk_token_path(cx, sp, name)
466 }
467
468 #[allow(non_upper_case_globals)]
469 fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
470     macro_rules! mk_lit {
471         ($name: expr, $suffix: expr, $($args: expr),*) => {{
472             let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]);
473             let suffix = match $suffix {
474                 Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
475                 None => cx.expr_none(sp)
476             };
477             cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
478         }}
479     }
480     match *tok {
481         token::BinOp(binop) => {
482             return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop)));
483         }
484         token::BinOpEq(binop) => {
485             return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"),
486                                 vec!(mk_binop(cx, sp, binop)));
487         }
488
489         token::OpenDelim(delim) => {
490             return cx.expr_call(sp, mk_token_path(cx, sp, "OpenDelim"),
491                                 vec![mk_delim(cx, sp, delim)]);
492         }
493         token::CloseDelim(delim) => {
494             return cx.expr_call(sp, mk_token_path(cx, sp, "CloseDelim"),
495                                 vec![mk_delim(cx, sp, delim)]);
496         }
497
498         token::Literal(token::Byte(i), suf) => {
499             let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
500             return mk_lit!("Byte", suf, e_byte);
501         }
502
503         token::Literal(token::Char(i), suf) => {
504             let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
505             return mk_lit!("Char", suf, e_char);
506         }
507
508         token::Literal(token::Integer(i), suf) => {
509             let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
510             return mk_lit!("Integer", suf, e_int);
511         }
512
513         token::Literal(token::Float(fident), suf) => {
514             let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident));
515             return mk_lit!("Float", suf, e_fident);
516         }
517
518         token::Literal(token::Str_(ident), suf) => {
519             return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))
520         }
521
522         token::Literal(token::StrRaw(ident, n), suf) => {
523             return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)),
524                            cx.expr_usize(sp, n))
525         }
526
527         token::Ident(ident, style) => {
528             return cx.expr_call(sp,
529                                 mk_token_path(cx, sp, "Ident"),
530                                 vec![mk_ident(cx, sp, ident),
531                                      match style {
532                                         ModName => mk_token_path(cx, sp, "ModName"),
533                                         Plain   => mk_token_path(cx, sp, "Plain"),
534                                      }]);
535         }
536
537         token::Lifetime(ident) => {
538             return cx.expr_call(sp,
539                                 mk_token_path(cx, sp, "Lifetime"),
540                                 vec!(mk_ident(cx, sp, ident)));
541         }
542
543         token::DocComment(ident) => {
544             return cx.expr_call(sp,
545                                 mk_token_path(cx, sp, "DocComment"),
546                                 vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))));
547         }
548
549         token::MatchNt(name, kind, namep, kindp) => {
550             return cx.expr_call(sp,
551                                 mk_token_path(cx, sp, "MatchNt"),
552                                 vec!(mk_ident(cx, sp, name),
553                                      mk_ident(cx, sp, kind),
554                                      match namep {
555                                         ModName => mk_token_path(cx, sp, "ModName"),
556                                         Plain   => mk_token_path(cx, sp, "Plain"),
557                                      },
558                                      match kindp {
559                                         ModName => mk_token_path(cx, sp, "ModName"),
560                                         Plain   => mk_token_path(cx, sp, "Plain"),
561                                      }));
562         }
563
564         token::Interpolated(_) => panic!("quote! with interpolated token"),
565
566         _ => ()
567     }
568
569     let name = match *tok {
570         token::Eq           => "Eq",
571         token::Lt           => "Lt",
572         token::Le           => "Le",
573         token::EqEq         => "EqEq",
574         token::Ne           => "Ne",
575         token::Ge           => "Ge",
576         token::Gt           => "Gt",
577         token::AndAnd       => "AndAnd",
578         token::OrOr         => "OrOr",
579         token::Not          => "Not",
580         token::Tilde        => "Tilde",
581         token::At           => "At",
582         token::Dot          => "Dot",
583         token::DotDot       => "DotDot",
584         token::Comma        => "Comma",
585         token::Semi         => "Semi",
586         token::Colon        => "Colon",
587         token::ModSep       => "ModSep",
588         token::RArrow       => "RArrow",
589         token::LArrow       => "LArrow",
590         token::FatArrow     => "FatArrow",
591         token::Pound        => "Pound",
592         token::Dollar       => "Dollar",
593         token::Question     => "Question",
594         token::Underscore   => "Underscore",
595         token::Eof          => "Eof",
596         _                   => panic!("unhandled token in quote!"),
597     };
598     mk_token_path(cx, sp, name)
599 }
600
601 fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<P<ast::Stmt>> {
602     match *tt {
603         TokenTree::Token(sp, SubstNt(ident, _)) => {
604             // tt.extend($ident.to_tokens(ext_cx))
605
606             let e_to_toks =
607                 cx.expr_method_call(sp,
608                                     cx.expr_ident(sp, ident),
609                                     id_ext("to_tokens"),
610                                     vec!(cx.expr_ident(sp, id_ext("ext_cx"))));
611             let e_to_toks =
612                 cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]);
613
614             let e_push =
615                 cx.expr_method_call(sp,
616                                     cx.expr_ident(sp, id_ext("tt")),
617                                     id_ext("extend"),
618                                     vec!(e_to_toks));
619
620             vec!(cx.stmt_expr(e_push))
621         }
622         ref tt @ TokenTree::Token(_, MatchNt(..)) if !matcher => {
623             let mut seq = vec![];
624             for i in 0..tt.len() {
625                 seq.push(tt.get_tt(i));
626             }
627             statements_mk_tts(cx, &seq[..], matcher)
628         }
629         TokenTree::Token(sp, ref tok) => {
630             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
631             let e_tok = cx.expr_call(sp,
632                                      mk_tt_path(cx, sp, "Token"),
633                                      vec!(e_sp, expr_mk_token(cx, sp, tok)));
634             let e_push =
635                 cx.expr_method_call(sp,
636                                     cx.expr_ident(sp, id_ext("tt")),
637                                     id_ext("push"),
638                                     vec!(e_tok));
639             vec!(cx.stmt_expr(e_push))
640         },
641         TokenTree::Delimited(_, ref delimed) => {
642             statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter()
643                 .chain(delimed.tts.iter()
644                                   .flat_map(|tt| statements_mk_tt(cx, tt, matcher)))
645                 .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher))
646                 .collect()
647         },
648         TokenTree::Sequence(sp, ref seq) => {
649             if !matcher {
650                 panic!("TokenTree::Sequence in quote!");
651             }
652
653             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
654
655             let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
656             let mut tts_stmts = vec![stmt_let_tt];
657             tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
658             let e_tts = cx.expr_block(cx.block(sp, tts_stmts,
659                                                    Some(cx.expr_ident(sp, id_ext("tt")))));
660             let e_separator = match seq.separator {
661                 Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
662                 None => cx.expr_none(sp),
663             };
664             let e_op = match seq.op {
665                 ast::ZeroOrMore => mk_ast_path(cx, sp, "ZeroOrMore"),
666                 ast::OneOrMore => mk_ast_path(cx, sp, "OneOrMore"),
667             };
668             let fields = vec![cx.field_imm(sp, id_ext("tts"), e_tts),
669                               cx.field_imm(sp, id_ext("separator"), e_separator),
670                               cx.field_imm(sp, id_ext("op"), e_op),
671                               cx.field_imm(sp, id_ext("num_captures"),
672                                                cx.expr_usize(sp, seq.num_captures))];
673             let seq_path = vec![id_ext("syntax"), id_ext("ast"), id_ext("SequenceRepetition")];
674             let e_seq_struct = cx.expr_struct(sp, cx.path_global(sp, seq_path), fields);
675             let e_rc_new = cx.expr_call_global(sp, vec![id_ext("std"),
676                                                         id_ext("rc"),
677                                                         id_ext("Rc"),
678                                                         id_ext("new")],
679                                                    vec![e_seq_struct]);
680             let e_tok = cx.expr_call(sp,
681                                      mk_tt_path(cx, sp, "Sequence"),
682                                      vec!(e_sp, e_rc_new));
683             let e_push =
684                 cx.expr_method_call(sp,
685                                     cx.expr_ident(sp, id_ext("tt")),
686                                     id_ext("push"),
687                                     vec!(e_tok));
688             vec!(cx.stmt_expr(e_push))
689         }
690     }
691 }
692
693 fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
694                             -> (P<ast::Expr>, Vec<TokenTree>) {
695     // NB: It appears that the main parser loses its mind if we consider
696     // $foo as a SubstNt during the main parse, so we have to re-parse
697     // under quote_depth > 0. This is silly and should go away; the _guess_ is
698     // it has to do with transition away from supporting old-style macros, so
699     // try removing it when enough of them are gone.
700
701     let mut p = cx.new_parser_from_tts(tts);
702     p.quote_depth += 1;
703
704     let cx_expr = panictry!(p.parse_expr_nopanic());
705     if !panictry!(p.eat(&token::Comma)) {
706         panic!(p.fatal("expected token `,`"));
707     }
708
709     let tts = panictry!(p.parse_all_token_trees());
710     p.abort_if_errors();
711
712     (cx_expr, tts)
713 }
714
715 fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<P<ast::Stmt>> {
716     // We also bind a single value, sp, to ext_cx.call_site()
717     //
718     // This causes every span in a token-tree quote to be attributed to the
719     // call site of the extension using the quote. We can't really do much
720     // better since the source of the quote may well be in a library that
721     // was not even parsed by this compilation run, that the user has no
722     // source code for (eg. in libsyntax, which they're just _using_).
723     //
724     // The old quasiquoter had an elaborate mechanism for denoting input
725     // file locations from which quotes originated; unfortunately this
726     // relied on feeding the source string of the quote back into the
727     // compiler (which we don't really want to do) and, in any case, only
728     // pushed the problem a very small step further back: an error
729     // resulting from a parse of the resulting quote is still attributed to
730     // the site the string literal occurred, which was in a source file
731     // _other_ than the one the user has control over. For example, an
732     // error in a quote from the protocol compiler, invoked in user code
733     // using macro_rules! for example, will be attributed to the macro_rules.rs
734     // file in libsyntax, which the user might not even have source to (unless
735     // they happen to have a compiler on hand). Over all, the phase distinction
736     // just makes quotes "hard to attribute". Possibly this could be fixed
737     // by recreating some of the original qq machinery in the tt regime
738     // (pushing fake FileMaps onto the parser to account for original sites
739     // of quotes, for example) but at this point it seems not likely to be
740     // worth the hassle.
741
742     let e_sp = cx.expr_method_call(sp,
743                                    cx.expr_ident(sp, id_ext("ext_cx")),
744                                    id_ext("call_site"),
745                                    Vec::new());
746
747     let stmt_let_sp = cx.stmt_let(sp, false,
748                                   id_ext("_sp"),
749                                   e_sp);
750
751     let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
752
753     vec!(stmt_let_sp, stmt_let_tt)
754 }
755
756 fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec<P<ast::Stmt>> {
757     let mut ss = Vec::new();
758     for tt in tts {
759         ss.extend(statements_mk_tt(cx, tt, matcher));
760     }
761     ss
762 }
763
764 fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])
765               -> (P<ast::Expr>, P<ast::Expr>) {
766     let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
767
768     let mut vector = mk_stmts_let(cx, sp);
769     vector.extend(statements_mk_tts(cx, &tts[..], false));
770     let block = cx.expr_block(
771         cx.block_all(sp,
772                      vector,
773                      Some(cx.expr_ident(sp, id_ext("tt")))));
774
775     (cx_expr, block)
776 }
777
778 fn expand_wrapper(cx: &ExtCtxt,
779                   sp: Span,
780                   cx_expr: P<ast::Expr>,
781                   expr: P<ast::Expr>,
782                   imports: &[&[&str]]) -> P<ast::Expr> {
783     // Explicitly borrow to avoid moving from the invoker (#16992)
784     let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
785     let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);
786
787     let stmts = imports.iter().map(|path| {
788         // make item: `use ...;`
789         let path = path.iter().map(|s| s.to_string()).collect();
790         cx.stmt_item(sp, cx.item_use_glob(sp, ast::Inherited, ids_ext(path)))
791     }).chain(Some(stmt_let_ext_cx)).collect();
792
793     cx.expr_block(cx.block_all(sp, stmts, Some(expr)))
794 }
795
796 fn expand_parse_call(cx: &ExtCtxt,
797                      sp: Span,
798                      parse_method: &str,
799                      arg_exprs: Vec<P<ast::Expr>> ,
800                      tts: &[TokenTree]) -> P<ast::Expr> {
801     let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
802
803     let cfg_call = || cx.expr_method_call(
804         sp, cx.expr_ident(sp, id_ext("ext_cx")),
805         id_ext("cfg"), Vec::new());
806
807     let parse_sess_call = || cx.expr_method_call(
808         sp, cx.expr_ident(sp, id_ext("ext_cx")),
809         id_ext("parse_sess"), Vec::new());
810
811     let new_parser_call =
812         cx.expr_call(sp,
813                      cx.expr_ident(sp, id_ext("new_parser_from_tts")),
814                      vec!(parse_sess_call(), cfg_call(), tts_expr));
815
816     let expr = cx.expr_method_call(sp, new_parser_call, id_ext(parse_method),
817                                    arg_exprs);
818
819     if parse_method == "parse_attribute" {
820         expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"],
821                                                 &["syntax", "parse", "attr"]])
822     } else {
823         expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]])
824     }
825 }