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