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