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