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