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