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