]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/quote.rs
rollup merge of #17054 : pcwalton/subslice-syntax
[rust.git] / src / libsyntax / ext / quote.rs
1 // Copyright 2012 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;
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
19 use std::gc::Gc;
20
21 /**
22 *
23 * Quasiquoting works via token trees.
24 *
25 * This is registered as a set of expression syntax extension called quote!
26 * that lifts its argument token-tree to an AST representing the
27 * construction of the same token tree, with ast::TTNonterminal nodes
28 * interpreted as antiquotes (splices).
29 *
30 */
31
32 pub mod rt {
33     use ast;
34     use codemap::Spanned;
35     use ext::base::ExtCtxt;
36     use parse::token;
37     use parse;
38     use print::pprust;
39
40     use ast::{TokenTree, Generics, Expr};
41
42     pub use parse::new_parser_from_tts;
43     pub use codemap::{BytePos, Span, dummy_spanned};
44
45     use std::gc::Gc;
46
47     pub trait ToTokens {
48         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> ;
49     }
50
51     impl ToTokens for TokenTree {
52         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
53             vec!(self.clone())
54         }
55     }
56
57     impl<T: ToTokens> ToTokens for Vec<T> {
58         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
59             let a = self.iter().flat_map(|t| t.to_tokens(cx).move_iter());
60             FromIterator::from_iter(a)
61         }
62     }
63
64     impl<T: ToTokens> ToTokens for Spanned<T> {
65         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
66             // FIXME: use the span?
67             self.node.to_tokens(cx)
68         }
69     }
70
71     impl<T: ToTokens> ToTokens for Option<T> {
72         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
73             match self {
74                 &Some(ref t) => t.to_tokens(cx),
75                 &None => Vec::new(),
76             }
77         }
78     }
79
80     /* Should be (when bugs in default methods are fixed):
81
82     trait ToSource : ToTokens {
83         // Takes a thing and generates a string containing rust code for it.
84         pub fn to_source() -> String;
85
86         // If you can make source, you can definitely make tokens.
87         pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
88             cx.parse_tts(self.to_source())
89         }
90     }
91
92     */
93
94     // FIXME: Move this trait to pprust and get rid of *_to_str?
95     pub trait ToSource {
96         // Takes a thing and generates a string containing rust code for it.
97         fn to_source(&self) -> String;
98     }
99
100     // FIXME (Issue #16472): This should go away after ToToken impls
101     // are revised to go directly to token-trees.
102     trait ToSourceWithHygiene : ToSource {
103         // Takes a thing and generates a string containing rust code
104         // for it, encoding Idents as special byte sequences to
105         // maintain hygiene across serialization and deserialization.
106         fn to_source_with_hygiene(&self) -> String;
107     }
108
109     macro_rules! impl_to_source(
110         (Gc<$t:ty>, $pp:ident) => (
111             impl ToSource for Gc<$t> {
112                 fn to_source(&self) -> String {
113                     pprust::$pp(&**self)
114                 }
115             }
116             impl ToSourceWithHygiene for Gc<$t> {
117                 fn to_source_with_hygiene(&self) -> String {
118                     pprust::with_hygiene::$pp(&**self)
119                 }
120             }
121         );
122         ($t:ty, $pp:ident) => (
123             impl ToSource for $t {
124                 fn to_source(&self) -> String {
125                     pprust::$pp(self)
126                 }
127             }
128             impl ToSourceWithHygiene for $t {
129                 fn to_source_with_hygiene(&self) -> String {
130                     pprust::with_hygiene::$pp(self)
131                 }
132             }
133         );
134     )
135
136     fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
137         xs.iter()
138             .map(|i| i.to_source())
139             .collect::<Vec<String>>()
140             .connect(sep)
141             .to_string()
142     }
143
144     fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
145         sep: &'static str, xs: &'a [T]) -> String {
146         xs.iter()
147             .map(|i| i.to_source_with_hygiene())
148             .collect::<Vec<String>>()
149             .connect(sep)
150             .to_string()
151     }
152
153     macro_rules! impl_to_source_slice(
154         ($t:ty, $sep:expr) => (
155             impl<'a> ToSource for &'a [$t] {
156                 fn to_source(&self) -> String {
157                     slice_to_source($sep, *self)
158                 }
159             }
160
161             impl<'a> ToSourceWithHygiene for &'a [$t] {
162                 fn to_source_with_hygiene(&self) -> String {
163                     slice_to_source_with_hygiene($sep, *self)
164                 }
165             }
166         )
167     )
168
169     impl ToSource for ast::Ident {
170         fn to_source(&self) -> String {
171             token::get_ident(*self).get().to_string()
172         }
173     }
174
175     impl ToSourceWithHygiene for ast::Ident {
176         fn to_source_with_hygiene(&self) -> String {
177             self.encode_with_hygiene()
178         }
179     }
180
181     impl_to_source!(ast::Ty, ty_to_string)
182     impl_to_source!(ast::Block, block_to_string)
183     impl_to_source!(ast::Arg, arg_to_string)
184     impl_to_source!(Generics, generics_to_string)
185     impl_to_source!(Gc<ast::Item>, item_to_string)
186     impl_to_source!(Gc<ast::Method>, method_to_string)
187     impl_to_source!(Gc<ast::Stmt>, stmt_to_string)
188     impl_to_source!(Gc<ast::Expr>, expr_to_string)
189     impl_to_source!(Gc<ast::Pat>, pat_to_string)
190     impl_to_source!(ast::Arm, arm_to_string)
191     impl_to_source_slice!(ast::Ty, ", ")
192     impl_to_source_slice!(Gc<ast::Item>, "\n\n")
193
194     impl ToSource for ast::Attribute_ {
195         fn to_source(&self) -> String {
196             pprust::attribute_to_string(&dummy_spanned(*self))
197         }
198     }
199     impl ToSourceWithHygiene for ast::Attribute_ {
200         fn to_source_with_hygiene(&self) -> String {
201             self.to_source()
202         }
203     }
204
205     impl<'a> ToSource for &'a str {
206         fn to_source(&self) -> String {
207             let lit = dummy_spanned(ast::LitStr(
208                     token::intern_and_get_ident(*self), ast::CookedStr));
209             pprust::lit_to_string(&lit)
210         }
211     }
212     impl<'a> ToSourceWithHygiene for &'a str {
213         fn to_source_with_hygiene(&self) -> String {
214             self.to_source()
215         }
216     }
217
218     impl ToSource for () {
219         fn to_source(&self) -> String {
220             "()".to_string()
221         }
222     }
223     impl ToSourceWithHygiene for () {
224         fn to_source_with_hygiene(&self) -> String {
225             self.to_source()
226         }
227     }
228
229     impl ToSource for bool {
230         fn to_source(&self) -> String {
231             let lit = dummy_spanned(ast::LitBool(*self));
232             pprust::lit_to_string(&lit)
233         }
234     }
235     impl ToSourceWithHygiene for bool {
236         fn to_source_with_hygiene(&self) -> String {
237             self.to_source()
238         }
239     }
240
241     impl ToSource for char {
242         fn to_source(&self) -> String {
243             let lit = dummy_spanned(ast::LitChar(*self));
244             pprust::lit_to_string(&lit)
245         }
246     }
247     impl ToSourceWithHygiene for char {
248         fn to_source_with_hygiene(&self) -> String {
249             self.to_source()
250         }
251     }
252
253     macro_rules! impl_to_source_int(
254         (signed, $t:ty, $tag:ident) => (
255             impl ToSource for $t {
256                 fn to_source(&self) -> String {
257                     let lit = ast::LitInt(*self as u64, ast::SignedIntLit(ast::$tag,
258                                                                           ast::Sign::new(*self)));
259                     pprust::lit_to_string(&dummy_spanned(lit))
260                 }
261             }
262             impl ToSourceWithHygiene for $t {
263                 fn to_source_with_hygiene(&self) -> String {
264                     self.to_source()
265                 }
266             }
267         );
268         (unsigned, $t:ty, $tag:ident) => (
269             impl ToSource for $t {
270                 fn to_source(&self) -> String {
271                     let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit(ast::$tag));
272                     pprust::lit_to_string(&dummy_spanned(lit))
273                 }
274             }
275             impl ToSourceWithHygiene for $t {
276                 fn to_source_with_hygiene(&self) -> String {
277                     self.to_source()
278                 }
279             }
280         );
281     )
282
283     impl_to_source_int!(signed, int, TyI)
284     impl_to_source_int!(signed, i8,  TyI8)
285     impl_to_source_int!(signed, i16, TyI16)
286     impl_to_source_int!(signed, i32, TyI32)
287     impl_to_source_int!(signed, i64, TyI64)
288
289     impl_to_source_int!(unsigned, uint, TyU)
290     impl_to_source_int!(unsigned, u8,   TyU8)
291     impl_to_source_int!(unsigned, u16,  TyU16)
292     impl_to_source_int!(unsigned, u32,  TyU32)
293     impl_to_source_int!(unsigned, u64,  TyU64)
294
295     // Alas ... we write these out instead. All redundant.
296
297     macro_rules! impl_to_tokens(
298         ($t:ty) => (
299             impl ToTokens for $t {
300                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
301                     cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
302                 }
303             }
304         )
305     )
306
307     macro_rules! impl_to_tokens_lifetime(
308         ($t:ty) => (
309             impl<'a> ToTokens for $t {
310                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
311                     cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
312                 }
313             }
314         )
315     )
316
317     impl_to_tokens!(ast::Ident)
318     impl_to_tokens!(Gc<ast::Item>)
319     impl_to_tokens!(Gc<ast::Pat>)
320     impl_to_tokens!(ast::Arm)
321     impl_to_tokens!(Gc<ast::Method>)
322     impl_to_tokens_lifetime!(&'a [Gc<ast::Item>])
323     impl_to_tokens!(ast::Ty)
324     impl_to_tokens_lifetime!(&'a [ast::Ty])
325     impl_to_tokens!(Generics)
326     impl_to_tokens!(Gc<ast::Stmt>)
327     impl_to_tokens!(Gc<ast::Expr>)
328     impl_to_tokens!(ast::Block)
329     impl_to_tokens!(ast::Arg)
330     impl_to_tokens!(ast::Attribute_)
331     impl_to_tokens_lifetime!(&'a str)
332     impl_to_tokens!(())
333     impl_to_tokens!(char)
334     impl_to_tokens!(bool)
335     impl_to_tokens!(int)
336     impl_to_tokens!(i8)
337     impl_to_tokens!(i16)
338     impl_to_tokens!(i32)
339     impl_to_tokens!(i64)
340     impl_to_tokens!(uint)
341     impl_to_tokens!(u8)
342     impl_to_tokens!(u16)
343     impl_to_tokens!(u32)
344     impl_to_tokens!(u64)
345
346     pub trait ExtParseUtils {
347         fn parse_item(&self, s: String) -> Gc<ast::Item>;
348         fn parse_expr(&self, s: String) -> Gc<ast::Expr>;
349         fn parse_stmt(&self, s: String) -> Gc<ast::Stmt>;
350         fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
351     }
352
353     trait ExtParseUtilsWithHygiene {
354         // FIXME (Issue #16472): This should go away after ToToken impls
355         // are revised to go directly to token-trees.
356         fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
357     }
358
359     impl<'a> ExtParseUtils for ExtCtxt<'a> {
360
361         fn parse_item(&self, s: String) -> Gc<ast::Item> {
362             let res = parse::parse_item_from_source_str(
363                 "<quote expansion>".to_string(),
364                 s,
365                 self.cfg(),
366                 self.parse_sess());
367             match res {
368                 Some(ast) => ast,
369                 None => {
370                     error!("parse error");
371                     fail!()
372                 }
373             }
374         }
375
376         fn parse_stmt(&self, s: String) -> Gc<ast::Stmt> {
377             parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
378                                               s,
379                                               self.cfg(),
380                                               Vec::new(),
381                                               self.parse_sess())
382         }
383
384         fn parse_expr(&self, s: String) -> Gc<ast::Expr> {
385             parse::parse_expr_from_source_str("<quote expansion>".to_string(),
386                                               s,
387                                               self.cfg(),
388                                               self.parse_sess())
389         }
390
391         fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
392             parse::parse_tts_from_source_str("<quote expansion>".to_string(),
393                                              s,
394                                              self.cfg(),
395                                              self.parse_sess())
396         }
397     }
398
399     impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {
400
401         fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
402             use parse::with_hygiene::parse_tts_from_source_str;
403             parse_tts_from_source_str("<quote expansion>".to_string(),
404                                       s,
405                                       self.cfg(),
406                                       self.parse_sess())
407         }
408
409     }
410
411 }
412
413 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
414                                 sp: Span,
415                                 tts: &[ast::TokenTree])
416                                 -> Box<base::MacResult+'cx> {
417     let (cx_expr, expr) = expand_tts(cx, sp, tts);
418     let expanded = expand_wrapper(cx, sp, cx_expr, expr);
419     base::MacExpr::new(expanded)
420 }
421
422 pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
423                               sp: Span,
424                               tts: &[ast::TokenTree])
425                               -> Box<base::MacResult+'cx> {
426     let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts);
427     base::MacExpr::new(expanded)
428 }
429
430 pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt,
431                               sp: Span,
432                               tts: &[ast::TokenTree])
433                               -> Box<base::MacResult+'cx> {
434     let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes",
435                                     vec!(), tts);
436     base::MacExpr::new(expanded)
437 }
438
439 pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
440                              sp: Span,
441                              tts: &[ast::TokenTree])
442                              -> Box<base::MacResult+'cx> {
443     let expanded = expand_parse_call(cx, sp, "parse_pat", vec!(), tts);
444     base::MacExpr::new(expanded)
445 }
446
447 pub fn expand_quote_arm(cx: &mut ExtCtxt,
448                         sp: Span,
449                         tts: &[ast::TokenTree])
450                         -> Box<base::MacResult+'static> {
451     let expanded = expand_parse_call(cx, sp, "parse_arm", vec!(), tts);
452     base::MacExpr::new(expanded)
453 }
454
455 pub fn expand_quote_ty(cx: &mut ExtCtxt,
456                        sp: Span,
457                        tts: &[ast::TokenTree])
458                        -> Box<base::MacResult+'static> {
459     let e_param_colons = cx.expr_lit(sp, ast::LitBool(false));
460     let expanded = expand_parse_call(cx, sp, "parse_ty",
461                                      vec!(e_param_colons), tts);
462     base::MacExpr::new(expanded)
463 }
464
465 pub fn expand_quote_method(cx: &mut ExtCtxt,
466                            sp: Span,
467                            tts: &[ast::TokenTree])
468                            -> Box<base::MacResult+'static> {
469     let e_param_colons = cx.expr_none(sp);
470     let expanded = expand_parse_call(cx, sp, "parse_method",
471                                      vec!(e_param_colons), tts);
472     base::MacExpr::new(expanded)
473 }
474
475 pub fn expand_quote_stmt(cx: &mut ExtCtxt,
476                          sp: Span,
477                          tts: &[ast::TokenTree])
478                          -> Box<base::MacResult+'static> {
479     let e_attrs = cx.expr_vec_ng(sp);
480     let expanded = expand_parse_call(cx, sp, "parse_stmt",
481                                     vec!(e_attrs), tts);
482     base::MacExpr::new(expanded)
483 }
484
485 fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> {
486     strs.iter().map(|str| str_to_ident((*str).as_slice())).collect()
487 }
488
489 fn id_ext(str: &str) -> ast::Ident {
490     str_to_ident(str)
491 }
492
493 // Lift an ident to the expr that evaluates to that ident.
494 fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> Gc<ast::Expr> {
495     let e_str = cx.expr_str(sp, token::get_ident(ident));
496     cx.expr_method_call(sp,
497                         cx.expr_ident(sp, id_ext("ext_cx")),
498                         id_ext("ident_of"),
499                         vec!(e_str))
500 }
501
502 // Lift a name to the expr that evaluates to that name
503 fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> Gc<ast::Expr> {
504     let e_str = cx.expr_str(sp, token::get_ident(ident));
505     cx.expr_method_call(sp,
506                         cx.expr_ident(sp, id_ext("ext_cx")),
507                         id_ext("name_of"),
508                         vec!(e_str))
509 }
510
511 fn mk_ast_path(cx: &ExtCtxt, sp: Span, name: &str) -> Gc<ast::Expr> {
512     let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext(name));
513     cx.expr_path(cx.path_global(sp, idents))
514 }
515
516 fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> Gc<ast::Expr> {
517     let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name));
518     cx.expr_path(cx.path_global(sp, idents))
519 }
520
521 fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOp) -> Gc<ast::Expr> {
522     let name = match bop {
523         PLUS => "PLUS",
524         MINUS => "MINUS",
525         STAR => "STAR",
526         SLASH => "SLASH",
527         PERCENT => "PERCENT",
528         CARET => "CARET",
529         AND => "AND",
530         OR => "OR",
531         SHL => "SHL",
532         SHR => "SHR"
533     };
534     mk_token_path(cx, sp, name)
535 }
536
537 fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> Gc<ast::Expr> {
538
539     match *tok {
540         BINOP(binop) => {
541             return cx.expr_call(sp, mk_token_path(cx, sp, "BINOP"), vec!(mk_binop(cx, sp, binop)));
542         }
543         BINOPEQ(binop) => {
544             return cx.expr_call(sp, mk_token_path(cx, sp, "BINOPEQ"),
545                                 vec!(mk_binop(cx, sp, binop)));
546         }
547
548         LIT_BYTE(i) => {
549             let e_byte = mk_name(cx, sp, i.ident());
550
551             return cx.expr_call(sp, mk_token_path(cx, sp, "LIT_BYTE"), vec!(e_byte));
552         }
553
554         LIT_CHAR(i) => {
555             let e_char = mk_name(cx, sp, i.ident());
556
557             return cx.expr_call(sp, mk_token_path(cx, sp, "LIT_CHAR"), vec!(e_char));
558         }
559
560         LIT_INTEGER(i) => {
561             let e_int = mk_name(cx, sp, i.ident());
562             return cx.expr_call(sp, mk_token_path(cx, sp, "LIT_INTEGER"), vec!(e_int));
563         }
564
565         LIT_FLOAT(fident) => {
566             let e_fident = mk_name(cx, sp, fident.ident());
567             return cx.expr_call(sp, mk_token_path(cx, sp, "LIT_FLOAT"), vec!(e_fident));
568         }
569
570         LIT_STR(ident) => {
571             return cx.expr_call(sp,
572                                 mk_token_path(cx, sp, "LIT_STR"),
573                                 vec!(mk_name(cx, sp, ident.ident())));
574         }
575
576         LIT_STR_RAW(ident, n) => {
577             return cx.expr_call(sp,
578                                 mk_token_path(cx, sp, "LIT_STR_RAW"),
579                                 vec!(mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)));
580         }
581
582         IDENT(ident, b) => {
583             return cx.expr_call(sp,
584                                 mk_token_path(cx, sp, "IDENT"),
585                                 vec!(mk_ident(cx, sp, ident), cx.expr_bool(sp, b)));
586         }
587
588         LIFETIME(ident) => {
589             return cx.expr_call(sp,
590                                 mk_token_path(cx, sp, "LIFETIME"),
591                                 vec!(mk_ident(cx, sp, ident)));
592         }
593
594         DOC_COMMENT(ident) => {
595             return cx.expr_call(sp,
596                                 mk_token_path(cx, sp, "DOC_COMMENT"),
597                                 vec!(mk_name(cx, sp, ident.ident())));
598         }
599
600         INTERPOLATED(_) => fail!("quote! with interpolated token"),
601
602         _ => ()
603     }
604
605     let name = match *tok {
606         EQ => "EQ",
607         LT => "LT",
608         LE => "LE",
609         EQEQ => "EQEQ",
610         NE => "NE",
611         GE => "GE",
612         GT => "GT",
613         ANDAND => "ANDAND",
614         OROR => "OROR",
615         NOT => "NOT",
616         TILDE => "TILDE",
617         AT => "AT",
618         DOT => "DOT",
619         DOTDOT => "DOTDOT",
620         COMMA => "COMMA",
621         SEMI => "SEMI",
622         COLON => "COLON",
623         MOD_SEP => "MOD_SEP",
624         RARROW => "RARROW",
625         LARROW => "LARROW",
626         FAT_ARROW => "FAT_ARROW",
627         LPAREN => "LPAREN",
628         RPAREN => "RPAREN",
629         LBRACKET => "LBRACKET",
630         RBRACKET => "RBRACKET",
631         LBRACE => "LBRACE",
632         RBRACE => "RBRACE",
633         POUND => "POUND",
634         DOLLAR => "DOLLAR",
635         UNDERSCORE => "UNDERSCORE",
636         EOF => "EOF",
637         _ => fail!()
638     };
639     mk_token_path(cx, sp, name)
640 }
641
642
643 fn mk_tt(cx: &ExtCtxt, sp: Span, tt: &ast::TokenTree) -> Vec<Gc<ast::Stmt>> {
644     match *tt {
645         ast::TTTok(sp, ref tok) => {
646             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
647             let e_tok = cx.expr_call(sp,
648                                      mk_ast_path(cx, sp, "TTTok"),
649                                      vec!(e_sp, mk_token(cx, sp, tok)));
650             let e_push =
651                 cx.expr_method_call(sp,
652                                     cx.expr_ident(sp, id_ext("tt")),
653                                     id_ext("push"),
654                                     vec!(e_tok));
655             vec!(cx.stmt_expr(e_push))
656         }
657
658         ast::TTDelim(ref tts) => mk_tts(cx, sp, tts.as_slice()),
659         ast::TTSeq(..) => fail!("TTSeq in quote!"),
660
661         ast::TTNonterminal(sp, ident) => {
662
663             // tt.push_all_move($ident.to_tokens(ext_cx))
664
665             let e_to_toks =
666                 cx.expr_method_call(sp,
667                                     cx.expr_ident(sp, ident),
668                                     id_ext("to_tokens"),
669                                     vec!(cx.expr_ident(sp, id_ext("ext_cx"))));
670
671             let e_push =
672                 cx.expr_method_call(sp,
673                                     cx.expr_ident(sp, id_ext("tt")),
674                                     id_ext("push_all_move"),
675                                     vec!(e_to_toks));
676
677             vec!(cx.stmt_expr(e_push))
678         }
679     }
680 }
681
682 fn mk_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree])
683     -> Vec<Gc<ast::Stmt>> {
684     let mut ss = Vec::new();
685     for tt in tts.iter() {
686         ss.push_all_move(mk_tt(cx, sp, tt));
687     }
688     ss
689 }
690
691 fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree])
692               -> (Gc<ast::Expr>, Gc<ast::Expr>) {
693     // NB: It appears that the main parser loses its mind if we consider
694     // $foo as a TTNonterminal during the main parse, so we have to re-parse
695     // under quote_depth > 0. This is silly and should go away; the _guess_ is
696     // it has to do with transition away from supporting old-style macros, so
697     // try removing it when enough of them are gone.
698
699     let mut p = cx.new_parser_from_tts(tts);
700     p.quote_depth += 1u;
701
702     let cx_expr = p.parse_expr();
703     if !p.eat(&token::COMMA) {
704         p.fatal("expected token `,`");
705     }
706
707     let tts = p.parse_all_token_trees();
708     p.abort_if_errors();
709
710     // We also bind a single value, sp, to ext_cx.call_site()
711     //
712     // This causes every span in a token-tree quote to be attributed to the
713     // call site of the extension using the quote. We can't really do much
714     // better since the source of the quote may well be in a library that
715     // was not even parsed by this compilation run, that the user has no
716     // source code for (eg. in libsyntax, which they're just _using_).
717     //
718     // The old quasiquoter had an elaborate mechanism for denoting input
719     // file locations from which quotes originated; unfortunately this
720     // relied on feeding the source string of the quote back into the
721     // compiler (which we don't really want to do) and, in any case, only
722     // pushed the problem a very small step further back: an error
723     // resulting from a parse of the resulting quote is still attributed to
724     // the site the string literal occurred, which was in a source file
725     // _other_ than the one the user has control over. For example, an
726     // error in a quote from the protocol compiler, invoked in user code
727     // using macro_rules! for example, will be attributed to the macro_rules.rs
728     // file in libsyntax, which the user might not even have source to (unless
729     // they happen to have a compiler on hand). Over all, the phase distinction
730     // just makes quotes "hard to attribute". Possibly this could be fixed
731     // by recreating some of the original qq machinery in the tt regime
732     // (pushing fake FileMaps onto the parser to account for original sites
733     // of quotes, for example) but at this point it seems not likely to be
734     // worth the hassle.
735
736     let e_sp = cx.expr_method_call(sp,
737                                    cx.expr_ident(sp, id_ext("ext_cx")),
738                                    id_ext("call_site"),
739                                    Vec::new());
740
741     let stmt_let_sp = cx.stmt_let(sp, false,
742                                   id_ext("_sp"),
743                                   e_sp);
744
745     let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
746
747     let mut vector = vec!(stmt_let_sp, stmt_let_tt);
748     vector.push_all_move(mk_tts(cx, sp, tts.as_slice()));
749     let block = cx.expr_block(
750         cx.block_all(sp,
751                      Vec::new(),
752                      vector,
753                      Some(cx.expr_ident(sp, id_ext("tt")))));
754
755     (cx_expr, block)
756 }
757
758 fn expand_wrapper(cx: &ExtCtxt,
759                   sp: Span,
760                   cx_expr: Gc<ast::Expr>,
761                   expr: Gc<ast::Expr>) -> Gc<ast::Expr> {
762     let uses = [
763         &["syntax", "ext", "quote", "rt"],
764     ].iter().map(|path| {
765         let path = path.iter().map(|s| s.to_string()).collect();
766         cx.view_use_glob(sp, ast::Inherited, ids_ext(path))
767     }).collect();
768
769     // Explicitly borrow to avoid moving from the invoker (#16992)
770     let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
771     let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);
772
773     cx.expr_block(cx.block_all(sp, uses, vec!(stmt_let_ext_cx), Some(expr)))
774 }
775
776 fn expand_parse_call(cx: &ExtCtxt,
777                      sp: Span,
778                      parse_method: &str,
779                      arg_exprs: Vec<Gc<ast::Expr>>,
780                      tts: &[ast::TokenTree]) -> Gc<ast::Expr> {
781     let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
782
783     let cfg_call = || cx.expr_method_call(
784         sp, cx.expr_ident(sp, id_ext("ext_cx")),
785         id_ext("cfg"), Vec::new());
786
787     let parse_sess_call = || cx.expr_method_call(
788         sp, cx.expr_ident(sp, id_ext("ext_cx")),
789         id_ext("parse_sess"), Vec::new());
790
791     let new_parser_call =
792         cx.expr_call(sp,
793                      cx.expr_ident(sp, id_ext("new_parser_from_tts")),
794                      vec!(parse_sess_call(), cfg_call(), tts_expr));
795
796     let expr = cx.expr_method_call(sp, new_parser_call, id_ext(parse_method),
797                                    arg_exprs);
798
799     expand_wrapper(cx, sp, cx_expr, expr)
800 }