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.
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.
11 use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty};
13 use ext::base::ExtCtxt;
15 use ext::build::AstBuilder;
16 use parse::parser::{Parser, PathStyle};
20 use tokenstream::{self, TokenTree};
22 /// Quasiquoting works via token trees.
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 token::SubstNt interpreted
27 /// as antiquotes (splices).
32 use ext::base::ExtCtxt;
33 use parse::{self, token, classify};
36 use tokenstream::{self, TokenTree};
38 pub use parse::new_parser_from_tts;
39 pub use syntax_pos::{BytePos, Span, DUMMY_SP};
40 pub use codemap::{dummy_spanned};
43 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
46 impl ToTokens for TokenTree {
47 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
52 impl<T: ToTokens> ToTokens for Vec<T> {
53 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
54 self.iter().flat_map(|t| t.to_tokens(cx)).collect()
58 impl<T: ToTokens> ToTokens for Spanned<T> {
59 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
60 // FIXME: use the span?
61 self.node.to_tokens(cx)
65 impl<T: ToTokens> ToTokens for Option<T> {
66 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
68 Some(ref t) => t.to_tokens(cx),
74 impl ToTokens for ast::Ident {
75 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
76 vec![TokenTree::Token(DUMMY_SP, token::Ident(*self))]
80 impl ToTokens for ast::Path {
81 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
82 vec![TokenTree::Token(DUMMY_SP,
83 token::Interpolated(token::NtPath(Box::new(self.clone()))))]
87 impl ToTokens for ast::Ty {
88 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
89 vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
93 impl ToTokens for ast::Block {
94 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
95 vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
99 impl ToTokens for ast::Generics {
100 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
101 vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))]
105 impl ToTokens for ast::WhereClause {
106 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
107 vec![TokenTree::Token(DUMMY_SP,
108 token::Interpolated(token::NtWhereClause(self.clone())))]
112 impl ToTokens for P<ast::Item> {
113 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
114 vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))]
118 impl ToTokens for ast::ImplItem {
119 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
120 vec![TokenTree::Token(self.span,
121 token::Interpolated(token::NtImplItem(P(self.clone()))))]
125 impl ToTokens for P<ast::ImplItem> {
126 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
127 vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
131 impl ToTokens for ast::TraitItem {
132 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
133 vec![TokenTree::Token(self.span,
134 token::Interpolated(token::NtTraitItem(P(self.clone()))))]
138 impl ToTokens for ast::Stmt {
139 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
141 TokenTree::Token(self.span, token::Interpolated(token::NtStmt(P(self.clone()))))
144 // Some statements require a trailing semicolon.
145 if classify::stmt_ends_with_semi(&self.node) {
146 tts.push(TokenTree::Token(self.span, token::Semi));
153 impl ToTokens for P<ast::Expr> {
154 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
155 vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))]
159 impl ToTokens for P<ast::Pat> {
160 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
161 vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))]
165 impl ToTokens for ast::Arm {
166 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
167 vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
171 impl ToTokens for ast::Arg {
172 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
173 vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))]
177 impl ToTokens for P<ast::Block> {
178 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
179 vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))]
183 macro_rules! impl_to_tokens_slice {
184 ($t: ty, $sep: expr) => {
185 impl ToTokens for [$t] {
186 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
188 for (i, x) in self.iter().enumerate() {
190 v.extend_from_slice(&$sep);
192 v.extend(x.to_tokens(cx));
200 impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
201 impl_to_tokens_slice! { P<ast::Item>, [] }
202 impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }
204 impl ToTokens for P<ast::MetaItem> {
205 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
206 vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
210 impl ToTokens for ast::Attribute {
211 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
213 // FIXME: The spans could be better
214 r.push(TokenTree::Token(self.span, token::Pound));
215 if self.node.style == ast::AttrStyle::Inner {
216 r.push(TokenTree::Token(self.span, token::Not));
218 r.push(TokenTree::Delimited(self.span, tokenstream::Delimited {
219 delim: token::Bracket,
220 open_span: self.span,
221 tts: self.node.value.to_tokens(cx),
222 close_span: self.span,
228 impl ToTokens for str {
229 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
230 let lit = ast::LitKind::Str(
231 token::intern_and_get_ident(self), ast::StrStyle::Cooked);
232 dummy_spanned(lit).to_tokens(cx)
236 impl ToTokens for () {
237 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
238 vec![TokenTree::Delimited(DUMMY_SP, tokenstream::Delimited {
242 close_span: DUMMY_SP,
247 impl ToTokens for ast::Lit {
248 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
249 // FIXME: This is wrong
251 id: ast::DUMMY_NODE_ID,
252 node: ast::ExprKind::Lit(P(self.clone())),
254 attrs: ast::ThinVec::new(),
259 impl ToTokens for bool {
260 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
261 dummy_spanned(ast::LitKind::Bool(*self)).to_tokens(cx)
265 impl ToTokens for char {
266 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
267 dummy_spanned(ast::LitKind::Char(*self)).to_tokens(cx)
271 macro_rules! impl_to_tokens_int {
272 (signed, $t:ty, $tag:expr) => (
273 impl ToTokens for $t {
274 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
275 let val = if *self < 0 {
280 let lit = ast::LitKind::Int(val as u64, ast::LitIntType::Signed($tag));
281 let lit = P(ast::Expr {
282 id: ast::DUMMY_NODE_ID,
283 node: ast::ExprKind::Lit(P(dummy_spanned(lit))),
285 attrs: ast::ThinVec::new(),
288 return lit.to_tokens(cx);
291 id: ast::DUMMY_NODE_ID,
292 node: ast::ExprKind::Unary(ast::UnOp::Neg, lit),
294 attrs: ast::ThinVec::new(),
299 (unsigned, $t:ty, $tag:expr) => (
300 impl ToTokens for $t {
301 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
302 let lit = ast::LitKind::Int(*self as u64, ast::LitIntType::Unsigned($tag));
303 dummy_spanned(lit).to_tokens(cx)
309 impl_to_tokens_int! { signed, isize, ast::IntTy::Is }
310 impl_to_tokens_int! { signed, i8, ast::IntTy::I8 }
311 impl_to_tokens_int! { signed, i16, ast::IntTy::I16 }
312 impl_to_tokens_int! { signed, i32, ast::IntTy::I32 }
313 impl_to_tokens_int! { signed, i64, ast::IntTy::I64 }
315 impl_to_tokens_int! { unsigned, usize, ast::UintTy::Us }
316 impl_to_tokens_int! { unsigned, u8, ast::UintTy::U8 }
317 impl_to_tokens_int! { unsigned, u16, ast::UintTy::U16 }
318 impl_to_tokens_int! { unsigned, u32, ast::UintTy::U32 }
319 impl_to_tokens_int! { unsigned, u64, ast::UintTy::U64 }
321 pub trait ExtParseUtils {
322 fn parse_item(&self, s: String) -> P<ast::Item>;
323 fn parse_expr(&self, s: String) -> P<ast::Expr>;
324 fn parse_stmt(&self, s: String) -> ast::Stmt;
325 fn parse_tts(&self, s: String) -> Vec<TokenTree>;
328 impl<'a> ExtParseUtils for ExtCtxt<'a> {
329 fn parse_item(&self, s: String) -> P<ast::Item> {
330 panictry!(parse::parse_item_from_source_str(
331 "<quote expansion>".to_string(),
334 self.parse_sess())).expect("parse error")
337 fn parse_stmt(&self, s: String) -> ast::Stmt {
338 panictry!(parse::parse_stmt_from_source_str(
339 "<quote expansion>".to_string(),
342 self.parse_sess())).expect("parse error")
345 fn parse_expr(&self, s: String) -> P<ast::Expr> {
346 panictry!(parse::parse_expr_from_source_str(
347 "<quote expansion>".to_string(),
353 fn parse_tts(&self, s: String) -> Vec<TokenTree> {
354 panictry!(parse::parse_tts_from_source_str(
355 "<quote expansion>".to_string(),
363 // These panicking parsing functions are used by the quote_*!() syntax extensions,
364 // but shouldn't be used otherwise.
365 pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> {
366 panictry!(parser.parse_expr())
369 pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
370 panictry!(parser.parse_item())
373 pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
374 panictry!(parser.parse_pat())
377 pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
378 panictry!(parser.parse_arm())
381 pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> {
382 panictry!(parser.parse_ty())
385 pub fn parse_stmt_panic(parser: &mut Parser) -> Option<Stmt> {
386 panictry!(parser.parse_stmt())
389 pub fn parse_attribute_panic(parser: &mut Parser, permit_inner: bool) -> ast::Attribute {
390 panictry!(parser.parse_attribute(permit_inner))
393 pub fn parse_arg_panic(parser: &mut Parser) -> Arg {
394 panictry!(parser.parse_arg())
397 pub fn parse_block_panic(parser: &mut Parser) -> P<Block> {
398 panictry!(parser.parse_block())
401 pub fn parse_meta_item_panic(parser: &mut Parser) -> P<ast::MetaItem> {
402 panictry!(parser.parse_meta_item())
405 pub fn parse_path_panic(parser: &mut Parser, mode: PathStyle) -> ast::Path {
406 panictry!(parser.parse_path(mode))
409 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
412 -> Box<base::MacResult+'cx> {
413 let (cx_expr, expr) = expand_tts(cx, sp, tts);
414 let expanded = expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]);
415 base::MacEager::expr(expanded)
418 pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
421 -> Box<base::MacResult+'cx> {
422 let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec!(), tts);
423 base::MacEager::expr(expanded)
426 pub fn expand_quote_item<'cx>(cx: &'cx mut ExtCtxt,
429 -> Box<base::MacResult+'cx> {
430 let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec!(), tts);
431 base::MacEager::expr(expanded)
434 pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
437 -> Box<base::MacResult+'cx> {
438 let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec!(), tts);
439 base::MacEager::expr(expanded)
442 pub fn expand_quote_arm(cx: &mut ExtCtxt,
445 -> Box<base::MacResult+'static> {
446 let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec!(), tts);
447 base::MacEager::expr(expanded)
450 pub fn expand_quote_ty(cx: &mut ExtCtxt,
453 -> Box<base::MacResult+'static> {
454 let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec!(), tts);
455 base::MacEager::expr(expanded)
458 pub fn expand_quote_stmt(cx: &mut ExtCtxt,
461 -> Box<base::MacResult+'static> {
462 let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec!(), tts);
463 base::MacEager::expr(expanded)
466 pub fn expand_quote_attr(cx: &mut ExtCtxt,
469 -> Box<base::MacResult+'static> {
470 let expanded = expand_parse_call(cx, sp, "parse_attribute_panic",
471 vec!(cx.expr_bool(sp, true)), tts);
473 base::MacEager::expr(expanded)
476 pub fn expand_quote_arg(cx: &mut ExtCtxt,
479 -> Box<base::MacResult+'static> {
480 let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts);
481 base::MacEager::expr(expanded)
484 pub fn expand_quote_block(cx: &mut ExtCtxt,
487 -> Box<base::MacResult+'static> {
488 let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts);
489 base::MacEager::expr(expanded)
492 pub fn expand_quote_meta_item(cx: &mut ExtCtxt,
495 -> Box<base::MacResult+'static> {
496 let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts);
497 base::MacEager::expr(expanded)
500 pub fn expand_quote_path(cx: &mut ExtCtxt,
503 -> Box<base::MacResult+'static> {
504 let mode = mk_parser_path(cx, sp, &["PathStyle", "Type"]);
505 let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts);
506 base::MacEager::expr(expanded)
509 pub fn expand_quote_matcher(cx: &mut ExtCtxt,
512 -> Box<base::MacResult+'static> {
513 let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
514 let mut vector = mk_stmts_let(cx, sp);
515 vector.extend(statements_mk_tts(cx, &tts[..], true));
516 vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
517 let block = cx.expr_block(cx.block(sp, vector));
519 let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
520 base::MacEager::expr(expanded)
523 fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> {
524 strs.iter().map(|str| str_to_ident(&(*str))).collect()
527 fn id_ext(str: &str) -> ast::Ident {
531 // Lift an ident to the expr that evaluates to that ident.
532 fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
533 let e_str = cx.expr_str(sp, ident.name.as_str());
534 cx.expr_method_call(sp,
535 cx.expr_ident(sp, id_ext("ext_cx")),
540 // Lift a name to the expr that evaluates to that name
541 fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
542 let e_str = cx.expr_str(sp, ident.name.as_str());
543 cx.expr_method_call(sp,
544 cx.expr_ident(sp, id_ext("ext_cx")),
549 fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
550 let idents = vec!(id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name));
551 cx.expr_path(cx.path_global(sp, idents))
554 fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
555 let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name));
556 cx.expr_path(cx.path_global(sp, idents))
559 fn mk_parser_path(cx: &ExtCtxt, sp: Span, names: &[&str]) -> P<ast::Expr> {
560 let mut idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("parser")];
561 idents.extend(names.iter().cloned().map(id_ext));
562 cx.expr_path(cx.path_global(sp, idents))
565 fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
566 let name = match bop {
567 token::Plus => "Plus",
568 token::Minus => "Minus",
569 token::Star => "Star",
570 token::Slash => "Slash",
571 token::Percent => "Percent",
572 token::Caret => "Caret",
578 mk_token_path(cx, sp, name)
581 fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
582 let name = match delim {
583 token::Paren => "Paren",
584 token::Bracket => "Bracket",
585 token::Brace => "Brace",
587 mk_token_path(cx, sp, name)
590 #[allow(non_upper_case_globals)]
591 fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
592 macro_rules! mk_lit {
593 ($name: expr, $suffix: expr, $($args: expr),*) => {{
594 let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]);
595 let suffix = match $suffix {
596 Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
597 None => cx.expr_none(sp)
599 cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
603 token::BinOp(binop) => {
604 return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop)));
606 token::BinOpEq(binop) => {
607 return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"),
608 vec!(mk_binop(cx, sp, binop)));
611 token::OpenDelim(delim) => {
612 return cx.expr_call(sp, mk_token_path(cx, sp, "OpenDelim"),
613 vec![mk_delim(cx, sp, delim)]);
615 token::CloseDelim(delim) => {
616 return cx.expr_call(sp, mk_token_path(cx, sp, "CloseDelim"),
617 vec![mk_delim(cx, sp, delim)]);
620 token::Literal(token::Byte(i), suf) => {
621 let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
622 return mk_lit!("Byte", suf, e_byte);
625 token::Literal(token::Char(i), suf) => {
626 let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
627 return mk_lit!("Char", suf, e_char);
630 token::Literal(token::Integer(i), suf) => {
631 let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
632 return mk_lit!("Integer", suf, e_int);
635 token::Literal(token::Float(fident), suf) => {
636 let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident));
637 return mk_lit!("Float", suf, e_fident);
640 token::Literal(token::Str_(ident), suf) => {
641 return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))
644 token::Literal(token::StrRaw(ident, n), suf) => {
645 return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)),
646 cx.expr_usize(sp, n))
649 token::Ident(ident) => {
650 return cx.expr_call(sp,
651 mk_token_path(cx, sp, "Ident"),
652 vec![mk_ident(cx, sp, ident)]);
655 token::Lifetime(ident) => {
656 return cx.expr_call(sp,
657 mk_token_path(cx, sp, "Lifetime"),
658 vec!(mk_ident(cx, sp, ident)));
661 token::DocComment(ident) => {
662 return cx.expr_call(sp,
663 mk_token_path(cx, sp, "DocComment"),
664 vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))));
667 token::MatchNt(name, kind) => {
668 return cx.expr_call(sp,
669 mk_token_path(cx, sp, "MatchNt"),
670 vec![mk_ident(cx, sp, name), mk_ident(cx, sp, kind)]);
673 token::Interpolated(_) => panic!("quote! with interpolated token"),
678 let name = match *tok {
682 token::EqEq => "EqEq",
686 token::AndAnd => "AndAnd",
687 token::OrOr => "OrOr",
689 token::Tilde => "Tilde",
692 token::DotDot => "DotDot",
693 token::Comma => "Comma",
694 token::Semi => "Semi",
695 token::Colon => "Colon",
696 token::ModSep => "ModSep",
697 token::RArrow => "RArrow",
698 token::LArrow => "LArrow",
699 token::FatArrow => "FatArrow",
700 token::Pound => "Pound",
701 token::Dollar => "Dollar",
702 token::Question => "Question",
703 token::Underscore => "Underscore",
705 _ => panic!("unhandled token in quote!"),
707 mk_token_path(cx, sp, name)
710 fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stmt> {
712 TokenTree::Token(sp, SubstNt(ident)) => {
713 // tt.extend($ident.to_tokens(ext_cx))
716 cx.expr_method_call(sp,
717 cx.expr_ident(sp, ident),
719 vec!(cx.expr_ident(sp, id_ext("ext_cx"))));
721 cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]);
724 cx.expr_method_call(sp,
725 cx.expr_ident(sp, id_ext("tt")),
729 vec!(cx.stmt_expr(e_push))
731 ref tt @ TokenTree::Token(_, MatchNt(..)) if !matcher => {
732 let mut seq = vec![];
733 for i in 0..tt.len() {
734 seq.push(tt.get_tt(i));
736 statements_mk_tts(cx, &seq[..], matcher)
738 TokenTree::Token(sp, ref tok) => {
739 let e_sp = cx.expr_ident(sp, id_ext("_sp"));
740 let e_tok = cx.expr_call(sp,
741 mk_tt_path(cx, sp, "Token"),
742 vec!(e_sp, expr_mk_token(cx, sp, tok)));
744 cx.expr_method_call(sp,
745 cx.expr_ident(sp, id_ext("tt")),
748 vec!(cx.stmt_expr(e_push))
750 TokenTree::Delimited(_, ref delimed) => {
751 statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter()
752 .chain(delimed.tts.iter()
753 .flat_map(|tt| statements_mk_tt(cx, tt, matcher)))
754 .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher))
757 TokenTree::Sequence(sp, ref seq) => {
759 panic!("TokenTree::Sequence in quote!");
762 let e_sp = cx.expr_ident(sp, id_ext("_sp"));
764 let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
765 let mut tts_stmts = vec![stmt_let_tt];
766 tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
767 tts_stmts.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
768 let e_tts = cx.expr_block(cx.block(sp, tts_stmts));
770 let e_separator = match seq.separator {
771 Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
772 None => cx.expr_none(sp),
774 let e_op = match seq.op {
775 tokenstream::KleeneOp::ZeroOrMore => "ZeroOrMore",
776 tokenstream::KleeneOp::OneOrMore => "OneOrMore",
778 let e_op_idents = vec![
780 id_ext("tokenstream"),
784 let e_op = cx.expr_path(cx.path_global(sp, e_op_idents));
785 let fields = vec![cx.field_imm(sp, id_ext("tts"), e_tts),
786 cx.field_imm(sp, id_ext("separator"), e_separator),
787 cx.field_imm(sp, id_ext("op"), e_op),
788 cx.field_imm(sp, id_ext("num_captures"),
789 cx.expr_usize(sp, seq.num_captures))];
790 let seq_path = vec![id_ext("syntax"),
791 id_ext("tokenstream"),
792 id_ext("SequenceRepetition")];
793 let e_seq_struct = cx.expr_struct(sp, cx.path_global(sp, seq_path), fields);
794 let e_tok = cx.expr_call(sp,
795 mk_tt_path(cx, sp, "Sequence"),
796 vec!(e_sp, e_seq_struct));
798 cx.expr_method_call(sp,
799 cx.expr_ident(sp, id_ext("tt")),
802 vec!(cx.stmt_expr(e_push))
807 fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
808 -> (P<ast::Expr>, Vec<TokenTree>) {
809 // NB: It appears that the main parser loses its mind if we consider
810 // $foo as a SubstNt during the main parse, so we have to re-parse
811 // under quote_depth > 0. This is silly and should go away; the _guess_ is
812 // it has to do with transition away from supporting old-style macros, so
813 // try removing it when enough of them are gone.
815 let mut p = cx.new_parser_from_tts(tts);
818 let cx_expr = panictry!(p.parse_expr());
819 if !p.eat(&token::Comma) {
820 let _ = p.diagnostic().fatal("expected token `,`");
823 let tts = panictry!(p.parse_all_token_trees());
829 fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<ast::Stmt> {
830 // We also bind a single value, sp, to ext_cx.call_site()
832 // This causes every span in a token-tree quote to be attributed to the
833 // call site of the extension using the quote. We can't really do much
834 // better since the source of the quote may well be in a library that
835 // was not even parsed by this compilation run, that the user has no
836 // source code for (eg. in libsyntax, which they're just _using_).
838 // The old quasiquoter had an elaborate mechanism for denoting input
839 // file locations from which quotes originated; unfortunately this
840 // relied on feeding the source string of the quote back into the
841 // compiler (which we don't really want to do) and, in any case, only
842 // pushed the problem a very small step further back: an error
843 // resulting from a parse of the resulting quote is still attributed to
844 // the site the string literal occurred, which was in a source file
845 // _other_ than the one the user has control over. For example, an
846 // error in a quote from the protocol compiler, invoked in user code
847 // using macro_rules! for example, will be attributed to the macro_rules.rs
848 // file in libsyntax, which the user might not even have source to (unless
849 // they happen to have a compiler on hand). Over all, the phase distinction
850 // just makes quotes "hard to attribute". Possibly this could be fixed
851 // by recreating some of the original qq machinery in the tt regime
852 // (pushing fake FileMaps onto the parser to account for original sites
853 // of quotes, for example) but at this point it seems not likely to be
856 let e_sp = cx.expr_method_call(sp,
857 cx.expr_ident(sp, id_ext("ext_cx")),
861 let stmt_let_sp = cx.stmt_let(sp, false,
865 let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
867 vec!(stmt_let_sp, stmt_let_tt)
870 fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec<ast::Stmt> {
871 let mut ss = Vec::new();
873 ss.extend(statements_mk_tt(cx, tt, matcher));
878 fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])
879 -> (P<ast::Expr>, P<ast::Expr>) {
880 let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
882 let mut vector = mk_stmts_let(cx, sp);
883 vector.extend(statements_mk_tts(cx, &tts[..], false));
884 vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
885 let block = cx.expr_block(cx.block(sp, vector));
890 fn expand_wrapper(cx: &ExtCtxt,
892 cx_expr: P<ast::Expr>,
894 imports: &[&[&str]]) -> P<ast::Expr> {
895 // Explicitly borrow to avoid moving from the invoker (#16992)
896 let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
897 let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);
899 let mut stmts = imports.iter().map(|path| {
900 // make item: `use ...;`
901 let path = path.iter().map(|s| s.to_string()).collect();
902 cx.stmt_item(sp, cx.item_use_glob(sp, ast::Visibility::Inherited, ids_ext(path)))
903 }).chain(Some(stmt_let_ext_cx)).collect::<Vec<_>>();
904 stmts.push(cx.stmt_expr(expr));
906 cx.expr_block(cx.block(sp, stmts))
909 fn expand_parse_call(cx: &ExtCtxt,
912 arg_exprs: Vec<P<ast::Expr>> ,
913 tts: &[TokenTree]) -> P<ast::Expr> {
914 let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
916 let cfg_call = || cx.expr_method_call(
917 sp, cx.expr_ident(sp, id_ext("ext_cx")),
918 id_ext("cfg"), Vec::new());
920 let parse_sess_call = || cx.expr_method_call(
921 sp, cx.expr_ident(sp, id_ext("ext_cx")),
922 id_ext("parse_sess"), Vec::new());
924 let new_parser_call =
926 cx.expr_ident(sp, id_ext("new_parser_from_tts")),
927 vec!(parse_sess_call(), cfg_call(), tts_expr));
929 let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)];
930 let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)];
931 args.extend(arg_exprs);
932 let expr = cx.expr_call_global(sp, path, args);
934 if parse_method == "parse_attribute" {
935 expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"],
936 &["syntax", "parse", "attr"]])
938 expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]])