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, Path, Stmt, TokenTree, Ty}
;
13 use ext
::base
::ExtCtxt
;
15 use ext
::build
::AstBuilder
;
16 use parse
::parser
::{Parser, PathParsingMode}
;
21 /// Quasiquoting works via token trees.
23 /// This is registered as a set of expression syntax extension called quote!
24 /// that lifts its argument token-tree to an AST representing the
25 /// construction of the same token tree, with token::SubstNt interpreted
26 /// as antiquotes (splices).
31 use ext
::base
::ExtCtxt
;
32 use parse
::{self, token, classify}
;
36 use ast
::{TokenTree, Expr}
;
38 pub use parse
::new_parser_from_tts
;
39 pub use codemap
::{BytePos, Span, dummy_spanned, DUMMY_SP}
;
42 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
>;
45 impl ToTokens
for TokenTree
{
46 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
51 impl<T
: ToTokens
> ToTokens
for Vec
<T
> {
52 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
53 self.iter().flat_map(|t
| t
.to_tokens(cx
)).collect()
57 impl<T
: ToTokens
> ToTokens
for Spanned
<T
> {
58 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
59 // FIXME: use the span?
60 self.node
.to_tokens(cx
)
64 impl<T
: ToTokens
> ToTokens
for Option
<T
> {
65 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
67 Some(ref t
) => t
.to_tokens(cx
),
73 impl ToTokens
for ast
::Ident
{
74 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
75 vec
![TokenTree
::Token(DUMMY_SP
, token
::Ident(*self, token
::Plain
))]
79 impl ToTokens
for ast
::Path
{
80 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
81 vec
![TokenTree
::Token(DUMMY_SP
,
82 token
::Interpolated(token
::NtPath(Box
::new(self.clone()))))]
86 impl ToTokens
for ast
::Ty
{
87 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
88 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtTy(P(self.clone()))))]
92 impl ToTokens
for ast
::Block
{
93 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
94 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtBlock(P(self.clone()))))]
98 impl ToTokens
for ast
::Generics
{
99 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
100 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(token
::NtGenerics(self.clone())))]
104 impl ToTokens
for ast
::WhereClause
{
105 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
106 vec
![TokenTree
::Token(DUMMY_SP
,
107 token
::Interpolated(token
::NtWhereClause(self.clone())))]
111 impl ToTokens
for P
<ast
::Item
> {
112 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
113 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtItem(self.clone())))]
117 impl ToTokens
for P
<ast
::ImplItem
> {
118 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
119 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtImplItem(self.clone())))]
123 impl ToTokens
for P
<ast
::TraitItem
> {
124 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
125 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtTraitItem(self.clone())))]
129 impl ToTokens
for P
<ast
::Stmt
> {
130 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
132 TokenTree
::Token(self.span
, token
::Interpolated(token
::NtStmt(self.clone())))
135 // Some statements require a trailing semicolon.
136 if classify
::stmt_ends_with_semi(&self.node
) {
137 tts
.push(TokenTree
::Token(self.span
, token
::Semi
));
144 impl ToTokens
for P
<ast
::Expr
> {
145 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
146 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtExpr(self.clone())))]
150 impl ToTokens
for P
<ast
::Pat
> {
151 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
152 vec
![TokenTree
::Token(self.span
, token
::Interpolated(token
::NtPat(self.clone())))]
156 impl ToTokens
for ast
::Arm
{
157 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
158 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(token
::NtArm(self.clone())))]
162 impl ToTokens
for ast
::Arg
{
163 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
164 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(token
::NtArg(self.clone())))]
168 impl ToTokens
for P
<ast
::Block
> {
169 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
170 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(token
::NtBlock(self.clone())))]
174 macro_rules
! impl_to_tokens_slice
{
175 ($t
: ty
, $sep
: expr
) => {
176 impl ToTokens
for [$t
] {
177 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
179 for (i
, x
) in self.iter().enumerate() {
181 v
.extend_from_slice(&$sep
);
183 v
.extend(x
.to_tokens(cx
));
191 impl_to_tokens_slice
! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
192 impl_to_tokens_slice
! { P<ast::Item>, [] }
193 impl_to_tokens_slice
! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }
195 impl ToTokens
for P
<ast
::MetaItem
> {
196 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
197 vec
![TokenTree
::Token(DUMMY_SP
, token
::Interpolated(token
::NtMeta(self.clone())))]
201 impl ToTokens
for ast
::Attribute
{
202 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
204 // FIXME: The spans could be better
205 r
.push(TokenTree
::Token(self.span
, token
::Pound
));
206 if self.node
.style
== ast
::AttrStyle
::Inner
{
207 r
.push(TokenTree
::Token(self.span
, token
::Not
));
209 r
.push(TokenTree
::Delimited(self.span
, Rc
::new(ast
::Delimited
{
210 delim
: token
::Bracket
,
211 open_span
: self.span
,
212 tts
: self.node
.value
.to_tokens(cx
),
213 close_span
: self.span
,
219 impl ToTokens
for str {
220 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
221 let lit
= ast
::LitStr(
222 token
::intern_and_get_ident(self), ast
::CookedStr
);
223 dummy_spanned(lit
).to_tokens(cx
)
227 impl ToTokens
for () {
228 fn to_tokens(&self, _cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
229 vec
![TokenTree
::Delimited(DUMMY_SP
, Rc
::new(ast
::Delimited
{
233 close_span
: DUMMY_SP
,
238 impl ToTokens
for ast
::Lit
{
239 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
240 // FIXME: This is wrong
242 id
: ast
::DUMMY_NODE_ID
,
243 node
: ast
::ExprLit(P(self.clone())),
250 impl ToTokens
for bool
{
251 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
252 dummy_spanned(ast
::LitBool(*self)).to_tokens(cx
)
256 impl ToTokens
for char {
257 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
258 dummy_spanned(ast
::LitChar(*self)).to_tokens(cx
)
262 macro_rules
! impl_to_tokens_int
{
263 (signed
, $t
:ty
, $tag
:expr
) => (
264 impl ToTokens
for $t
{
265 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
266 let lit
= ast
::LitInt(*self as u64, ast
::SignedIntLit($tag
,
267 ast
::Sign
::new(*self)));
268 dummy_spanned(lit
).to_tokens(cx
)
272 (unsigned
, $t
:ty
, $tag
:expr
) => (
273 impl ToTokens
for $t
{
274 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
275 let lit
= ast
::LitInt(*self as u64, ast
::UnsignedIntLit($tag
));
276 dummy_spanned(lit
).to_tokens(cx
)
282 impl_to_tokens_int
! { signed, isize, ast::TyIs }
283 impl_to_tokens_int
! { signed, i8, ast::TyI8 }
284 impl_to_tokens_int
! { signed, i16, ast::TyI16 }
285 impl_to_tokens_int
! { signed, i32, ast::TyI32 }
286 impl_to_tokens_int
! { signed, i64, ast::TyI64 }
288 impl_to_tokens_int
! { unsigned, usize, ast::TyUs }
289 impl_to_tokens_int
! { unsigned, u8, ast::TyU8 }
290 impl_to_tokens_int
! { unsigned, u16, ast::TyU16 }
291 impl_to_tokens_int
! { unsigned, u32, ast::TyU32 }
292 impl_to_tokens_int
! { unsigned, u64, ast::TyU64 }
294 pub trait ExtParseUtils
{
295 fn parse_item(&self, s
: String
) -> P
<ast
::Item
>;
296 fn parse_expr(&self, s
: String
) -> P
<ast
::Expr
>;
297 fn parse_stmt(&self, s
: String
) -> P
<ast
::Stmt
>;
298 fn parse_tts(&self, s
: String
) -> Vec
<TokenTree
>;
301 impl<'a
> ExtParseUtils
for ExtCtxt
<'a
> {
303 fn parse_item(&self, s
: String
) -> P
<ast
::Item
> {
304 parse
::parse_item_from_source_str(
305 "<quote expansion>".to_string(),
308 self.parse_sess()).expect("parse error")
311 fn parse_stmt(&self, s
: String
) -> P
<ast
::Stmt
> {
312 parse
::parse_stmt_from_source_str("<quote expansion>".to_string(),
315 self.parse_sess()).expect("parse error")
318 fn parse_expr(&self, s
: String
) -> P
<ast
::Expr
> {
319 parse
::parse_expr_from_source_str("<quote expansion>".to_string(),
325 fn parse_tts(&self, s
: String
) -> Vec
<TokenTree
> {
326 parse
::parse_tts_from_source_str("<quote expansion>".to_string(),
334 // These panicking parsing functions are used by the quote_*!() syntax extensions,
335 // but shouldn't be used otherwise.
336 pub fn parse_expr_panic(parser
: &mut Parser
) -> P
<Expr
> {
337 panictry
!(parser
.parse_expr())
340 pub fn parse_item_panic(parser
: &mut Parser
) -> Option
<P
<Item
>> {
341 panictry
!(parser
.parse_item())
344 pub fn parse_pat_panic(parser
: &mut Parser
) -> P
<Pat
> {
345 panictry
!(parser
.parse_pat())
348 pub fn parse_arm_panic(parser
: &mut Parser
) -> Arm
{
349 panictry
!(parser
.parse_arm())
352 pub fn parse_ty_panic(parser
: &mut Parser
) -> P
<Ty
> {
353 panictry
!(parser
.parse_ty())
356 pub fn parse_stmt_panic(parser
: &mut Parser
) -> Option
<P
<Stmt
>> {
357 panictry
!(parser
.parse_stmt())
360 pub fn parse_attribute_panic(parser
: &mut Parser
, permit_inner
: bool
) -> ast
::Attribute
{
361 panictry
!(parser
.parse_attribute(permit_inner
))
364 pub fn parse_arg_panic(parser
: &mut Parser
) -> Arg
{
365 panictry
!(parser
.parse_arg())
368 pub fn parse_block_panic(parser
: &mut Parser
) -> P
<Block
> {
369 panictry
!(parser
.parse_block())
372 pub fn parse_meta_item_panic(parser
: &mut Parser
) -> P
<ast
::MetaItem
> {
373 panictry
!(parser
.parse_meta_item())
376 pub fn parse_path_panic(parser
: &mut Parser
, mode
: PathParsingMode
) -> ast
::Path
{
377 panictry
!(parser
.parse_path(mode
))
380 pub fn expand_quote_tokens
<'cx
>(cx
: &'cx
mut ExtCtxt
,
383 -> Box
<base
::MacResult
+'cx
> {
384 let (cx_expr
, expr
) = expand_tts(cx
, sp
, tts
);
385 let expanded
= expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"]]);
386 base
::MacEager
::expr(expanded
)
389 pub fn expand_quote_expr
<'cx
>(cx
: &'cx
mut ExtCtxt
,
392 -> Box
<base
::MacResult
+'cx
> {
393 let expanded
= expand_parse_call(cx
, sp
, "parse_expr_panic", vec
!(), tts
);
394 base
::MacEager
::expr(expanded
)
397 pub fn expand_quote_item
<'cx
>(cx
: &mut ExtCtxt
,
400 -> Box
<base
::MacResult
+'cx
> {
401 let expanded
= expand_parse_call(cx
, sp
, "parse_item_panic", vec
!(), tts
);
402 base
::MacEager
::expr(expanded
)
405 pub fn expand_quote_pat
<'cx
>(cx
: &'cx
mut ExtCtxt
,
408 -> Box
<base
::MacResult
+'cx
> {
409 let expanded
= expand_parse_call(cx
, sp
, "parse_pat_panic", vec
!(), tts
);
410 base
::MacEager
::expr(expanded
)
413 pub fn expand_quote_arm(cx
: &mut ExtCtxt
,
416 -> Box
<base
::MacResult
+'
static> {
417 let expanded
= expand_parse_call(cx
, sp
, "parse_arm_panic", vec
!(), tts
);
418 base
::MacEager
::expr(expanded
)
421 pub fn expand_quote_ty(cx
: &mut ExtCtxt
,
424 -> Box
<base
::MacResult
+'
static> {
425 let expanded
= expand_parse_call(cx
, sp
, "parse_ty_panic", vec
!(), tts
);
426 base
::MacEager
::expr(expanded
)
429 pub fn expand_quote_stmt(cx
: &mut ExtCtxt
,
432 -> Box
<base
::MacResult
+'
static> {
433 let expanded
= expand_parse_call(cx
, sp
, "parse_stmt_panic", vec
!(), tts
);
434 base
::MacEager
::expr(expanded
)
437 pub fn expand_quote_attr(cx
: &mut ExtCtxt
,
440 -> Box
<base
::MacResult
+'
static> {
441 let expanded
= expand_parse_call(cx
, sp
, "parse_attribute_panic",
442 vec
!(cx
.expr_bool(sp
, true)), tts
);
444 base
::MacEager
::expr(expanded
)
447 pub fn expand_quote_arg(cx
: &mut ExtCtxt
,
450 -> Box
<base
::MacResult
+'
static> {
451 let expanded
= expand_parse_call(cx
, sp
, "parse_arg_panic", vec
!(), tts
);
452 base
::MacEager
::expr(expanded
)
455 pub fn expand_quote_block(cx
: &mut ExtCtxt
,
458 -> Box
<base
::MacResult
+'
static> {
459 let expanded
= expand_parse_call(cx
, sp
, "parse_block_panic", vec
!(), tts
);
460 base
::MacEager
::expr(expanded
)
463 pub fn expand_quote_meta_item(cx
: &mut ExtCtxt
,
466 -> Box
<base
::MacResult
+'
static> {
467 let expanded
= expand_parse_call(cx
, sp
, "parse_meta_item_panic", vec
!(), tts
);
468 base
::MacEager
::expr(expanded
)
471 pub fn expand_quote_path(cx
: &mut ExtCtxt
,
474 -> Box
<base
::MacResult
+'
static> {
475 let mode
= mk_parser_path(cx
, sp
, "LifetimeAndTypesWithoutColons");
476 let expanded
= expand_parse_call(cx
, sp
, "parse_path_panic", vec
!(mode
), tts
);
477 base
::MacEager
::expr(expanded
)
480 pub fn expand_quote_matcher(cx
: &mut ExtCtxt
,
483 -> Box
<base
::MacResult
+'
static> {
484 let (cx_expr
, tts
) = parse_arguments_to_quote(cx
, tts
);
485 let mut vector
= mk_stmts_let(cx
, sp
);
486 vector
.extend(statements_mk_tts(cx
, &tts
[..], true));
487 let block
= cx
.expr_block(
490 Some(cx
.expr_ident(sp
, id_ext("tt")))));
492 let expanded
= expand_wrapper(cx
, sp
, cx_expr
, block
, &[&["syntax", "ext", "quote", "rt"]]);
493 base
::MacEager
::expr(expanded
)
496 fn ids_ext(strs
: Vec
<String
> ) -> Vec
<ast
::Ident
> {
497 strs
.iter().map(|str| str_to_ident(&(*str))).collect()
500 fn id_ext(str: &str) -> ast
::Ident
{
504 // Lift an ident to the expr that evaluates to that ident.
505 fn mk_ident(cx
: &ExtCtxt
, sp
: Span
, ident
: ast
::Ident
) -> P
<ast
::Expr
> {
506 let e_str
= cx
.expr_str(sp
, ident
.name
.as_str());
507 cx
.expr_method_call(sp
,
508 cx
.expr_ident(sp
, id_ext("ext_cx")),
513 // Lift a name to the expr that evaluates to that name
514 fn mk_name(cx
: &ExtCtxt
, sp
: Span
, ident
: ast
::Ident
) -> P
<ast
::Expr
> {
515 let e_str
= cx
.expr_str(sp
, ident
.name
.as_str());
516 cx
.expr_method_call(sp
,
517 cx
.expr_ident(sp
, id_ext("ext_cx")),
522 fn mk_tt_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
523 let idents
= vec
!(id_ext("syntax"), id_ext("ast"), id_ext("TokenTree"), id_ext(name
));
524 cx
.expr_path(cx
.path_global(sp
, idents
))
527 fn mk_ast_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
528 let idents
= vec
!(id_ext("syntax"), id_ext("ast"), id_ext(name
));
529 cx
.expr_path(cx
.path_global(sp
, idents
))
532 fn mk_token_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
533 let idents
= vec
!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name
));
534 cx
.expr_path(cx
.path_global(sp
, idents
))
537 fn mk_parser_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
538 let idents
= vec
!(id_ext("syntax"), id_ext("parse"), id_ext("parser"), id_ext(name
));
539 cx
.expr_path(cx
.path_global(sp
, idents
))
542 fn mk_binop(cx
: &ExtCtxt
, sp
: Span
, bop
: token
::BinOpToken
) -> P
<ast
::Expr
> {
543 let name
= match bop
{
544 token
::Plus
=> "Plus",
545 token
::Minus
=> "Minus",
546 token
::Star
=> "Star",
547 token
::Slash
=> "Slash",
548 token
::Percent
=> "Percent",
549 token
::Caret
=> "Caret",
555 mk_token_path(cx
, sp
, name
)
558 fn mk_delim(cx
: &ExtCtxt
, sp
: Span
, delim
: token
::DelimToken
) -> P
<ast
::Expr
> {
559 let name
= match delim
{
560 token
::Paren
=> "Paren",
561 token
::Bracket
=> "Bracket",
562 token
::Brace
=> "Brace",
564 mk_token_path(cx
, sp
, name
)
567 #[allow(non_upper_case_globals)]
568 fn expr_mk_token(cx
: &ExtCtxt
, sp
: Span
, tok
: &token
::Token
) -> P
<ast
::Expr
> {
569 macro_rules
! mk_lit
{
570 ($name
: expr
, $suffix
: expr
, $
($args
: expr
),*) => {{
571 let inner
= cx
.expr_call(sp
, mk_token_path(cx
, sp
, $name
), vec
![$
($args
),*]);
572 let suffix
= match $suffix
{
573 Some(name
) => cx
.expr_some(sp
, mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(name
))),
574 None
=> cx
.expr_none(sp
)
576 cx
.expr_call(sp
, mk_token_path(cx
, sp
, "Literal"), vec
![inner
, suffix
])
580 token
::BinOp(binop
) => {
581 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "BinOp"), vec
!(mk_binop(cx
, sp
, binop
)));
583 token
::BinOpEq(binop
) => {
584 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "BinOpEq"),
585 vec
!(mk_binop(cx
, sp
, binop
)));
588 token
::OpenDelim(delim
) => {
589 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "OpenDelim"),
590 vec
![mk_delim(cx
, sp
, delim
)]);
592 token
::CloseDelim(delim
) => {
593 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "CloseDelim"),
594 vec
![mk_delim(cx
, sp
, delim
)]);
597 token
::Literal(token
::Byte(i
), suf
) => {
598 let e_byte
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(i
));
599 return mk_lit
!("Byte", suf
, e_byte
);
602 token
::Literal(token
::Char(i
), suf
) => {
603 let e_char
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(i
));
604 return mk_lit
!("Char", suf
, e_char
);
607 token
::Literal(token
::Integer(i
), suf
) => {
608 let e_int
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(i
));
609 return mk_lit
!("Integer", suf
, e_int
);
612 token
::Literal(token
::Float(fident
), suf
) => {
613 let e_fident
= mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(fident
));
614 return mk_lit
!("Float", suf
, e_fident
);
617 token
::Literal(token
::Str_(ident
), suf
) => {
618 return mk_lit
!("Str_", suf
, mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(ident
)))
621 token
::Literal(token
::StrRaw(ident
, n
), suf
) => {
622 return mk_lit
!("StrRaw", suf
, mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(ident
)),
623 cx
.expr_usize(sp
, n
))
626 token
::Ident(ident
, style
) => {
627 return cx
.expr_call(sp
,
628 mk_token_path(cx
, sp
, "Ident"),
629 vec
![mk_ident(cx
, sp
, ident
),
631 ModName
=> mk_token_path(cx
, sp
, "ModName"),
632 Plain
=> mk_token_path(cx
, sp
, "Plain"),
636 token
::Lifetime(ident
) => {
637 return cx
.expr_call(sp
,
638 mk_token_path(cx
, sp
, "Lifetime"),
639 vec
!(mk_ident(cx
, sp
, ident
)));
642 token
::DocComment(ident
) => {
643 return cx
.expr_call(sp
,
644 mk_token_path(cx
, sp
, "DocComment"),
645 vec
!(mk_name(cx
, sp
, ast
::Ident
::with_empty_ctxt(ident
))));
648 token
::MatchNt(name
, kind
, namep
, kindp
) => {
649 return cx
.expr_call(sp
,
650 mk_token_path(cx
, sp
, "MatchNt"),
651 vec
!(mk_ident(cx
, sp
, name
),
652 mk_ident(cx
, sp
, kind
),
654 ModName
=> mk_token_path(cx
, sp
, "ModName"),
655 Plain
=> mk_token_path(cx
, sp
, "Plain"),
658 ModName
=> mk_token_path(cx
, sp
, "ModName"),
659 Plain
=> mk_token_path(cx
, sp
, "Plain"),
663 token
::Interpolated(_
) => panic
!("quote! with interpolated token"),
668 let name
= match *tok
{
672 token
::EqEq
=> "EqEq",
676 token
::AndAnd
=> "AndAnd",
677 token
::OrOr
=> "OrOr",
679 token
::Tilde
=> "Tilde",
682 token
::DotDot
=> "DotDot",
683 token
::Comma
=> "Comma",
684 token
::Semi
=> "Semi",
685 token
::Colon
=> "Colon",
686 token
::ModSep
=> "ModSep",
687 token
::RArrow
=> "RArrow",
688 token
::LArrow
=> "LArrow",
689 token
::FatArrow
=> "FatArrow",
690 token
::Pound
=> "Pound",
691 token
::Dollar
=> "Dollar",
692 token
::Question
=> "Question",
693 token
::Underscore
=> "Underscore",
695 _
=> panic
!("unhandled token in quote!"),
697 mk_token_path(cx
, sp
, name
)
700 fn statements_mk_tt(cx
: &ExtCtxt
, tt
: &TokenTree
, matcher
: bool
) -> Vec
<P
<ast
::Stmt
>> {
702 TokenTree
::Token(sp
, SubstNt(ident
, _
)) => {
703 // tt.extend($ident.to_tokens(ext_cx))
706 cx
.expr_method_call(sp
,
707 cx
.expr_ident(sp
, ident
),
709 vec
!(cx
.expr_ident(sp
, id_ext("ext_cx"))));
711 cx
.expr_method_call(sp
, e_to_toks
, id_ext("into_iter"), vec
![]);
714 cx
.expr_method_call(sp
,
715 cx
.expr_ident(sp
, id_ext("tt")),
719 vec
!(cx
.stmt_expr(e_push
))
721 ref tt @ TokenTree
::Token(_
, MatchNt(..)) if !matcher
=> {
722 let mut seq
= vec
![];
723 for i
in 0..tt
.len() {
724 seq
.push(tt
.get_tt(i
));
726 statements_mk_tts(cx
, &seq
[..], matcher
)
728 TokenTree
::Token(sp
, ref tok
) => {
729 let e_sp
= cx
.expr_ident(sp
, id_ext("_sp"));
730 let e_tok
= cx
.expr_call(sp
,
731 mk_tt_path(cx
, sp
, "Token"),
732 vec
!(e_sp
, expr_mk_token(cx
, sp
, tok
)));
734 cx
.expr_method_call(sp
,
735 cx
.expr_ident(sp
, id_ext("tt")),
738 vec
!(cx
.stmt_expr(e_push
))
740 TokenTree
::Delimited(_
, ref delimed
) => {
741 statements_mk_tt(cx
, &delimed
.open_tt(), matcher
).into_iter()
742 .chain(delimed
.tts
.iter()
743 .flat_map(|tt
| statements_mk_tt(cx
, tt
, matcher
)))
744 .chain(statements_mk_tt(cx
, &delimed
.close_tt(), matcher
))
747 TokenTree
::Sequence(sp
, ref seq
) => {
749 panic
!("TokenTree::Sequence in quote!");
752 let e_sp
= cx
.expr_ident(sp
, id_ext("_sp"));
754 let stmt_let_tt
= cx
.stmt_let(sp
, true, id_ext("tt"), cx
.expr_vec_ng(sp
));
755 let mut tts_stmts
= vec
![stmt_let_tt
];
756 tts_stmts
.extend(statements_mk_tts(cx
, &seq
.tts
[..], matcher
));
757 let e_tts
= cx
.expr_block(cx
.block(sp
, tts_stmts
,
758 Some(cx
.expr_ident(sp
, id_ext("tt")))));
759 let e_separator
= match seq
.separator
{
760 Some(ref sep
) => cx
.expr_some(sp
, expr_mk_token(cx
, sp
, sep
)),
761 None
=> cx
.expr_none(sp
),
763 let e_op
= match seq
.op
{
764 ast
::ZeroOrMore
=> mk_ast_path(cx
, sp
, "ZeroOrMore"),
765 ast
::OneOrMore
=> mk_ast_path(cx
, sp
, "OneOrMore"),
767 let fields
= vec
![cx
.field_imm(sp
, id_ext("tts"), e_tts
),
768 cx
.field_imm(sp
, id_ext("separator"), e_separator
),
769 cx
.field_imm(sp
, id_ext("op"), e_op
),
770 cx
.field_imm(sp
, id_ext("num_captures"),
771 cx
.expr_usize(sp
, seq
.num_captures
))];
772 let seq_path
= vec
![id_ext("syntax"), id_ext("ast"), id_ext("SequenceRepetition")];
773 let e_seq_struct
= cx
.expr_struct(sp
, cx
.path_global(sp
, seq_path
), fields
);
774 let e_rc_new
= cx
.expr_call_global(sp
, vec
![id_ext("std"),
779 let e_tok
= cx
.expr_call(sp
,
780 mk_tt_path(cx
, sp
, "Sequence"),
781 vec
!(e_sp
, e_rc_new
));
783 cx
.expr_method_call(sp
,
784 cx
.expr_ident(sp
, id_ext("tt")),
787 vec
!(cx
.stmt_expr(e_push
))
792 fn parse_arguments_to_quote(cx
: &ExtCtxt
, tts
: &[TokenTree
])
793 -> (P
<ast
::Expr
>, Vec
<TokenTree
>) {
794 // NB: It appears that the main parser loses its mind if we consider
795 // $foo as a SubstNt during the main parse, so we have to re-parse
796 // under quote_depth > 0. This is silly and should go away; the _guess_ is
797 // it has to do with transition away from supporting old-style macros, so
798 // try removing it when enough of them are gone.
800 let mut p
= cx
.new_parser_from_tts(tts
);
803 let cx_expr
= panictry
!(p
.parse_expr());
804 if !panictry
!(p
.eat(&token
::Comma
)) {
805 panic
!(p
.fatal("expected token `,`"));
808 let tts
= panictry
!(p
.parse_all_token_trees());
814 fn mk_stmts_let(cx
: &ExtCtxt
, sp
: Span
) -> Vec
<P
<ast
::Stmt
>> {
815 // We also bind a single value, sp, to ext_cx.call_site()
817 // This causes every span in a token-tree quote to be attributed to the
818 // call site of the extension using the quote. We can't really do much
819 // better since the source of the quote may well be in a library that
820 // was not even parsed by this compilation run, that the user has no
821 // source code for (eg. in libsyntax, which they're just _using_).
823 // The old quasiquoter had an elaborate mechanism for denoting input
824 // file locations from which quotes originated; unfortunately this
825 // relied on feeding the source string of the quote back into the
826 // compiler (which we don't really want to do) and, in any case, only
827 // pushed the problem a very small step further back: an error
828 // resulting from a parse of the resulting quote is still attributed to
829 // the site the string literal occurred, which was in a source file
830 // _other_ than the one the user has control over. For example, an
831 // error in a quote from the protocol compiler, invoked in user code
832 // using macro_rules! for example, will be attributed to the macro_rules.rs
833 // file in libsyntax, which the user might not even have source to (unless
834 // they happen to have a compiler on hand). Over all, the phase distinction
835 // just makes quotes "hard to attribute". Possibly this could be fixed
836 // by recreating some of the original qq machinery in the tt regime
837 // (pushing fake FileMaps onto the parser to account for original sites
838 // of quotes, for example) but at this point it seems not likely to be
841 let e_sp
= cx
.expr_method_call(sp
,
842 cx
.expr_ident(sp
, id_ext("ext_cx")),
846 let stmt_let_sp
= cx
.stmt_let(sp
, false,
850 let stmt_let_tt
= cx
.stmt_let(sp
, true, id_ext("tt"), cx
.expr_vec_ng(sp
));
852 vec
!(stmt_let_sp
, stmt_let_tt
)
855 fn statements_mk_tts(cx
: &ExtCtxt
, tts
: &[TokenTree
], matcher
: bool
) -> Vec
<P
<ast
::Stmt
>> {
856 let mut ss
= Vec
::new();
858 ss
.extend(statements_mk_tt(cx
, tt
, matcher
));
863 fn expand_tts(cx
: &ExtCtxt
, sp
: Span
, tts
: &[TokenTree
])
864 -> (P
<ast
::Expr
>, P
<ast
::Expr
>) {
865 let (cx_expr
, tts
) = parse_arguments_to_quote(cx
, tts
);
867 let mut vector
= mk_stmts_let(cx
, sp
);
868 vector
.extend(statements_mk_tts(cx
, &tts
[..], false));
869 let block
= cx
.expr_block(
872 Some(cx
.expr_ident(sp
, id_ext("tt")))));
877 fn expand_wrapper(cx
: &ExtCtxt
,
879 cx_expr
: P
<ast
::Expr
>,
881 imports
: &[&[&str]]) -> P
<ast
::Expr
> {
882 // Explicitly borrow to avoid moving from the invoker (#16992)
883 let cx_expr_borrow
= cx
.expr_addr_of(sp
, cx
.expr_deref(sp
, cx_expr
));
884 let stmt_let_ext_cx
= cx
.stmt_let(sp
, false, id_ext("ext_cx"), cx_expr_borrow
);
886 let stmts
= imports
.iter().map(|path
| {
887 // make item: `use ...;`
888 let path
= path
.iter().map(|s
| s
.to_string()).collect();
889 cx
.stmt_item(sp
, cx
.item_use_glob(sp
, ast
::Inherited
, ids_ext(path
)))
890 }).chain(Some(stmt_let_ext_cx
)).collect();
892 cx
.expr_block(cx
.block_all(sp
, stmts
, Some(expr
)))
895 fn expand_parse_call(cx
: &ExtCtxt
,
898 arg_exprs
: Vec
<P
<ast
::Expr
>> ,
899 tts
: &[TokenTree
]) -> P
<ast
::Expr
> {
900 let (cx_expr
, tts_expr
) = expand_tts(cx
, sp
, tts
);
902 let cfg_call
= || cx
.expr_method_call(
903 sp
, cx
.expr_ident(sp
, id_ext("ext_cx")),
904 id_ext("cfg"), Vec
::new());
906 let parse_sess_call
= || cx
.expr_method_call(
907 sp
, cx
.expr_ident(sp
, id_ext("ext_cx")),
908 id_ext("parse_sess"), Vec
::new());
910 let new_parser_call
=
912 cx
.expr_ident(sp
, id_ext("new_parser_from_tts")),
913 vec
!(parse_sess_call(), cfg_call(), tts_expr
));
915 let path
= vec
![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method
)];
916 let mut args
= vec
![cx
.expr_mut_addr_of(sp
, new_parser_call
)];
917 args
.extend(arg_exprs
);
918 let expr
= cx
.expr_call_global(sp
, path
, args
);
920 if parse_method
== "parse_attribute" {
921 expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"],
922 &["syntax", "parse", "attr"]])
924 expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"]])