]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/quote.rs
Auto merge of #29780 - KyleMayes:quote-ext, r=nrc
[rust.git] / src / libsyntax / ext / quote.rs
1 // Copyright 2015 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::{self, TokenTree};
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 ///  Quasiquoting works via token trees.
21 ///
22 ///  This is registered as a set of expression syntax extension called quote!
23 ///  that lifts its argument token-tree to an AST representing the
24 ///  construction of the same token tree, with token::SubstNt interpreted
25 ///  as antiquotes (splices).
26
27 pub mod rt {
28     use ast;
29     use codemap::Spanned;
30     use ext::base::ExtCtxt;
31     use parse::{self, token, classify};
32     use ptr::P;
33     use std::rc::Rc;
34
35     use ast::{TokenTree, Expr};
36
37     pub use parse::new_parser_from_tts;
38     pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP};
39
40     pub trait ToTokens {
41         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
42     }
43
44     impl ToTokens for TokenTree {
45         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
46             vec!(self.clone())
47         }
48     }
49
50     impl<T: ToTokens> ToTokens for Vec<T> {
51         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
52             self.iter().flat_map(|t| t.to_tokens(cx)).collect()
53         }
54     }
55
56     impl<T: ToTokens> ToTokens for Spanned<T> {
57         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
58             // FIXME: use the span?
59             self.node.to_tokens(cx)
60         }
61     }
62
63     impl<T: ToTokens> ToTokens for Option<T> {
64         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
65             match self {
66                 &Some(ref t) => t.to_tokens(cx),
67                 &None => Vec::new(),
68             }
69         }
70     }
71
72     impl ToTokens for ast::Ident {
73         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
74             vec![TokenTree::Token(DUMMY_SP, token::Ident(*self, token::Plain))]
75         }
76     }
77
78     impl ToTokens for ast::Path {
79         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
80             vec![TokenTree::Token(DUMMY_SP,
81                                   token::Interpolated(token::NtPath(Box::new(self.clone()))))]
82         }
83     }
84
85     impl ToTokens for ast::Ty {
86         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
87             vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
88         }
89     }
90
91     impl ToTokens for ast::Block {
92         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
93             vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
94         }
95     }
96
97     impl ToTokens for ast::Generics {
98         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
99             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))]
100         }
101     }
102
103     impl ToTokens for ast::WhereClause {
104         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
105             vec![TokenTree::Token(DUMMY_SP,
106                                   token::Interpolated(token::NtWhereClause(self.clone())))]
107         }
108     }
109
110     impl ToTokens for P<ast::Item> {
111         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
112             vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))]
113         }
114     }
115
116     impl ToTokens for P<ast::ImplItem> {
117         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
118             vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
119         }
120     }
121
122     impl ToTokens for P<ast::TraitItem> {
123         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
124             vec![TokenTree::Token(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
125         }
126     }
127
128     impl ToTokens for P<ast::Stmt> {
129         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
130             let mut tts = vec![
131                 TokenTree::Token(self.span, token::Interpolated(token::NtStmt(self.clone())))
132             ];
133
134             // Some statements require a trailing semicolon.
135             if classify::stmt_ends_with_semi(&self.node) {
136                 tts.push(TokenTree::Token(self.span, token::Semi));
137             }
138
139             tts
140         }
141     }
142
143     impl ToTokens for P<ast::Expr> {
144         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
145             vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))]
146         }
147     }
148
149     impl ToTokens for P<ast::Pat> {
150         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
151             vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))]
152         }
153     }
154
155     impl ToTokens for ast::Arm {
156         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
157             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
158         }
159     }
160
161     impl ToTokens for ast::Arg {
162         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
163             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))]
164         }
165     }
166
167     impl ToTokens for P<ast::Block> {
168         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
169             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))]
170         }
171     }
172
173     macro_rules! impl_to_tokens_slice {
174         ($t: ty, $sep: expr) => {
175             impl ToTokens for [$t] {
176                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
177                     let mut v = vec![];
178                     for (i, x) in self.iter().enumerate() {
179                         if i > 0 {
180                             v.push_all(&$sep);
181                         }
182                         v.extend(x.to_tokens(cx));
183                     }
184                     v
185                 }
186             }
187         };
188     }
189
190     impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
191     impl_to_tokens_slice! { P<ast::Item>, [] }
192     impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }
193
194     impl ToTokens for P<ast::MetaItem> {
195         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
196             vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
197         }
198     }
199
200     impl ToTokens for ast::Attribute {
201         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
202             let mut r = vec![];
203             // FIXME: The spans could be better
204             r.push(TokenTree::Token(self.span, token::Pound));
205             if self.node.style == ast::AttrStyle::Inner {
206                 r.push(TokenTree::Token(self.span, token::Not));
207             }
208             r.push(TokenTree::Delimited(self.span, Rc::new(ast::Delimited {
209                 delim: token::Bracket,
210                 open_span: self.span,
211                 tts: self.node.value.to_tokens(cx),
212                 close_span: self.span,
213             })));
214             r
215         }
216     }
217
218     impl ToTokens for str {
219         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
220             let lit = ast::LitStr(
221                 token::intern_and_get_ident(self), ast::CookedStr);
222             dummy_spanned(lit).to_tokens(cx)
223         }
224     }
225
226     impl ToTokens for () {
227         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
228             vec![TokenTree::Delimited(DUMMY_SP, Rc::new(ast::Delimited {
229                 delim: token::Paren,
230                 open_span: DUMMY_SP,
231                 tts: vec![],
232                 close_span: DUMMY_SP,
233             }))]
234         }
235     }
236
237     impl ToTokens for ast::Lit {
238         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
239             // FIXME: This is wrong
240             P(ast::Expr {
241                 id: ast::DUMMY_NODE_ID,
242                 node: ast::ExprLit(P(self.clone())),
243                 span: DUMMY_SP,
244             }).to_tokens(cx)
245         }
246     }
247
248     impl ToTokens for bool {
249         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
250             dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
251         }
252     }
253
254     impl ToTokens for char {
255         fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
256             dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
257         }
258     }
259
260     macro_rules! impl_to_tokens_int {
261         (signed, $t:ty, $tag:expr) => (
262             impl ToTokens for $t {
263                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
264                     let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
265                                                                           ast::Sign::new(*self)));
266                     dummy_spanned(lit).to_tokens(cx)
267                 }
268             }
269         );
270         (unsigned, $t:ty, $tag:expr) => (
271             impl ToTokens for $t {
272                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
273                     let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
274                     dummy_spanned(lit).to_tokens(cx)
275                 }
276             }
277         );
278     }
279
280     impl_to_tokens_int! { signed, isize, ast::TyIs }
281     impl_to_tokens_int! { signed, i8,  ast::TyI8 }
282     impl_to_tokens_int! { signed, i16, ast::TyI16 }
283     impl_to_tokens_int! { signed, i32, ast::TyI32 }
284     impl_to_tokens_int! { signed, i64, ast::TyI64 }
285
286     impl_to_tokens_int! { unsigned, usize, ast::TyUs }
287     impl_to_tokens_int! { unsigned, u8,   ast::TyU8 }
288     impl_to_tokens_int! { unsigned, u16,  ast::TyU16 }
289     impl_to_tokens_int! { unsigned, u32,  ast::TyU32 }
290     impl_to_tokens_int! { unsigned, u64,  ast::TyU64 }
291
292     pub trait ExtParseUtils {
293         fn parse_item(&self, s: String) -> P<ast::Item>;
294         fn parse_expr(&self, s: String) -> P<ast::Expr>;
295         fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
296         fn parse_tts(&self, s: String) -> Vec<TokenTree>;
297     }
298
299     impl<'a> ExtParseUtils for ExtCtxt<'a> {
300
301         fn parse_item(&self, s: String) -> P<ast::Item> {
302             parse::parse_item_from_source_str(
303                 "<quote expansion>".to_string(),
304                 s,
305                 self.cfg(),
306                 self.parse_sess()).expect("parse error")
307         }
308
309         fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
310             parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
311                                               s,
312                                               self.cfg(),
313                                               self.parse_sess()).expect("parse error")
314         }
315
316         fn parse_expr(&self, s: String) -> P<ast::Expr> {
317             parse::parse_expr_from_source_str("<quote expansion>".to_string(),
318                                               s,
319                                               self.cfg(),
320                                               self.parse_sess())
321         }
322
323         fn parse_tts(&self, s: String) -> Vec<TokenTree> {
324             parse::parse_tts_from_source_str("<quote expansion>".to_string(),
325                                              s,
326                                              self.cfg(),
327                                              self.parse_sess())
328         }
329     }
330 }
331
332 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
333                                 sp: Span,
334                                 tts: &[TokenTree])
335                                 -> Box<base::MacResult+'cx> {
336     let (cx_expr, expr) = expand_tts(cx, sp, tts);
337     let expanded = expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]);
338     base::MacEager::expr(expanded)
339 }
340
341 pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
342                               sp: Span,
343                               tts: &[TokenTree])
344                               -> Box<base::MacResult+'cx> {
345     let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec!(), tts);
346     base::MacEager::expr(expanded)
347 }
348
349 pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt,
350                               sp: Span,
351                               tts: &[TokenTree])
352                               -> Box<base::MacResult+'cx> {
353     let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec!(), tts);
354     base::MacEager::expr(expanded)
355 }
356
357 pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
358                              sp: Span,
359                              tts: &[TokenTree])
360                              -> Box<base::MacResult+'cx> {
361     let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec!(), tts);
362     base::MacEager::expr(expanded)
363 }
364
365 pub fn expand_quote_arm(cx: &mut ExtCtxt,
366                         sp: Span,
367                         tts: &[TokenTree])
368                         -> Box<base::MacResult+'static> {
369     let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec!(), tts);
370     base::MacEager::expr(expanded)
371 }
372
373 pub fn expand_quote_ty(cx: &mut ExtCtxt,
374                        sp: Span,
375                        tts: &[TokenTree])
376                        -> Box<base::MacResult+'static> {
377     let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec!(), tts);
378     base::MacEager::expr(expanded)
379 }
380
381 pub fn expand_quote_stmt(cx: &mut ExtCtxt,
382                          sp: Span,
383                          tts: &[TokenTree])
384                          -> Box<base::MacResult+'static> {
385     let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec!(), tts);
386     base::MacEager::expr(expanded)
387 }
388
389 pub fn expand_quote_attr(cx: &mut ExtCtxt,
390                          sp: Span,
391                          tts: &[TokenTree])
392                          -> Box<base::MacResult+'static> {
393     let expanded = expand_parse_call(cx, sp, "parse_attribute_panic",
394                                     vec!(cx.expr_bool(sp, true)), tts);
395
396     base::MacEager::expr(expanded)
397 }
398
399 pub fn expand_quote_arg(cx: &mut ExtCtxt,
400                         sp: Span,
401                         tts: &[TokenTree])
402                         -> Box<base::MacResult+'static> {
403     let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts);
404     base::MacEager::expr(expanded)
405 }
406
407 pub fn expand_quote_block(cx: &mut ExtCtxt,
408                         sp: Span,
409                         tts: &[TokenTree])
410                         -> Box<base::MacResult+'static> {
411     let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts);
412     base::MacEager::expr(expanded)
413 }
414
415 pub fn expand_quote_meta_item(cx: &mut ExtCtxt,
416                         sp: Span,
417                         tts: &[TokenTree])
418                         -> Box<base::MacResult+'static> {
419     let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts);
420     base::MacEager::expr(expanded)
421 }
422
423 pub fn expand_quote_path(cx: &mut ExtCtxt,
424                         sp: Span,
425                         tts: &[TokenTree])
426                         -> Box<base::MacResult+'static> {
427     let mode = mk_parser_path(cx, sp, "LifetimeAndTypesWithoutColons");
428     let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts);
429     base::MacEager::expr(expanded)
430 }
431
432 pub fn expand_quote_matcher(cx: &mut ExtCtxt,
433                             sp: Span,
434                             tts: &[TokenTree])
435                             -> Box<base::MacResult+'static> {
436     let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
437     let mut vector = mk_stmts_let(cx, sp);
438     vector.extend(statements_mk_tts(cx, &tts[..], true));
439     let block = cx.expr_block(
440         cx.block_all(sp,
441                      vector,
442                      Some(cx.expr_ident(sp, id_ext("tt")))));
443
444     let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
445     base::MacEager::expr(expanded)
446 }
447
448 fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> {
449     strs.iter().map(|str| str_to_ident(&(*str))).collect()
450 }
451
452 fn id_ext(str: &str) -> ast::Ident {
453     str_to_ident(str)
454 }
455
456 // Lift an ident to the expr that evaluates to that ident.
457 fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
458     let e_str = cx.expr_str(sp, ident.name.as_str());
459     cx.expr_method_call(sp,
460                         cx.expr_ident(sp, id_ext("ext_cx")),
461                         id_ext("ident_of"),
462                         vec!(e_str))
463 }
464
465 // Lift a name to the expr that evaluates to that name
466 fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
467     let e_str = cx.expr_str(sp, ident.name.as_str());
468     cx.expr_method_call(sp,
469                         cx.expr_ident(sp, id_ext("ext_cx")),
470                         id_ext("name_of"),
471                         vec!(e_str))
472 }
473
474 fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
475     let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext("TokenTree"), id_ext(name));
476     cx.expr_path(cx.path_global(sp, idents))
477 }
478
479 fn mk_ast_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
480     let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext(name));
481     cx.expr_path(cx.path_global(sp, idents))
482 }
483
484 fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
485     let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name));
486     cx.expr_path(cx.path_global(sp, idents))
487 }
488
489 fn mk_parser_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
490     let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("parser"), id_ext(name));
491     cx.expr_path(cx.path_global(sp, idents))
492 }
493
494 fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
495     let name = match bop {
496         token::Plus     => "Plus",
497         token::Minus    => "Minus",
498         token::Star     => "Star",
499         token::Slash    => "Slash",
500         token::Percent  => "Percent",
501         token::Caret    => "Caret",
502         token::And      => "And",
503         token::Or       => "Or",
504         token::Shl      => "Shl",
505         token::Shr      => "Shr"
506     };
507     mk_token_path(cx, sp, name)
508 }
509
510 fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
511     let name = match delim {
512         token::Paren     => "Paren",
513         token::Bracket   => "Bracket",
514         token::Brace     => "Brace",
515     };
516     mk_token_path(cx, sp, name)
517 }
518
519 #[allow(non_upper_case_globals)]
520 fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
521     macro_rules! mk_lit {
522         ($name: expr, $suffix: expr, $($args: expr),*) => {{
523             let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]);
524             let suffix = match $suffix {
525                 Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
526                 None => cx.expr_none(sp)
527             };
528             cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
529         }}
530     }
531     match *tok {
532         token::BinOp(binop) => {
533             return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop)));
534         }
535         token::BinOpEq(binop) => {
536             return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"),
537                                 vec!(mk_binop(cx, sp, binop)));
538         }
539
540         token::OpenDelim(delim) => {
541             return cx.expr_call(sp, mk_token_path(cx, sp, "OpenDelim"),
542                                 vec![mk_delim(cx, sp, delim)]);
543         }
544         token::CloseDelim(delim) => {
545             return cx.expr_call(sp, mk_token_path(cx, sp, "CloseDelim"),
546                                 vec![mk_delim(cx, sp, delim)]);
547         }
548
549         token::Literal(token::Byte(i), suf) => {
550             let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
551             return mk_lit!("Byte", suf, e_byte);
552         }
553
554         token::Literal(token::Char(i), suf) => {
555             let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
556             return mk_lit!("Char", suf, e_char);
557         }
558
559         token::Literal(token::Integer(i), suf) => {
560             let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
561             return mk_lit!("Integer", suf, e_int);
562         }
563
564         token::Literal(token::Float(fident), suf) => {
565             let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident));
566             return mk_lit!("Float", suf, e_fident);
567         }
568
569         token::Literal(token::Str_(ident), suf) => {
570             return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))
571         }
572
573         token::Literal(token::StrRaw(ident, n), suf) => {
574             return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)),
575                            cx.expr_usize(sp, n))
576         }
577
578         token::Ident(ident, style) => {
579             return cx.expr_call(sp,
580                                 mk_token_path(cx, sp, "Ident"),
581                                 vec![mk_ident(cx, sp, ident),
582                                      match style {
583                                         ModName => mk_token_path(cx, sp, "ModName"),
584                                         Plain   => mk_token_path(cx, sp, "Plain"),
585                                      }]);
586         }
587
588         token::Lifetime(ident) => {
589             return cx.expr_call(sp,
590                                 mk_token_path(cx, sp, "Lifetime"),
591                                 vec!(mk_ident(cx, sp, ident)));
592         }
593
594         token::DocComment(ident) => {
595             return cx.expr_call(sp,
596                                 mk_token_path(cx, sp, "DocComment"),
597                                 vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))));
598         }
599
600         token::MatchNt(name, kind, namep, kindp) => {
601             return cx.expr_call(sp,
602                                 mk_token_path(cx, sp, "MatchNt"),
603                                 vec!(mk_ident(cx, sp, name),
604                                      mk_ident(cx, sp, kind),
605                                      match namep {
606                                         ModName => mk_token_path(cx, sp, "ModName"),
607                                         Plain   => mk_token_path(cx, sp, "Plain"),
608                                      },
609                                      match kindp {
610                                         ModName => mk_token_path(cx, sp, "ModName"),
611                                         Plain   => mk_token_path(cx, sp, "Plain"),
612                                      }));
613         }
614
615         token::Interpolated(_) => panic!("quote! with interpolated token"),
616
617         _ => ()
618     }
619
620     let name = match *tok {
621         token::Eq           => "Eq",
622         token::Lt           => "Lt",
623         token::Le           => "Le",
624         token::EqEq         => "EqEq",
625         token::Ne           => "Ne",
626         token::Ge           => "Ge",
627         token::Gt           => "Gt",
628         token::AndAnd       => "AndAnd",
629         token::OrOr         => "OrOr",
630         token::Not          => "Not",
631         token::Tilde        => "Tilde",
632         token::At           => "At",
633         token::Dot          => "Dot",
634         token::DotDot       => "DotDot",
635         token::Comma        => "Comma",
636         token::Semi         => "Semi",
637         token::Colon        => "Colon",
638         token::ModSep       => "ModSep",
639         token::RArrow       => "RArrow",
640         token::LArrow       => "LArrow",
641         token::FatArrow     => "FatArrow",
642         token::Pound        => "Pound",
643         token::Dollar       => "Dollar",
644         token::Question     => "Question",
645         token::Underscore   => "Underscore",
646         token::Eof          => "Eof",
647         _                   => panic!("unhandled token in quote!"),
648     };
649     mk_token_path(cx, sp, name)
650 }
651
652 fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<P<ast::Stmt>> {
653     match *tt {
654         TokenTree::Token(sp, SubstNt(ident, _)) => {
655             // tt.extend($ident.to_tokens(ext_cx))
656
657             let e_to_toks =
658                 cx.expr_method_call(sp,
659                                     cx.expr_ident(sp, ident),
660                                     id_ext("to_tokens"),
661                                     vec!(cx.expr_ident(sp, id_ext("ext_cx"))));
662             let e_to_toks =
663                 cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]);
664
665             let e_push =
666                 cx.expr_method_call(sp,
667                                     cx.expr_ident(sp, id_ext("tt")),
668                                     id_ext("extend"),
669                                     vec!(e_to_toks));
670
671             vec!(cx.stmt_expr(e_push))
672         }
673         ref tt @ TokenTree::Token(_, MatchNt(..)) if !matcher => {
674             let mut seq = vec![];
675             for i in 0..tt.len() {
676                 seq.push(tt.get_tt(i));
677             }
678             statements_mk_tts(cx, &seq[..], matcher)
679         }
680         TokenTree::Token(sp, ref tok) => {
681             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
682             let e_tok = cx.expr_call(sp,
683                                      mk_tt_path(cx, sp, "Token"),
684                                      vec!(e_sp, expr_mk_token(cx, sp, tok)));
685             let e_push =
686                 cx.expr_method_call(sp,
687                                     cx.expr_ident(sp, id_ext("tt")),
688                                     id_ext("push"),
689                                     vec!(e_tok));
690             vec!(cx.stmt_expr(e_push))
691         },
692         TokenTree::Delimited(_, ref delimed) => {
693             statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter()
694                 .chain(delimed.tts.iter()
695                                   .flat_map(|tt| statements_mk_tt(cx, tt, matcher)))
696                 .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher))
697                 .collect()
698         },
699         TokenTree::Sequence(sp, ref seq) => {
700             if !matcher {
701                 panic!("TokenTree::Sequence in quote!");
702             }
703
704             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
705
706             let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
707             let mut tts_stmts = vec![stmt_let_tt];
708             tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
709             let e_tts = cx.expr_block(cx.block(sp, tts_stmts,
710                                                    Some(cx.expr_ident(sp, id_ext("tt")))));
711             let e_separator = match seq.separator {
712                 Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
713                 None => cx.expr_none(sp),
714             };
715             let e_op = match seq.op {
716                 ast::ZeroOrMore => mk_ast_path(cx, sp, "ZeroOrMore"),
717                 ast::OneOrMore => mk_ast_path(cx, sp, "OneOrMore"),
718             };
719             let fields = vec![cx.field_imm(sp, id_ext("tts"), e_tts),
720                               cx.field_imm(sp, id_ext("separator"), e_separator),
721                               cx.field_imm(sp, id_ext("op"), e_op),
722                               cx.field_imm(sp, id_ext("num_captures"),
723                                                cx.expr_usize(sp, seq.num_captures))];
724             let seq_path = vec![id_ext("syntax"), id_ext("ast"), id_ext("SequenceRepetition")];
725             let e_seq_struct = cx.expr_struct(sp, cx.path_global(sp, seq_path), fields);
726             let e_rc_new = cx.expr_call_global(sp, vec![id_ext("std"),
727                                                         id_ext("rc"),
728                                                         id_ext("Rc"),
729                                                         id_ext("new")],
730                                                    vec![e_seq_struct]);
731             let e_tok = cx.expr_call(sp,
732                                      mk_tt_path(cx, sp, "Sequence"),
733                                      vec!(e_sp, e_rc_new));
734             let e_push =
735                 cx.expr_method_call(sp,
736                                     cx.expr_ident(sp, id_ext("tt")),
737                                     id_ext("push"),
738                                     vec!(e_tok));
739             vec!(cx.stmt_expr(e_push))
740         }
741     }
742 }
743
744 fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
745                             -> (P<ast::Expr>, Vec<TokenTree>) {
746     // NB: It appears that the main parser loses its mind if we consider
747     // $foo as a SubstNt during the main parse, so we have to re-parse
748     // under quote_depth > 0. This is silly and should go away; the _guess_ is
749     // it has to do with transition away from supporting old-style macros, so
750     // try removing it when enough of them are gone.
751
752     let mut p = cx.new_parser_from_tts(tts);
753     p.quote_depth += 1;
754
755     let cx_expr = panictry!(p.parse_expr_nopanic());
756     if !panictry!(p.eat(&token::Comma)) {
757         panic!(p.fatal("expected token `,`"));
758     }
759
760     let tts = panictry!(p.parse_all_token_trees());
761     p.abort_if_errors();
762
763     (cx_expr, tts)
764 }
765
766 fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<P<ast::Stmt>> {
767     // We also bind a single value, sp, to ext_cx.call_site()
768     //
769     // This causes every span in a token-tree quote to be attributed to the
770     // call site of the extension using the quote. We can't really do much
771     // better since the source of the quote may well be in a library that
772     // was not even parsed by this compilation run, that the user has no
773     // source code for (eg. in libsyntax, which they're just _using_).
774     //
775     // The old quasiquoter had an elaborate mechanism for denoting input
776     // file locations from which quotes originated; unfortunately this
777     // relied on feeding the source string of the quote back into the
778     // compiler (which we don't really want to do) and, in any case, only
779     // pushed the problem a very small step further back: an error
780     // resulting from a parse of the resulting quote is still attributed to
781     // the site the string literal occurred, which was in a source file
782     // _other_ than the one the user has control over. For example, an
783     // error in a quote from the protocol compiler, invoked in user code
784     // using macro_rules! for example, will be attributed to the macro_rules.rs
785     // file in libsyntax, which the user might not even have source to (unless
786     // they happen to have a compiler on hand). Over all, the phase distinction
787     // just makes quotes "hard to attribute". Possibly this could be fixed
788     // by recreating some of the original qq machinery in the tt regime
789     // (pushing fake FileMaps onto the parser to account for original sites
790     // of quotes, for example) but at this point it seems not likely to be
791     // worth the hassle.
792
793     let e_sp = cx.expr_method_call(sp,
794                                    cx.expr_ident(sp, id_ext("ext_cx")),
795                                    id_ext("call_site"),
796                                    Vec::new());
797
798     let stmt_let_sp = cx.stmt_let(sp, false,
799                                   id_ext("_sp"),
800                                   e_sp);
801
802     let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
803
804     vec!(stmt_let_sp, stmt_let_tt)
805 }
806
807 fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec<P<ast::Stmt>> {
808     let mut ss = Vec::new();
809     for tt in tts {
810         ss.extend(statements_mk_tt(cx, tt, matcher));
811     }
812     ss
813 }
814
815 fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])
816               -> (P<ast::Expr>, P<ast::Expr>) {
817     let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
818
819     let mut vector = mk_stmts_let(cx, sp);
820     vector.extend(statements_mk_tts(cx, &tts[..], false));
821     let block = cx.expr_block(
822         cx.block_all(sp,
823                      vector,
824                      Some(cx.expr_ident(sp, id_ext("tt")))));
825
826     (cx_expr, block)
827 }
828
829 fn expand_wrapper(cx: &ExtCtxt,
830                   sp: Span,
831                   cx_expr: P<ast::Expr>,
832                   expr: P<ast::Expr>,
833                   imports: &[&[&str]]) -> P<ast::Expr> {
834     // Explicitly borrow to avoid moving from the invoker (#16992)
835     let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
836     let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);
837
838     let stmts = imports.iter().map(|path| {
839         // make item: `use ...;`
840         let path = path.iter().map(|s| s.to_string()).collect();
841         cx.stmt_item(sp, cx.item_use_glob(sp, ast::Inherited, ids_ext(path)))
842     }).chain(Some(stmt_let_ext_cx)).collect();
843
844     cx.expr_block(cx.block_all(sp, stmts, Some(expr)))
845 }
846
847 fn expand_parse_call(cx: &ExtCtxt,
848                      sp: Span,
849                      parse_method: &str,
850                      arg_exprs: Vec<P<ast::Expr>> ,
851                      tts: &[TokenTree]) -> P<ast::Expr> {
852     let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
853
854     let cfg_call = || cx.expr_method_call(
855         sp, cx.expr_ident(sp, id_ext("ext_cx")),
856         id_ext("cfg"), Vec::new());
857
858     let parse_sess_call = || cx.expr_method_call(
859         sp, cx.expr_ident(sp, id_ext("ext_cx")),
860         id_ext("parse_sess"), Vec::new());
861
862     let new_parser_call =
863         cx.expr_call(sp,
864                      cx.expr_ident(sp, id_ext("new_parser_from_tts")),
865                      vec!(parse_sess_call(), cfg_call(), tts_expr));
866
867     let expr = cx.expr_method_call(sp, new_parser_call, id_ext(parse_method),
868                                    arg_exprs);
869
870     if parse_method == "parse_attribute" {
871         expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"],
872                                                 &["syntax", "parse", "attr"]])
873     } else {
874         expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]])
875     }
876 }