1 use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty};
2 use source_map::respan;
3 use syntax_pos::{Span, DUMMY_SP};
4 use ext::base::ExtCtxt;
6 use ext::build::AstBuilder;
7 use parse::parser::{Parser, PathStyle};
10 use tokenstream::{DelimSpan, TokenStream, TokenTree};
12 /// Quasiquoting works via token trees.
14 /// This is registered as a set of expression syntax extension called quote!
15 /// that lifts its argument token-tree to an AST representing the
16 /// construction of the same token tree, with `token::SubstNt` interpreted
17 /// as antiquotes (splices).
21 use source_map::Spanned;
22 use ext::base::ExtCtxt;
23 use parse::{self, classify};
24 use parse::token::{self, Token};
29 use tokenstream::{DelimSpan, TokenTree, TokenStream};
31 pub use parse::new_parser_from_tts;
32 pub use syntax_pos::{BytePos, Span, DUMMY_SP, FileName};
33 pub use source_map::{dummy_spanned};
36 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
39 impl ToTokens for TokenTree {
40 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
45 impl<T: ToTokens> ToTokens for Vec<T> {
46 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
47 self.iter().flat_map(|t| t.to_tokens(cx)).collect()
51 impl<T: ToTokens> ToTokens for Spanned<T> {
52 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
53 // FIXME: use the span?
54 self.node.to_tokens(cx)
58 impl<T: ToTokens> ToTokens for Option<T> {
59 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
61 Some(ref t) => t.to_tokens(cx),
67 impl ToTokens for ast::Ident {
68 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
69 vec![TokenTree::Token(self.span, Token::from_ast_ident(*self))]
73 impl ToTokens for ast::Path {
74 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
75 let nt = token::NtPath(self.clone());
76 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
80 impl ToTokens for ast::Ty {
81 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
82 let nt = token::NtTy(P(self.clone()));
83 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
87 impl ToTokens for ast::Block {
88 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
89 let nt = token::NtBlock(P(self.clone()));
90 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
94 impl ToTokens for ast::Generics {
95 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
96 let nt = token::NtGenerics(self.clone());
97 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
101 impl ToTokens for ast::WhereClause {
102 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
103 let nt = token::NtWhereClause(self.clone());
104 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
108 impl ToTokens for P<ast::Item> {
109 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
110 let nt = token::NtItem(self.clone());
111 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
115 impl ToTokens for ast::ImplItem {
116 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
117 let nt = token::NtImplItem(self.clone());
118 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
122 impl ToTokens for P<ast::ImplItem> {
123 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
124 let nt = token::NtImplItem((**self).clone());
125 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
129 impl ToTokens for ast::TraitItem {
130 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
131 let nt = token::NtTraitItem(self.clone());
132 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
136 impl ToTokens for ast::Stmt {
137 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
138 let nt = token::NtStmt(self.clone());
139 let mut tts = vec![TokenTree::Token(self.span, Token::interpolated(nt))];
141 // Some statements require a trailing semicolon.
142 if classify::stmt_ends_with_semi(&self.node) {
143 tts.push(TokenTree::Token(self.span, token::Semi));
150 impl ToTokens for P<ast::Expr> {
151 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
152 let nt = token::NtExpr(self.clone());
153 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
157 impl ToTokens for P<ast::Pat> {
158 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
159 let nt = token::NtPat(self.clone());
160 vec![TokenTree::Token(self.span, Token::interpolated(nt))]
164 impl ToTokens for ast::Arm {
165 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
166 let nt = token::NtArm(self.clone());
167 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
171 impl ToTokens for ast::Arg {
172 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
173 let nt = token::NtArg(self.clone());
174 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
178 impl ToTokens for P<ast::Block> {
179 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
180 let nt = token::NtBlock(self.clone());
181 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
185 impl ToTokens for ast::Lifetime {
186 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
187 vec![TokenTree::Token(self.ident.span, token::Lifetime(self.ident))]
191 macro_rules! impl_to_tokens_slice {
192 ($t: ty, $sep: expr) => {
193 impl ToTokens for [$t] {
194 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
196 for (i, x) in self.iter().enumerate() {
198 v.extend_from_slice(&$sep);
200 v.extend(x.to_tokens(cx));
208 impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
209 impl_to_tokens_slice! { P<ast::Item>, [] }
210 impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }
212 impl ToTokens for ast::MetaItem {
213 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
214 let nt = token::NtMeta(self.clone());
215 vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
219 impl ToTokens for ast::Attribute {
220 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
222 // FIXME: The spans could be better
223 r.push(TokenTree::Token(self.span, token::Pound));
224 if self.style == ast::AttrStyle::Inner {
225 r.push(TokenTree::Token(self.span, token::Not));
227 let mut inner = Vec::new();
228 for (i, segment) in self.path.segments.iter().enumerate() {
230 inner.push(TokenTree::Token(self.span, token::Colon).into());
232 inner.push(TokenTree::Token(
233 self.span, token::Token::from_ast_ident(segment.ident)
236 inner.push(self.tokens.clone());
238 let delim_span = DelimSpan::from_single(self.span);
239 r.push(TokenTree::Delimited(
240 delim_span, token::Bracket, TokenStream::new(inner).into()
246 impl ToTokens for str {
247 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
248 let lit = ast::LitKind::Str(Symbol::intern(self), ast::StrStyle::Cooked);
249 dummy_spanned(lit).to_tokens(cx)
253 impl ToTokens for () {
254 fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
256 TokenTree::Delimited(DelimSpan::dummy(), token::Paren, TokenStream::empty().into())
261 impl ToTokens for ast::Lit {
262 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
263 // FIXME: This is wrong
265 id: ast::DUMMY_NODE_ID,
266 node: ast::ExprKind::Lit(self.clone()),
268 attrs: ThinVec::new(),
273 impl ToTokens for bool {
274 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
275 dummy_spanned(ast::LitKind::Bool(*self)).to_tokens(cx)
279 impl ToTokens for char {
280 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
281 dummy_spanned(ast::LitKind::Char(*self)).to_tokens(cx)
285 macro_rules! impl_to_tokens_int {
286 (signed, $t:ty, $tag:expr) => (
287 impl ToTokens for $t {
288 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
289 let val = if *self < 0 {
294 let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag));
295 let lit = P(ast::Expr {
296 id: ast::DUMMY_NODE_ID,
297 node: ast::ExprKind::Lit(dummy_spanned(lit)),
299 attrs: ThinVec::new(),
302 return lit.to_tokens(cx);
305 id: ast::DUMMY_NODE_ID,
306 node: ast::ExprKind::Unary(ast::UnOp::Neg, lit),
308 attrs: ThinVec::new(),
313 (unsigned, $t:ty, $tag:expr) => (
314 impl ToTokens for $t {
315 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
316 let lit = ast::LitKind::Int(*self as u128, ast::LitIntType::Unsigned($tag));
317 dummy_spanned(lit).to_tokens(cx)
323 impl_to_tokens_int! { signed, isize, ast::IntTy::Isize }
324 impl_to_tokens_int! { signed, i8, ast::IntTy::I8 }
325 impl_to_tokens_int! { signed, i16, ast::IntTy::I16 }
326 impl_to_tokens_int! { signed, i32, ast::IntTy::I32 }
327 impl_to_tokens_int! { signed, i64, ast::IntTy::I64 }
329 impl_to_tokens_int! { unsigned, usize, ast::UintTy::Usize }
330 impl_to_tokens_int! { unsigned, u8, ast::UintTy::U8 }
331 impl_to_tokens_int! { unsigned, u16, ast::UintTy::U16 }
332 impl_to_tokens_int! { unsigned, u32, ast::UintTy::U32 }
333 impl_to_tokens_int! { unsigned, u64, ast::UintTy::U64 }
335 pub trait ExtParseUtils {
336 fn parse_item(&self, s: String) -> P<ast::Item>;
337 fn parse_expr(&self, s: String) -> P<ast::Expr>;
338 fn parse_stmt(&self, s: String) -> ast::Stmt;
339 fn parse_tts(&self, s: String) -> Vec<TokenTree>;
342 impl<'a> ExtParseUtils for ExtCtxt<'a> {
343 fn parse_item(&self, s: String) -> P<ast::Item> {
344 panictry!(parse::parse_item_from_source_str(
345 FileName::quote_expansion_source_code(&s),
347 self.parse_sess())).expect("parse error")
350 fn parse_stmt(&self, s: String) -> ast::Stmt {
351 panictry!(parse::parse_stmt_from_source_str(
352 FileName::quote_expansion_source_code(&s),
354 self.parse_sess())).expect("parse error")
357 fn parse_expr(&self, s: String) -> P<ast::Expr> {
358 panictry!(parse::parse_expr_from_source_str(
359 FileName::quote_expansion_source_code(&s),
364 fn parse_tts(&self, s: String) -> Vec<TokenTree> {
365 let source_name = FileName::quote_expansion_source_code(&s);
366 parse::parse_stream_from_source_str(source_name, s, self.parse_sess(), None)
367 .into_trees().collect()
372 // Replaces `Token::OpenDelim .. Token::CloseDelim` with `TokenTree::Delimited(..)`.
373 pub fn unflatten(tts: Vec<TokenTree>) -> Vec<TokenTree> {
374 let mut results = Vec::new();
375 let mut result = Vec::new();
376 let mut open_span = DUMMY_SP;
379 TokenTree::Token(span, token::OpenDelim(..)) => {
381 results.push(::std::mem::replace(&mut result, Vec::new()));
383 TokenTree::Token(span, token::CloseDelim(delim)) => {
384 let delim_span = DelimSpan::from_pair(open_span, span);
385 let tree = TokenTree::Delimited(
388 result.into_iter().map(TokenStream::from).collect::<TokenStream>().into(),
390 result = results.pop().unwrap();
393 tree => result.push(tree),
399 // These panicking parsing functions are used by the quote_*!() syntax extensions,
400 // but shouldn't be used otherwise.
401 pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> {
402 panictry!(parser.parse_expr())
405 pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
406 panictry!(parser.parse_item())
409 pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
410 panictry!(parser.parse_pat(None))
413 pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
414 panictry!(parser.parse_arm())
417 pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> {
418 panictry!(parser.parse_ty())
421 pub fn parse_stmt_panic(parser: &mut Parser) -> Option<Stmt> {
422 panictry!(parser.parse_stmt())
425 pub fn parse_attribute_panic(parser: &mut Parser, permit_inner: bool) -> ast::Attribute {
426 panictry!(parser.parse_attribute(permit_inner))
429 pub fn parse_arg_panic(parser: &mut Parser) -> Arg {
430 panictry!(parser.parse_arg())
433 pub fn parse_block_panic(parser: &mut Parser) -> P<Block> {
434 panictry!(parser.parse_block())
437 pub fn parse_meta_item_panic(parser: &mut Parser) -> ast::MetaItem {
438 panictry!(parser.parse_meta_item())
441 pub fn parse_path_panic(parser: &mut Parser, mode: PathStyle) -> ast::Path {
442 panictry!(parser.parse_path(mode))
445 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
448 -> Box<dyn base::MacResult+'cx> {
449 let (cx_expr, expr) = expand_tts(cx, sp, tts);
450 let expanded = expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]);
451 base::MacEager::expr(expanded)
454 pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
457 -> Box<dyn base::MacResult+'cx> {
458 let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec![], tts);
459 base::MacEager::expr(expanded)
462 pub fn expand_quote_item<'cx>(cx: &'cx mut ExtCtxt,
465 -> Box<dyn base::MacResult+'cx> {
466 let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec![], tts);
467 base::MacEager::expr(expanded)
470 pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
473 -> Box<dyn base::MacResult+'cx> {
474 let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec![], tts);
475 base::MacEager::expr(expanded)
478 pub fn expand_quote_arm(cx: &mut ExtCtxt,
481 -> Box<dyn base::MacResult+'static> {
482 let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec![], tts);
483 base::MacEager::expr(expanded)
486 pub fn expand_quote_ty(cx: &mut ExtCtxt,
489 -> Box<dyn base::MacResult+'static> {
490 let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec![], tts);
491 base::MacEager::expr(expanded)
494 pub fn expand_quote_stmt(cx: &mut ExtCtxt,
497 -> Box<dyn base::MacResult+'static> {
498 let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec![], tts);
499 base::MacEager::expr(expanded)
502 pub fn expand_quote_attr(cx: &mut ExtCtxt,
505 -> Box<dyn base::MacResult+'static> {
506 let expanded = expand_parse_call(cx, sp, "parse_attribute_panic",
507 vec![cx.expr_bool(sp, true)], tts);
509 base::MacEager::expr(expanded)
512 pub fn expand_quote_arg(cx: &mut ExtCtxt,
515 -> Box<dyn base::MacResult+'static> {
516 let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec![], tts);
517 base::MacEager::expr(expanded)
520 pub fn expand_quote_block(cx: &mut ExtCtxt,
523 -> Box<dyn base::MacResult+'static> {
524 let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec![], tts);
525 base::MacEager::expr(expanded)
528 pub fn expand_quote_meta_item(cx: &mut ExtCtxt,
531 -> Box<dyn base::MacResult+'static> {
532 let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec![], tts);
533 base::MacEager::expr(expanded)
536 pub fn expand_quote_path(cx: &mut ExtCtxt,
539 -> Box<dyn base::MacResult+'static> {
540 let mode = mk_parser_path(cx, sp, &["PathStyle", "Type"]);
541 let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec![mode], tts);
542 base::MacEager::expr(expanded)
545 fn ids_ext(strs: Vec<String>) -> Vec<ast::Ident> {
546 strs.iter().map(|s| ast::Ident::from_str(s)).collect()
549 fn id_ext(s: &str) -> ast::Ident {
550 ast::Ident::from_str(s)
553 // Lift an ident to the expr that evaluates to that ident.
554 fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
555 let e_str = cx.expr_str(sp, ident.name);
556 cx.expr_method_call(sp,
557 cx.expr_ident(sp, id_ext("ext_cx")),
562 // Lift a name to the expr that evaluates to that name
563 fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
564 let e_str = cx.expr_str(sp, ident.name);
565 cx.expr_method_call(sp,
566 cx.expr_ident(sp, id_ext("ext_cx")),
571 fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
572 let idents = vec![id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name)];
573 cx.expr_path(cx.path_global(sp, idents))
576 fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
577 let idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name)];
578 cx.expr_path(cx.path_global(sp, idents))
581 fn mk_parser_path(cx: &ExtCtxt, sp: Span, names: &[&str]) -> P<ast::Expr> {
582 let mut idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("parser")];
583 idents.extend(names.iter().cloned().map(id_ext));
584 cx.expr_path(cx.path_global(sp, idents))
587 fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
588 let name = match bop {
589 token::Plus => "Plus",
590 token::Minus => "Minus",
591 token::Star => "Star",
592 token::Slash => "Slash",
593 token::Percent => "Percent",
594 token::Caret => "Caret",
600 mk_token_path(cx, sp, name)
603 fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
604 let name = match delim {
605 token::Paren => "Paren",
606 token::Bracket => "Bracket",
607 token::Brace => "Brace",
608 token::NoDelim => "NoDelim",
610 mk_token_path(cx, sp, name)
613 #[allow(non_upper_case_globals)]
614 fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
615 macro_rules! mk_lit {
616 ($name: expr, $suffix: expr, $content: expr $(, $count: expr)*) => {{
617 let name = mk_name(cx, sp, ast::Ident::with_empty_ctxt($content));
618 let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![
619 name $(, cx.expr_u16(sp, $count))*
621 let suffix = match $suffix {
622 Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
623 None => cx.expr_none(sp)
625 cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
629 let name = match *tok {
630 token::BinOp(binop) => {
631 return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec![mk_binop(cx, sp, binop)]);
633 token::BinOpEq(binop) => {
634 return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"),
635 vec![mk_binop(cx, sp, binop)]);
638 token::OpenDelim(delim) => {
639 return cx.expr_call(sp, mk_token_path(cx, sp, "OpenDelim"),
640 vec![mk_delim(cx, sp, delim)]);
642 token::CloseDelim(delim) => {
643 return cx.expr_call(sp, mk_token_path(cx, sp, "CloseDelim"),
644 vec![mk_delim(cx, sp, delim)]);
647 token::Literal(token::Byte(i), suf) => return mk_lit!("Byte", suf, i),
648 token::Literal(token::Char(i), suf) => return mk_lit!("Char", suf, i),
649 token::Literal(token::Integer(i), suf) => return mk_lit!("Integer", suf, i),
650 token::Literal(token::Float(i), suf) => return mk_lit!("Float", suf, i),
651 token::Literal(token::Str_(i), suf) => return mk_lit!("Str_", suf, i),
652 token::Literal(token::StrRaw(i, n), suf) => return mk_lit!("StrRaw", suf, i, n),
653 token::Literal(token::ByteStr(i), suf) => return mk_lit!("ByteStr", suf, i),
654 token::Literal(token::ByteStrRaw(i, n), suf) => return mk_lit!("ByteStrRaw", suf, i, n),
656 token::Ident(ident, is_raw) => {
657 return cx.expr_call(sp,
658 mk_token_path(cx, sp, "Ident"),
659 vec![mk_ident(cx, sp, ident), cx.expr_bool(sp, is_raw)]);
662 token::Lifetime(ident) => {
663 return cx.expr_call(sp,
664 mk_token_path(cx, sp, "Lifetime"),
665 vec![mk_ident(cx, sp, ident)]);
668 token::DocComment(ident) => {
669 return cx.expr_call(sp,
670 mk_token_path(cx, sp, "DocComment"),
671 vec![mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))]);
674 token::Interpolated(_) => {
675 cx.span_err(sp, "quote! with interpolated token");
683 token::EqEq => "EqEq",
687 token::AndAnd => "AndAnd",
688 token::OrOr => "OrOr",
690 token::Tilde => "Tilde",
693 token::DotDot => "DotDot",
694 token::DotDotDot => "DotDotDot",
695 token::DotDotEq => "DotDotEq",
696 token::Comma => "Comma",
697 token::Semi => "Semi",
698 token::Colon => "Colon",
699 token::ModSep => "ModSep",
700 token::RArrow => "RArrow",
701 token::LArrow => "LArrow",
702 token::FatArrow => "FatArrow",
703 token::Pound => "Pound",
704 token::Dollar => "Dollar",
705 token::Question => "Question",
706 token::SingleQuote => "SingleQuote",
709 token::Whitespace | token::Comment | token::Shebang(_) => {
710 panic!("unhandled token in quote!");
713 mk_token_path(cx, sp, name)
716 fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, quoted: bool) -> Vec<ast::Stmt> {
718 TokenTree::Token(sp, token::Ident(ident, _)) if quoted => {
719 // tt.extend($ident.to_tokens(ext_cx))
722 cx.expr_method_call(sp,
723 cx.expr_ident(sp, ident),
725 vec![cx.expr_ident(sp, id_ext("ext_cx"))]);
727 cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]);
730 cx.expr_method_call(sp,
731 cx.expr_ident(sp, id_ext("tt")),
735 vec![cx.stmt_expr(e_push)]
737 TokenTree::Token(sp, ref tok) => {
738 let e_sp = cx.expr_ident(sp, id_ext("_sp"));
739 let e_tok = cx.expr_call(sp,
740 mk_tt_path(cx, sp, "Token"),
741 vec![e_sp, expr_mk_token(cx, sp, tok)]);
743 cx.expr_method_call(sp,
744 cx.expr_ident(sp, id_ext("tt")),
747 vec![cx.stmt_expr(e_push)]
749 TokenTree::Delimited(span, delim, ref tts) => {
750 let mut stmts = statements_mk_tt(cx, &TokenTree::open_tt(span.open, delim), false);
751 stmts.extend(statements_mk_tts(cx, tts.stream()));
752 stmts.extend(statements_mk_tt(cx, &TokenTree::close_tt(span.close, delim), false));
758 fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
759 -> (P<ast::Expr>, Vec<TokenTree>) {
760 let mut p = cx.new_parser_from_tts(tts);
762 let cx_expr = panictry!(p.parse_expr());
763 if !p.eat(&token::Comma) {
764 let _ = p.diagnostic().fatal("expected token `,`");
767 let tts = panictry!(p.parse_all_token_trees());
773 fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<ast::Stmt> {
774 // We also bind a single value, sp, to ext_cx.call_site()
776 // This causes every span in a token-tree quote to be attributed to the
777 // call site of the extension using the quote. We can't really do much
778 // better since the source of the quote may well be in a library that
779 // was not even parsed by this compilation run, that the user has no
780 // source code for (eg. in libsyntax, which they're just _using_).
782 // The old quasiquoter had an elaborate mechanism for denoting input
783 // file locations from which quotes originated; unfortunately this
784 // relied on feeding the source string of the quote back into the
785 // compiler (which we don't really want to do) and, in any case, only
786 // pushed the problem a very small step further back: an error
787 // resulting from a parse of the resulting quote is still attributed to
788 // the site the string literal occurred, which was in a source file
789 // _other_ than the one the user has control over. For example, an
790 // error in a quote from the protocol compiler, invoked in user code
791 // using macro_rules! for example, will be attributed to the macro_rules.rs
792 // file in libsyntax, which the user might not even have source to (unless
793 // they happen to have a compiler on hand). Over all, the phase distinction
794 // just makes quotes "hard to attribute". Possibly this could be fixed
795 // by recreating some of the original qq machinery in the tt regime
796 // (pushing fake SourceFiles onto the parser to account for original sites
797 // of quotes, for example) but at this point it seems not likely to be
800 let e_sp = cx.expr_method_call(sp,
801 cx.expr_ident(sp, id_ext("ext_cx")),
805 let stmt_let_sp = cx.stmt_let(sp, false,
809 let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
811 vec![stmt_let_sp, stmt_let_tt]
814 fn statements_mk_tts(cx: &ExtCtxt, tts: TokenStream) -> Vec<ast::Stmt> {
815 let mut ss = Vec::new();
816 let mut quoted = false;
817 for tt in tts.into_trees() {
819 TokenTree::Token(_, token::Dollar) if !quoted => true,
821 ss.extend(statements_mk_tt(cx, &tt, quoted));
829 fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> (P<ast::Expr>, P<ast::Expr>) {
830 let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
832 let mut vector = mk_stmts_let(cx, sp);
833 vector.extend(statements_mk_tts(cx, tts.iter().cloned().collect()));
834 vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
835 let block = cx.expr_block(cx.block(sp, vector));
836 let unflatten = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext("unflatten")];
838 (cx_expr, cx.expr_call_global(sp, unflatten, vec![block]))
841 fn expand_wrapper(cx: &ExtCtxt,
843 cx_expr: P<ast::Expr>,
845 imports: &[&[&str]]) -> P<ast::Expr> {
846 // Explicitly borrow to avoid moving from the invoker (#16992)
847 let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
848 let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);
850 let mut stmts = imports.iter().map(|path| {
851 // make item: `use ...;`
852 let path = path.iter().map(|s| s.to_string()).collect();
853 let use_item = cx.item_use_glob(
855 respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited),
858 cx.stmt_item(sp, use_item)
859 }).chain(Some(stmt_let_ext_cx)).collect::<Vec<_>>();
860 stmts.push(cx.stmt_expr(expr));
862 cx.expr_block(cx.block(sp, stmts))
865 fn expand_parse_call(cx: &ExtCtxt,
868 arg_exprs: Vec<P<ast::Expr>> ,
869 tts: &[TokenTree]) -> P<ast::Expr> {
870 let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
872 let parse_sess_call = || cx.expr_method_call(
873 sp, cx.expr_ident(sp, id_ext("ext_cx")),
874 id_ext("parse_sess"), Vec::new());
876 let new_parser_call =
878 cx.expr_ident(sp, id_ext("new_parser_from_tts")),
879 vec![parse_sess_call(), tts_expr]);
881 let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)];
882 let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)];
883 args.extend(arg_exprs);
884 let expr = cx.expr_call_global(sp, path, args);
886 if parse_method == "parse_attribute" {
887 expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"],
888 &["syntax", "parse", "attr"]])
890 expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]])