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}
;
19 use tokenstream
::{TokenStream, 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}
;
38 use tokenstream
::{self, TokenTree, TokenStream}
;
40 pub use parse
::new_parser_from_tts
;
41 pub use syntax_pos
::{BytePos, Span, DUMMY_SP}
;
42 pub use codemap
::{dummy_spanned}
;
45 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
>;
48 impl ToTokens
for TokenTree
{
49 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
54 impl<T
: ToTokens
> ToTokens
for Vec
<T
> {
55 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
56 self.iter().flat_map(|t
| t
.to_tokens(cx
)).collect()
60 impl<T
: ToTokens
> ToTokens
for Spanned
<T
> {
61 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
62 // FIXME: use the span?
63 self.node
.to_tokens(cx
)
67 impl<T
: ToTokens
> ToTokens
for Option
<T
> {
68 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
70 Some(ref t
) => t
.to_tokens(cx
),
76 impl ToTokens
for ast
::Ident
{
77 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
78 vec
![TokenTree
::Token(DUMMY_SP
, token
::Ident(*self))]
82 impl ToTokens
for ast
::Path
{
83 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
84 let nt
= token
::NtPath(self.clone());
85 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
89 impl ToTokens
for ast
::Ty
{
90 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
91 let nt
= token
::NtTy(P(self.clone()));
92 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
96 impl ToTokens
for ast
::Block
{
97 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
98 let nt
= token
::NtBlock(P(self.clone()));
99 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
103 impl ToTokens
for ast
::Generics
{
104 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
105 let nt
= token
::NtGenerics(self.clone());
106 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
110 impl ToTokens
for ast
::WhereClause
{
111 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
112 let nt
= token
::NtWhereClause(self.clone());
113 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
117 impl ToTokens
for P
<ast
::Item
> {
118 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
119 let nt
= token
::NtItem(self.clone());
120 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
124 impl ToTokens
for ast
::ImplItem
{
125 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
126 let nt
= token
::NtImplItem(self.clone());
127 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
131 impl ToTokens
for P
<ast
::ImplItem
> {
132 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
133 let nt
= token
::NtImplItem((**self).clone());
134 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
138 impl ToTokens
for ast
::TraitItem
{
139 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
140 let nt
= token
::NtTraitItem(self.clone());
141 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
145 impl ToTokens
for ast
::Stmt
{
146 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
147 let nt
= token
::NtStmt(self.clone());
148 let mut tts
= vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))];
150 // Some statements require a trailing semicolon.
151 if classify
::stmt_ends_with_semi(&self.node
) {
152 tts
.push(TokenTree
::Token(self.span
, token
::Semi
));
159 impl ToTokens
for P
<ast
::Expr
> {
160 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
161 let nt
= token
::NtExpr(self.clone());
162 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
166 impl ToTokens
for P
<ast
::Pat
> {
167 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
168 let nt
= token
::NtPat(self.clone());
169 vec
![TokenTree
::Token(self.span
, token
::Interpolated(Rc
::new(nt
)))]
173 impl ToTokens
for ast
::Arm
{
174 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
175 let nt
= token
::NtArm(self.clone());
176 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
180 impl ToTokens
for ast
::Arg
{
181 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
182 let nt
= token
::NtArg(self.clone());
183 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
187 impl ToTokens
for P
<ast
::Block
> {
188 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
189 let nt
= token
::NtBlock(self.clone());
190 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
194 macro_rules
! impl_to_tokens_slice
{
195 ($t
: ty
, $sep
: expr
) => {
196 impl ToTokens
for [$t
] {
197 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
199 for (i
, x
) in self.iter().enumerate() {
201 v
.extend_from_slice(&$sep
);
203 v
.extend(x
.to_tokens(cx
));
211 impl_to_tokens_slice
! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
212 impl_to_tokens_slice
! { P<ast::Item>, [] }
213 impl_to_tokens_slice
! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }
215 impl ToTokens
for ast
::MetaItem
{
216 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
217 let nt
= token
::NtMeta(self.clone());
218 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(Rc
::new(nt
)))]
222 impl ToTokens
for ast
::Attribute
{
223 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
225 // FIXME: The spans could be better
226 r
.push(TokenTree
::Token(self.span
, token
::Pound
));
227 if self.style
== ast
::AttrStyle
::Inner
{
228 r
.push(TokenTree
::Token(self.span
, token
::Not
));
230 r
.push(TokenTree
::Delimited(self.span
, tokenstream
::Delimited
{
231 delim
: token
::Bracket
,
232 tts
: self.value
.to_tokens(cx
).into_iter().collect
::<TokenStream
>().into(),
238 impl ToTokens
for str {
239 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
240 let lit
= ast
::LitKind
::Str(Symbol
::intern(self), ast
::StrStyle
::Cooked
);
241 dummy_spanned(lit
).to_tokens(cx
)
245 impl ToTokens
for () {
246 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
247 vec
![TokenTree
::Delimited(DUMMY_SP
, tokenstream
::Delimited
{
249 tts
: TokenStream
::empty().into(),
254 impl ToTokens
for ast
::Lit
{
255 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
256 // FIXME: This is wrong
258 id
: ast
::DUMMY_NODE_ID
,
259 node
: ast
::ExprKind
::Lit(P(self.clone())),
261 attrs
: ast
::ThinVec
::new(),
266 impl ToTokens
for bool
{
267 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
268 dummy_spanned(ast
::LitKind
::Bool(*self)).to_tokens(cx
)
272 impl ToTokens
for char {
273 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
274 dummy_spanned(ast
::LitKind
::Char(*self)).to_tokens(cx
)
278 macro_rules
! impl_to_tokens_int
{
279 (signed
, $t
:ty
, $tag
:expr
) => (
280 impl ToTokens
for $t
{
281 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
282 let val
= if *self < 0 {
287 let lit
= ast
::LitKind
::Int(val
as u128
, ast
::LitIntType
::Signed($tag
));
288 let lit
= P(ast
::Expr
{
289 id
: ast
::DUMMY_NODE_ID
,
290 node
: ast
::ExprKind
::Lit(P(dummy_spanned(lit
))),
292 attrs
: ast
::ThinVec
::new(),
295 return lit
.to_tokens(cx
);
298 id
: ast
::DUMMY_NODE_ID
,
299 node
: ast
::ExprKind
::Unary(ast
::UnOp
::Neg
, lit
),
301 attrs
: ast
::ThinVec
::new(),
306 (unsigned
, $t
:ty
, $tag
:expr
) => (
307 impl ToTokens
for $t
{
308 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
309 let lit
= ast
::LitKind
::Int(*self as u128
, ast
::LitIntType
::Unsigned($tag
));
310 dummy_spanned(lit
).to_tokens(cx
)
316 impl_to_tokens_int
! { signed, isize, ast::IntTy::Is }
317 impl_to_tokens_int
! { signed, i8, ast::IntTy::I8 }
318 impl_to_tokens_int
! { signed, i16, ast::IntTy::I16 }
319 impl_to_tokens_int
! { signed, i32, ast::IntTy::I32 }
320 impl_to_tokens_int
! { signed, i64, ast::IntTy::I64 }
322 impl_to_tokens_int
! { unsigned, usize, ast::UintTy::Us }
323 impl_to_tokens_int
! { unsigned, u8, ast::UintTy::U8 }
324 impl_to_tokens_int
! { unsigned, u16, ast::UintTy::U16 }
325 impl_to_tokens_int
! { unsigned, u32, ast::UintTy::U32 }
326 impl_to_tokens_int
! { unsigned, u64, ast::UintTy::U64 }
328 pub trait ExtParseUtils
{
329 fn parse_item(&self, s
: String
) -> P
<ast
::Item
>;
330 fn parse_expr(&self, s
: String
) -> P
<ast
::Expr
>;
331 fn parse_stmt(&self, s
: String
) -> ast
::Stmt
;
332 fn parse_tts(&self, s
: String
) -> Vec
<TokenTree
>;
335 impl<'a
> ExtParseUtils
for ExtCtxt
<'a
> {
336 fn parse_item(&self, s
: String
) -> P
<ast
::Item
> {
337 panictry
!(parse
::parse_item_from_source_str(
338 "<quote expansion>".to_string(),
340 self.parse_sess())).expect("parse error")
343 fn parse_stmt(&self, s
: String
) -> ast
::Stmt
{
344 panictry
!(parse
::parse_stmt_from_source_str(
345 "<quote expansion>".to_string(),
347 self.parse_sess())).expect("parse error")
350 fn parse_expr(&self, s
: String
) -> P
<ast
::Expr
> {
351 panictry
!(parse
::parse_expr_from_source_str(
352 "<quote expansion>".to_string(),
357 fn parse_tts(&self, s
: String
) -> Vec
<TokenTree
> {
358 let source_name
= "<quote expansion>".to_owned();
359 parse
::parse_stream_from_source_str(source_name
, s
, self.parse_sess())
360 .into_trees().collect()
365 // Replaces `Token::OpenDelim .. Token::CloseDelim` with `TokenTree::Delimited(..)`.
366 pub fn unflatten(tts
: Vec
<TokenTree
>) -> Vec
<TokenTree
> {
367 use tokenstream
::Delimited
;
369 let mut results
= Vec
::new();
370 let mut result
= Vec
::new();
373 TokenTree
::Token(_
, token
::OpenDelim(..)) => {
374 results
.push(::std
::mem
::replace(&mut result
, Vec
::new()));
376 TokenTree
::Token(span
, token
::CloseDelim(delim
)) => {
377 let tree
= TokenTree
::Delimited(span
, Delimited
{
379 tts
: result
.into_iter().map(TokenStream
::from
).collect
::<TokenStream
>().into(),
381 result
= results
.pop().unwrap();
384 tree @ _
=> result
.push(tree
),
390 // These panicking parsing functions are used by the quote_*!() syntax extensions,
391 // but shouldn't be used otherwise.
392 pub fn parse_expr_panic(parser
: &mut Parser
) -> P
<Expr
> {
393 panictry
!(parser
.parse_expr())
396 pub fn parse_item_panic(parser
: &mut Parser
) -> Option
<P
<Item
>> {
397 panictry
!(parser
.parse_item())
400 pub fn parse_pat_panic(parser
: &mut Parser
) -> P
<Pat
> {
401 panictry
!(parser
.parse_pat())
404 pub fn parse_arm_panic(parser
: &mut Parser
) -> Arm
{
405 panictry
!(parser
.parse_arm())
408 pub fn parse_ty_panic(parser
: &mut Parser
) -> P
<Ty
> {
409 panictry
!(parser
.parse_ty_no_plus())
412 pub fn parse_stmt_panic(parser
: &mut Parser
) -> Option
<Stmt
> {
413 panictry
!(parser
.parse_stmt())
416 pub fn parse_attribute_panic(parser
: &mut Parser
, permit_inner
: bool
) -> ast
::Attribute
{
417 panictry
!(parser
.parse_attribute(permit_inner
))
420 pub fn parse_arg_panic(parser
: &mut Parser
) -> Arg
{
421 panictry
!(parser
.parse_arg())
424 pub fn parse_block_panic(parser
: &mut Parser
) -> P
<Block
> {
425 panictry
!(parser
.parse_block())
428 pub fn parse_meta_item_panic(parser
: &mut Parser
) -> ast
::MetaItem
{
429 panictry
!(parser
.parse_meta_item())
432 pub fn parse_path_panic(parser
: &mut Parser
, mode
: PathStyle
) -> ast
::Path
{
433 panictry
!(parser
.parse_path(mode
))
436 pub fn expand_quote_tokens
<'cx
>(cx
: &'cx
mut ExtCtxt
,
439 -> Box
<base
::MacResult
+'cx
> {
440 let (cx_expr
, expr
) = expand_tts(cx
, sp
, tts
);
441 let expanded
= expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"]]);
442 base
::MacEager
::expr(expanded
)
445 pub fn expand_quote_expr
<'cx
>(cx
: &'cx
mut ExtCtxt
,
448 -> Box
<base
::MacResult
+'cx
> {
449 let expanded
= expand_parse_call(cx
, sp
, "parse_expr_panic", vec
![], tts
);
450 base
::MacEager
::expr(expanded
)
453 pub fn expand_quote_item
<'cx
>(cx
: &'cx
mut ExtCtxt
,
456 -> Box
<base
::MacResult
+'cx
> {
457 let expanded
= expand_parse_call(cx
, sp
, "parse_item_panic", vec
![], tts
);
458 base
::MacEager
::expr(expanded
)
461 pub fn expand_quote_pat
<'cx
>(cx
: &'cx
mut ExtCtxt
,
464 -> Box
<base
::MacResult
+'cx
> {
465 let expanded
= expand_parse_call(cx
, sp
, "parse_pat_panic", vec
![], tts
);
466 base
::MacEager
::expr(expanded
)
469 pub fn expand_quote_arm(cx
: &mut ExtCtxt
,
472 -> Box
<base
::MacResult
+'
static> {
473 let expanded
= expand_parse_call(cx
, sp
, "parse_arm_panic", vec
![], tts
);
474 base
::MacEager
::expr(expanded
)
477 pub fn expand_quote_ty(cx
: &mut ExtCtxt
,
480 -> Box
<base
::MacResult
+'
static> {
481 let expanded
= expand_parse_call(cx
, sp
, "parse_ty_panic", vec
![], tts
);
482 base
::MacEager
::expr(expanded
)
485 pub fn expand_quote_stmt(cx
: &mut ExtCtxt
,
488 -> Box
<base
::MacResult
+'
static> {
489 let expanded
= expand_parse_call(cx
, sp
, "parse_stmt_panic", vec
![], tts
);
490 base
::MacEager
::expr(expanded
)
493 pub fn expand_quote_attr(cx
: &mut ExtCtxt
,
496 -> Box
<base
::MacResult
+'
static> {
497 let expanded
= expand_parse_call(cx
, sp
, "parse_attribute_panic",
498 vec
![cx
.expr_bool(sp
, true)], tts
);
500 base
::MacEager
::expr(expanded
)
503 pub fn expand_quote_arg(cx
: &mut ExtCtxt
,
506 -> Box
<base
::MacResult
+'
static> {
507 let expanded
= expand_parse_call(cx
, sp
, "parse_arg_panic", vec
![], tts
);
508 base
::MacEager
::expr(expanded
)
511 pub fn expand_quote_block(cx
: &mut ExtCtxt
,
514 -> Box
<base
::MacResult
+'
static> {
515 let expanded
= expand_parse_call(cx
, sp
, "parse_block_panic", vec
![], tts
);
516 base
::MacEager
::expr(expanded
)
519 pub fn expand_quote_meta_item(cx
: &mut ExtCtxt
,
522 -> Box
<base
::MacResult
+'
static> {
523 let expanded
= expand_parse_call(cx
, sp
, "parse_meta_item_panic", vec
![], tts
);
524 base
::MacEager
::expr(expanded
)
527 pub fn expand_quote_path(cx
: &mut ExtCtxt
,
530 -> Box
<base
::MacResult
+'
static> {
531 let mode
= mk_parser_path(cx
, sp
, &["PathStyle", "Type"]);
532 let expanded
= expand_parse_call(cx
, sp
, "parse_path_panic", vec
![mode
], tts
);
533 base
::MacEager
::expr(expanded
)
536 fn ids_ext(strs
: Vec
<String
>) -> Vec
<ast
::Ident
> {
537 strs
.iter().map(|s
| ast
::Ident
::from_str(s
)).collect()
540 fn id_ext(s
: &str) -> ast
::Ident
{
541 ast
::Ident
::from_str(s
)
544 // Lift an ident to the expr that evaluates to that ident.
545 fn mk_ident(cx
: &ExtCtxt
, sp
: Span
, ident
: ast
::Ident
) -> P
<ast
::Expr
> {
546 let e_str
= cx
.expr_str(sp
, ident
.name
);
547 cx
.expr_method_call(sp
,
548 cx
.expr_ident(sp
, id_ext("ext_cx")),
553 // Lift a name to the expr that evaluates to that name
554 fn mk_name(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 fn mk_tt_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
563 let idents
= vec
![id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name
)];
564 cx
.expr_path(cx
.path_global(sp
, idents
))
567 fn mk_token_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
568 let idents
= vec
![id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name
)];
569 cx
.expr_path(cx
.path_global(sp
, idents
))
572 fn mk_parser_path(cx
: &ExtCtxt
, sp
: Span
, names
: &[&str]) -> P
<ast
::Expr
> {
573 let mut idents
= vec
![id_ext("syntax"), id_ext("parse"), id_ext("parser")];
574 idents
.extend(names
.iter().cloned().map(id_ext
));
575 cx
.expr_path(cx
.path_global(sp
, idents
))
578 fn mk_binop(cx
: &ExtCtxt
, sp
: Span
, bop
: token
::BinOpToken
) -> P
<ast
::Expr
> {
579 let name
= match bop
{
580 token
::Plus
=> "Plus",
581 token
::Minus
=> "Minus",
582 token
::Star
=> "Star",
583 token
::Slash
=> "Slash",
584 token
::Percent
=> "Percent",
585 token
::Caret
=> "Caret",
591 mk_token_path(cx
, sp
, name
)
594 fn mk_delim(cx
: &ExtCtxt
, sp
: Span
, delim
: token
::DelimToken
) -> P
<ast
::Expr
> {
595 let name
= match delim
{
596 token
::Paren
=> "Paren",
597 token
::Bracket
=> "Bracket",
598 token
::Brace
=> "Brace",
599 token
::NoDelim
=> "NoDelim",
601 mk_token_path(cx
, sp
, name
)
604 #[allow(non_upper_case_globals)]
605 fn expr_mk_token(cx
: &ExtCtxt
, sp
: Span
, tok
: &token
::Token
) -> P
<ast
::Expr
> {
606 macro_rules
! mk_lit
{
607 ($name
: expr
, $suffix
: expr
, $
($args
: expr
),*) => {{
608 let inner
= cx
.expr_call(sp
, mk_token_path(cx
, sp
, $name
), vec
![$
($args
),*]);
609 let suffix
= match $suffix
{
610 Some(name
) => cx
.expr_some(sp
, mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(name
))),
611 None
=> cx
.expr_none(sp
)
613 cx
.expr_call(sp
, mk_token_path(cx
, sp
, "Literal"), vec
![inner
, suffix
])
617 token
::BinOp(binop
) => {
618 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "BinOp"), vec
![mk_binop(cx
, sp
, binop
)]);
620 token
::BinOpEq(binop
) => {
621 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "BinOpEq"),
622 vec
![mk_binop(cx
, sp
, binop
)]);
625 token
::OpenDelim(delim
) => {
626 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "OpenDelim"),
627 vec
![mk_delim(cx
, sp
, delim
)]);
629 token
::CloseDelim(delim
) => {
630 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "CloseDelim"),
631 vec
![mk_delim(cx
, sp
, delim
)]);
634 token
::Literal(token
::Byte(i
), suf
) => {
635 let e_byte
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(i
));
636 return mk_lit
!("Byte", suf
, e_byte
);
639 token
::Literal(token
::Char(i
), suf
) => {
640 let e_char
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(i
));
641 return mk_lit
!("Char", suf
, e_char
);
644 token
::Literal(token
::Integer(i
), suf
) => {
645 let e_int
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(i
));
646 return mk_lit
!("Integer", suf
, e_int
);
649 token
::Literal(token
::Float(fident
), suf
) => {
650 let e_fident
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(fident
));
651 return mk_lit
!("Float", suf
, e_fident
);
654 token
::Literal(token
::Str_(ident
), suf
) => {
655 return mk_lit
!("Str_", suf
, mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(ident
)))
658 token
::Literal(token
::StrRaw(ident
, n
), suf
) => {
659 return mk_lit
!("StrRaw", suf
, mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(ident
)),
660 cx
.expr_usize(sp
, n
))
663 token
::Ident(ident
) => {
664 return cx
.expr_call(sp
,
665 mk_token_path(cx
, sp
, "Ident"),
666 vec
![mk_ident(cx
, sp
, ident
)]);
669 token
::Lifetime(ident
) => {
670 return cx
.expr_call(sp
,
671 mk_token_path(cx
, sp
, "Lifetime"),
672 vec
![mk_ident(cx
, sp
, ident
)]);
675 token
::DocComment(ident
) => {
676 return cx
.expr_call(sp
,
677 mk_token_path(cx
, sp
, "DocComment"),
678 vec
![mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(ident
))]);
681 token
::Interpolated(_
) => panic
!("quote! with interpolated token"),
686 let name
= match *tok
{
690 token
::EqEq
=> "EqEq",
694 token
::AndAnd
=> "AndAnd",
695 token
::OrOr
=> "OrOr",
697 token
::Tilde
=> "Tilde",
700 token
::DotDot
=> "DotDot",
701 token
::Comma
=> "Comma",
702 token
::Semi
=> "Semi",
703 token
::Colon
=> "Colon",
704 token
::ModSep
=> "ModSep",
705 token
::RArrow
=> "RArrow",
706 token
::LArrow
=> "LArrow",
707 token
::FatArrow
=> "FatArrow",
708 token
::Pound
=> "Pound",
709 token
::Dollar
=> "Dollar",
710 token
::Question
=> "Question",
711 token
::Underscore
=> "Underscore",
713 _
=> panic
!("unhandled token in quote!"),
715 mk_token_path(cx
, sp
, name
)
718 fn statements_mk_tt(cx
: &ExtCtxt
, tt
: &TokenTree
, quoted
: bool
) -> Vec
<ast
::Stmt
> {
720 TokenTree
::Token(sp
, token
::Ident(ident
)) if quoted
=> {
721 // tt.extend($ident.to_tokens(ext_cx))
724 cx
.expr_method_call(sp
,
725 cx
.expr_ident(sp
, ident
),
727 vec
![cx
.expr_ident(sp
, id_ext("ext_cx"))]);
729 cx
.expr_method_call(sp
, e_to_toks
, id_ext("into_iter"), vec
![]);
732 cx
.expr_method_call(sp
,
733 cx
.expr_ident(sp
, id_ext("tt")),
737 vec
![cx
.stmt_expr(e_push
)]
739 TokenTree
::Token(sp
, ref tok
) => {
740 let e_sp
= cx
.expr_ident(sp
, id_ext("_sp"));
741 let e_tok
= cx
.expr_call(sp
,
742 mk_tt_path(cx
, sp
, "Token"),
743 vec
![e_sp
, expr_mk_token(cx
, sp
, tok
)]);
745 cx
.expr_method_call(sp
,
746 cx
.expr_ident(sp
, id_ext("tt")),
749 vec
![cx
.stmt_expr(e_push
)]
751 TokenTree
::Delimited(span
, ref delimed
) => {
752 let mut stmts
= statements_mk_tt(cx
, &delimed
.open_tt(span
), false);
753 stmts
.extend(statements_mk_tts(cx
, delimed
.stream()));
754 stmts
.extend(statements_mk_tt(cx
, &delimed
.close_tt(span
), false));
760 fn parse_arguments_to_quote(cx
: &ExtCtxt
, tts
: &[TokenTree
])
761 -> (P
<ast
::Expr
>, Vec
<TokenTree
>) {
762 let mut p
= cx
.new_parser_from_tts(tts
);
764 let cx_expr
= panictry
!(p
.parse_expr());
765 if !p
.eat(&token
::Comma
) {
766 let _
= p
.diagnostic().fatal("expected token `,`");
769 let tts
= panictry
!(p
.parse_all_token_trees());
775 fn mk_stmts_let(cx
: &ExtCtxt
, sp
: Span
) -> Vec
<ast
::Stmt
> {
776 // We also bind a single value, sp, to ext_cx.call_site()
778 // This causes every span in a token-tree quote to be attributed to the
779 // call site of the extension using the quote. We can't really do much
780 // better since the source of the quote may well be in a library that
781 // was not even parsed by this compilation run, that the user has no
782 // source code for (eg. in libsyntax, which they're just _using_).
784 // The old quasiquoter had an elaborate mechanism for denoting input
785 // file locations from which quotes originated; unfortunately this
786 // relied on feeding the source string of the quote back into the
787 // compiler (which we don't really want to do) and, in any case, only
788 // pushed the problem a very small step further back: an error
789 // resulting from a parse of the resulting quote is still attributed to
790 // the site the string literal occurred, which was in a source file
791 // _other_ than the one the user has control over. For example, an
792 // error in a quote from the protocol compiler, invoked in user code
793 // using macro_rules! for example, will be attributed to the macro_rules.rs
794 // file in libsyntax, which the user might not even have source to (unless
795 // they happen to have a compiler on hand). Over all, the phase distinction
796 // just makes quotes "hard to attribute". Possibly this could be fixed
797 // by recreating some of the original qq machinery in the tt regime
798 // (pushing fake FileMaps onto the parser to account for original sites
799 // of quotes, for example) but at this point it seems not likely to be
802 let e_sp
= cx
.expr_method_call(sp
,
803 cx
.expr_ident(sp
, id_ext("ext_cx")),
807 let stmt_let_sp
= cx
.stmt_let(sp
, false,
811 let stmt_let_tt
= cx
.stmt_let(sp
, true, id_ext("tt"), cx
.expr_vec_ng(sp
));
813 vec
![stmt_let_sp
, stmt_let_tt
]
816 fn statements_mk_tts(cx
: &ExtCtxt
, tts
: TokenStream
) -> Vec
<ast
::Stmt
> {
817 let mut ss
= Vec
::new();
818 let mut quoted
= false;
819 for tt
in tts
.into_trees() {
821 TokenTree
::Token(_
, token
::Dollar
) if !quoted
=> true,
823 ss
.extend(statements_mk_tt(cx
, &tt
, quoted
));
831 fn expand_tts(cx
: &ExtCtxt
, sp
: Span
, tts
: &[TokenTree
]) -> (P
<ast
::Expr
>, P
<ast
::Expr
>) {
832 let (cx_expr
, tts
) = parse_arguments_to_quote(cx
, tts
);
834 let mut vector
= mk_stmts_let(cx
, sp
);
835 vector
.extend(statements_mk_tts(cx
, tts
.iter().cloned().collect()));
836 vector
.push(cx
.stmt_expr(cx
.expr_ident(sp
, id_ext("tt"))));
837 let block
= cx
.expr_block(cx
.block(sp
, vector
));
838 let unflatten
= vec
![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext("unflatten")];
840 (cx_expr
, cx
.expr_call_global(sp
, unflatten
, vec
![block
]))
843 fn expand_wrapper(cx
: &ExtCtxt
,
845 cx_expr
: P
<ast
::Expr
>,
847 imports
: &[&[&str]]) -> P
<ast
::Expr
> {
848 // Explicitly borrow to avoid moving from the invoker (#16992)
849 let cx_expr_borrow
= cx
.expr_addr_of(sp
, cx
.expr_deref(sp
, cx_expr
));
850 let stmt_let_ext_cx
= cx
.stmt_let(sp
, false, id_ext("ext_cx"), cx_expr_borrow
);
852 let mut stmts
= imports
.iter().map(|path
| {
853 // make item: `use ...;`
854 let path
= path
.iter().map(|s
| s
.to_string()).collect();
855 cx
.stmt_item(sp
, cx
.item_use_glob(sp
, ast
::Visibility
::Inherited
, ids_ext(path
)))
856 }).chain(Some(stmt_let_ext_cx
)).collect
::<Vec
<_
>>();
857 stmts
.push(cx
.stmt_expr(expr
));
859 cx
.expr_block(cx
.block(sp
, stmts
))
862 fn expand_parse_call(cx
: &ExtCtxt
,
865 arg_exprs
: Vec
<P
<ast
::Expr
>> ,
866 tts
: &[TokenTree
]) -> P
<ast
::Expr
> {
867 let (cx_expr
, tts_expr
) = expand_tts(cx
, sp
, tts
);
869 let parse_sess_call
= || cx
.expr_method_call(
870 sp
, cx
.expr_ident(sp
, id_ext("ext_cx")),
871 id_ext("parse_sess"), Vec
::new());
873 let new_parser_call
=
875 cx
.expr_ident(sp
, id_ext("new_parser_from_tts")),
876 vec
![parse_sess_call(), tts_expr
]);
878 let path
= vec
![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method
)];
879 let mut args
= vec
![cx
.expr_mut_addr_of(sp
, new_parser_call
)];
880 args
.extend(arg_exprs
);
881 let expr
= cx
.expr_call_global(sp
, path
, args
);
883 if parse_method
== "parse_attribute" {
884 expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"],
885 &["syntax", "parse", "attr"]])
887 expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"]])