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.
13 use ext
::base
::ExtCtxt
;
15 use ext
::build
::AstBuilder
;
20 /// Quasiquoting works via token trees.
22 /// This is registered as a set of expression syntax extension called quote!
23 /// that lifts its argument token-tree to an AST representing the
24 /// construction of the same token tree, with token::SubstNt interpreted
25 /// as antiquotes (splices).
30 use ext
::base
::ExtCtxt
;
36 use ast
::{TokenTree, Generics, Expr}
;
38 pub use parse
::new_parser_from_tts
;
39 pub use codemap
::{BytePos, Span, dummy_spanned}
;
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
).into_iter()).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 /* Should be (when bugs in default methods are fixed):
75 trait ToSource : ToTokens {
76 // Takes a thing and generates a string containing rust code for it.
77 pub fn to_source() -> String;
79 // If you can make source, you can definitely make tokens.
80 pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
81 cx.parse_tts(self.to_source())
87 // FIXME: Move this trait to pprust and get rid of *_to_str?
89 // Takes a thing and generates a string containing rust code for it.
90 fn to_source(&self) -> String
;
93 // FIXME (Issue #16472): This should go away after ToToken impls
94 // are revised to go directly to token-trees.
95 trait ToSourceWithHygiene
: ToSource
{
96 // Takes a thing and generates a string containing rust code
97 // for it, encoding Idents as special byte sequences to
98 // maintain hygiene across serialization and deserialization.
99 fn to_source_with_hygiene(&self) -> String
;
102 macro_rules
! impl_to_source
{
103 (P
<$t
:ty
>, $pp
:ident
) => (
104 impl ToSource
for P
<$t
> {
105 fn to_source(&self) -> String
{
109 impl ToSourceWithHygiene
for P
<$t
> {
110 fn to_source_with_hygiene(&self) -> String
{
111 pprust
::with_hygiene
::$
pp(&**self)
115 ($t
:ty
, $pp
:ident
) => (
116 impl ToSource
for $t
{
117 fn to_source(&self) -> String
{
121 impl ToSourceWithHygiene
for $t
{
122 fn to_source_with_hygiene(&self) -> String
{
123 pprust
::with_hygiene
::$
pp(self)
129 fn slice_to_source
<'a
, T
: ToSource
>(sep
: &'
static str, xs
: &'a
[T
]) -> String
{
131 .map(|i
| i
.to_source())
132 .collect
::<Vec
<String
>>()
137 fn slice_to_source_with_hygiene
<'a
, T
: ToSourceWithHygiene
>(
138 sep
: &'
static str, xs
: &'a
[T
]) -> String
{
140 .map(|i
| i
.to_source_with_hygiene())
141 .collect
::<Vec
<String
>>()
146 macro_rules
! impl_to_source_slice
{
147 ($t
:ty
, $sep
:expr
) => (
148 impl ToSource
for [$t
] {
149 fn to_source(&self) -> String
{
150 slice_to_source($sep
, self)
154 impl ToSourceWithHygiene
for [$t
] {
155 fn to_source_with_hygiene(&self) -> String
{
156 slice_to_source_with_hygiene($sep
, self)
162 impl ToSource
for ast
::Ident
{
163 fn to_source(&self) -> String
{
164 token
::get_ident(*self).to_string()
168 impl ToSourceWithHygiene
for ast
::Ident
{
169 fn to_source_with_hygiene(&self) -> String
{
170 self.encode_with_hygiene()
174 impl_to_source
! { ast::Path, path_to_string }
175 impl_to_source
! { ast::Ty, ty_to_string }
176 impl_to_source
! { ast::Block, block_to_string }
177 impl_to_source
! { ast::Arg, arg_to_string }
178 impl_to_source
! { Generics, generics_to_string }
179 impl_to_source
! { ast::WhereClause, where_clause_to_string }
180 impl_to_source
! { P<ast::Item>, item_to_string }
181 impl_to_source
! { P<ast::ImplItem>, impl_item_to_string }
182 impl_to_source
! { P<ast::TraitItem>, trait_item_to_string }
183 impl_to_source
! { P<ast::Stmt>, stmt_to_string }
184 impl_to_source
! { P<ast::Expr>, expr_to_string }
185 impl_to_source
! { P<ast::Pat>, pat_to_string }
186 impl_to_source
! { ast::Arm, arm_to_string }
187 impl_to_source_slice
! { ast::Ty, ", " }
188 impl_to_source_slice
! { P<ast::Item>, "\n\n" }
190 impl ToSource
for ast
::Attribute_
{
191 fn to_source(&self) -> String
{
192 pprust
::attribute_to_string(&dummy_spanned(self.clone()))
195 impl ToSourceWithHygiene
for ast
::Attribute_
{
196 fn to_source_with_hygiene(&self) -> String
{
201 impl ToSource
for str {
202 fn to_source(&self) -> String
{
203 let lit
= dummy_spanned(ast
::LitStr(
204 token
::intern_and_get_ident(self), ast
::CookedStr
));
205 pprust
::lit_to_string(&lit
)
208 impl ToSourceWithHygiene
for str {
209 fn to_source_with_hygiene(&self) -> String
{
214 impl ToSource
for () {
215 fn to_source(&self) -> String
{
219 impl ToSourceWithHygiene
for () {
220 fn to_source_with_hygiene(&self) -> String
{
225 impl ToSource
for bool
{
226 fn to_source(&self) -> String
{
227 let lit
= dummy_spanned(ast
::LitBool(*self));
228 pprust
::lit_to_string(&lit
)
231 impl ToSourceWithHygiene
for bool
{
232 fn to_source_with_hygiene(&self) -> String
{
237 impl ToSource
for char {
238 fn to_source(&self) -> String
{
239 let lit
= dummy_spanned(ast
::LitChar(*self));
240 pprust
::lit_to_string(&lit
)
243 impl ToSourceWithHygiene
for char {
244 fn to_source_with_hygiene(&self) -> String
{
249 macro_rules
! impl_to_source_int
{
250 (signed
, $t
:ty
, $tag
:expr
) => (
251 impl ToSource
for $t
{
252 fn to_source(&self) -> String
{
253 let lit
= ast
::LitInt(*self as u64, ast
::SignedIntLit($tag
,
254 ast
::Sign
::new(*self)));
255 pprust
::lit_to_string(&dummy_spanned(lit
))
258 impl ToSourceWithHygiene
for $t
{
259 fn to_source_with_hygiene(&self) -> String
{
264 (unsigned
, $t
:ty
, $tag
:expr
) => (
265 impl ToSource
for $t
{
266 fn to_source(&self) -> String
{
267 let lit
= ast
::LitInt(*self as u64, ast
::UnsignedIntLit($tag
));
268 pprust
::lit_to_string(&dummy_spanned(lit
))
271 impl ToSourceWithHygiene
for $t
{
272 fn to_source_with_hygiene(&self) -> String
{
279 impl_to_source_int
! { signed, isize, ast::TyIs }
280 impl_to_source_int
! { signed, i8, ast::TyI8 }
281 impl_to_source_int
! { signed, i16, ast::TyI16 }
282 impl_to_source_int
! { signed, i32, ast::TyI32 }
283 impl_to_source_int
! { signed, i64, ast::TyI64 }
285 impl_to_source_int
! { unsigned, usize, ast::TyUs }
286 impl_to_source_int
! { unsigned, u8, ast::TyU8 }
287 impl_to_source_int
! { unsigned, u16, ast::TyU16 }
288 impl_to_source_int
! { unsigned, u32, ast::TyU32 }
289 impl_to_source_int
! { unsigned, u64, ast::TyU64 }
291 // Alas ... we write these out instead. All redundant.
293 macro_rules
! impl_to_tokens
{
295 impl ToTokens
for $t
{
296 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
297 cx
.parse_tts_with_hygiene(self.to_source_with_hygiene())
303 macro_rules
! impl_to_tokens_lifetime
{
305 impl<'a
> ToTokens
for $t
{
306 fn to_tokens(&self, cx
: &ExtCtxt
) -> Vec
<TokenTree
> {
307 cx
.parse_tts_with_hygiene(self.to_source_with_hygiene())
313 impl_to_tokens
! { ast::Ident }
314 impl_to_tokens
! { ast::Path }
315 impl_to_tokens
! { P<ast::Item> }
316 impl_to_tokens
! { P<ast::ImplItem> }
317 impl_to_tokens
! { P<ast::TraitItem> }
318 impl_to_tokens
! { P<ast::Pat> }
319 impl_to_tokens
! { ast::Arm }
320 impl_to_tokens_lifetime
! { &'a [P<ast::Item>] }
321 impl_to_tokens
! { ast::Ty }
322 impl_to_tokens_lifetime
! { &'a [ast::Ty] }
323 impl_to_tokens
! { Generics }
324 impl_to_tokens
! { ast::WhereClause }
325 impl_to_tokens
! { P<ast::Stmt> }
326 impl_to_tokens
! { P<ast::Expr> }
327 impl_to_tokens
! { ast::Block }
328 impl_to_tokens
! { ast::Arg }
329 impl_to_tokens
! { ast::Attribute_ }
330 impl_to_tokens_lifetime
! { &'a str }
331 impl_to_tokens
! { () }
332 impl_to_tokens
! { char }
333 impl_to_tokens
! { bool }
334 impl_to_tokens
! { isize }
335 impl_to_tokens
! { i8 }
336 impl_to_tokens
! { i16 }
337 impl_to_tokens
! { i32 }
338 impl_to_tokens
! { i64 }
339 impl_to_tokens
! { usize }
340 impl_to_tokens
! { u8 }
341 impl_to_tokens
! { u16 }
342 impl_to_tokens
! { u32 }
343 impl_to_tokens
! { u64 }
345 pub trait ExtParseUtils
{
346 fn parse_item(&self, s
: String
) -> P
<ast
::Item
>;
347 fn parse_expr(&self, s
: String
) -> P
<ast
::Expr
>;
348 fn parse_stmt(&self, s
: String
) -> P
<ast
::Stmt
>;
349 fn parse_tts(&self, s
: String
) -> Vec
<ast
::TokenTree
>;
352 trait ExtParseUtilsWithHygiene
{
353 // FIXME (Issue #16472): This should go away after ToToken impls
354 // are revised to go directly to token-trees.
355 fn parse_tts_with_hygiene(&self, s
: String
) -> Vec
<ast
::TokenTree
>;
358 impl<'a
> ExtParseUtils
for ExtCtxt
<'a
> {
360 fn parse_item(&self, s
: String
) -> P
<ast
::Item
> {
361 parse
::parse_item_from_source_str(
362 "<quote expansion>".to_string(),
365 self.parse_sess()).expect("parse error")
368 fn parse_stmt(&self, s
: String
) -> P
<ast
::Stmt
> {
369 parse
::parse_stmt_from_source_str("<quote expansion>".to_string(),
372 self.parse_sess()).expect("parse error")
375 fn parse_expr(&self, s
: String
) -> P
<ast
::Expr
> {
376 parse
::parse_expr_from_source_str("<quote expansion>".to_string(),
382 fn parse_tts(&self, s
: String
) -> Vec
<ast
::TokenTree
> {
383 parse
::parse_tts_from_source_str("<quote expansion>".to_string(),
390 impl<'a
> ExtParseUtilsWithHygiene
for ExtCtxt
<'a
> {
392 fn parse_tts_with_hygiene(&self, s
: String
) -> Vec
<ast
::TokenTree
> {
393 use parse
::with_hygiene
::parse_tts_from_source_str
;
394 parse_tts_from_source_str("<quote expansion>".to_string(),
404 pub fn expand_quote_tokens
<'cx
>(cx
: &'cx
mut ExtCtxt
,
406 tts
: &[ast
::TokenTree
])
407 -> Box
<base
::MacResult
+'cx
> {
408 let (cx_expr
, expr
) = expand_tts(cx
, sp
, tts
);
409 let expanded
= expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"]]);
410 base
::MacEager
::expr(expanded
)
413 pub fn expand_quote_expr
<'cx
>(cx
: &'cx
mut ExtCtxt
,
415 tts
: &[ast
::TokenTree
])
416 -> Box
<base
::MacResult
+'cx
> {
417 let expanded
= expand_parse_call(cx
, sp
, "parse_expr", vec
!(), tts
);
418 base
::MacEager
::expr(expanded
)
421 pub fn expand_quote_item
<'cx
>(cx
: &mut ExtCtxt
,
423 tts
: &[ast
::TokenTree
])
424 -> Box
<base
::MacResult
+'cx
> {
425 let expanded
= expand_parse_call(cx
, sp
, "parse_item", vec
!(), tts
);
426 base
::MacEager
::expr(expanded
)
429 pub fn expand_quote_pat
<'cx
>(cx
: &'cx
mut ExtCtxt
,
431 tts
: &[ast
::TokenTree
])
432 -> Box
<base
::MacResult
+'cx
> {
433 let expanded
= expand_parse_call(cx
, sp
, "parse_pat", vec
!(), tts
);
434 base
::MacEager
::expr(expanded
)
437 pub fn expand_quote_arm(cx
: &mut ExtCtxt
,
439 tts
: &[ast
::TokenTree
])
440 -> Box
<base
::MacResult
+'
static> {
441 let expanded
= expand_parse_call(cx
, sp
, "parse_arm", vec
!(), tts
);
442 base
::MacEager
::expr(expanded
)
445 pub fn expand_quote_ty(cx
: &mut ExtCtxt
,
447 tts
: &[ast
::TokenTree
])
448 -> Box
<base
::MacResult
+'
static> {
449 let expanded
= expand_parse_call(cx
, sp
, "parse_ty", vec
!(), tts
);
450 base
::MacEager
::expr(expanded
)
453 pub fn expand_quote_stmt(cx
: &mut ExtCtxt
,
455 tts
: &[ast
::TokenTree
])
456 -> Box
<base
::MacResult
+'
static> {
457 let expanded
= expand_parse_call(cx
, sp
, "parse_stmt", vec
!(), tts
);
458 base
::MacEager
::expr(expanded
)
461 pub fn expand_quote_attr(cx
: &mut ExtCtxt
,
463 tts
: &[ast
::TokenTree
])
464 -> Box
<base
::MacResult
+'
static> {
465 let expanded
= expand_parse_call(cx
, sp
, "parse_attribute",
466 vec
!(cx
.expr_bool(sp
, true)), tts
);
468 base
::MacEager
::expr(expanded
)
471 pub fn expand_quote_matcher(cx
: &mut ExtCtxt
,
473 tts
: &[ast
::TokenTree
])
474 -> Box
<base
::MacResult
+'
static> {
475 let (cx_expr
, tts
) = parse_arguments_to_quote(cx
, tts
);
476 let mut vector
= mk_stmts_let(cx
, sp
);
477 vector
.extend(statements_mk_tts(cx
, &tts
[..], true).into_iter());
478 let block
= cx
.expr_block(
481 Some(cx
.expr_ident(sp
, id_ext("tt")))));
483 let expanded
= expand_wrapper(cx
, sp
, cx_expr
, block
, &[&["syntax", "ext", "quote", "rt"]]);
484 base
::MacEager
::expr(expanded
)
487 fn ids_ext(strs
: Vec
<String
> ) -> Vec
<ast
::Ident
> {
488 strs
.iter().map(|str| str_to_ident(&(*str))).collect()
491 fn id_ext(str: &str) -> ast
::Ident
{
495 // Lift an ident to the expr that evaluates to that ident.
496 fn mk_ident(cx
: &ExtCtxt
, sp
: Span
, ident
: ast
::Ident
) -> P
<ast
::Expr
> {
497 let e_str
= cx
.expr_str(sp
, token
::get_ident(ident
));
498 cx
.expr_method_call(sp
,
499 cx
.expr_ident(sp
, id_ext("ext_cx")),
504 // Lift a name to the expr that evaluates to that name
505 fn mk_name(cx
: &ExtCtxt
, sp
: Span
, ident
: ast
::Ident
) -> P
<ast
::Expr
> {
506 let e_str
= cx
.expr_str(sp
, token
::get_ident(ident
));
507 cx
.expr_method_call(sp
,
508 cx
.expr_ident(sp
, id_ext("ext_cx")),
513 fn mk_ast_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
514 let idents
= vec
!(id_ext("syntax"), id_ext("ast"), id_ext(name
));
515 cx
.expr_path(cx
.path_global(sp
, idents
))
518 fn mk_token_path(cx
: &ExtCtxt
, sp
: Span
, name
: &str) -> P
<ast
::Expr
> {
519 let idents
= vec
!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name
));
520 cx
.expr_path(cx
.path_global(sp
, idents
))
523 fn mk_binop(cx
: &ExtCtxt
, sp
: Span
, bop
: token
::BinOpToken
) -> P
<ast
::Expr
> {
524 let name
= match bop
{
525 token
::Plus
=> "Plus",
526 token
::Minus
=> "Minus",
527 token
::Star
=> "Star",
528 token
::Slash
=> "Slash",
529 token
::Percent
=> "Percent",
530 token
::Caret
=> "Caret",
536 mk_token_path(cx
, sp
, name
)
539 fn mk_delim(cx
: &ExtCtxt
, sp
: Span
, delim
: token
::DelimToken
) -> P
<ast
::Expr
> {
540 let name
= match delim
{
541 token
::Paren
=> "Paren",
542 token
::Bracket
=> "Bracket",
543 token
::Brace
=> "Brace",
545 mk_token_path(cx
, sp
, name
)
548 #[allow(non_upper_case_globals)]
549 fn expr_mk_token(cx
: &ExtCtxt
, sp
: Span
, tok
: &token
::Token
) -> P
<ast
::Expr
> {
550 macro_rules
! mk_lit
{
551 ($name
: expr
, $suffix
: expr
, $
($args
: expr
),*) => {{
552 let inner
= cx
.expr_call(sp
, mk_token_path(cx
, sp
, $name
), vec
![$
($args
),*]);
553 let suffix
= match $suffix
{
554 Some(name
) => cx
.expr_some(sp
, mk_name(cx
, sp
, ast
::Ident
::new(name
))),
555 None
=> cx
.expr_none(sp
)
557 cx
.expr_call(sp
, mk_token_path(cx
, sp
, "Literal"), vec
![inner
, suffix
])
561 token
::BinOp(binop
) => {
562 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "BinOp"), vec
!(mk_binop(cx
, sp
, binop
)));
564 token
::BinOpEq(binop
) => {
565 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "BinOpEq"),
566 vec
!(mk_binop(cx
, sp
, binop
)));
569 token
::OpenDelim(delim
) => {
570 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "OpenDelim"),
571 vec
![mk_delim(cx
, sp
, delim
)]);
573 token
::CloseDelim(delim
) => {
574 return cx
.expr_call(sp
, mk_token_path(cx
, sp
, "CloseDelim"),
575 vec
![mk_delim(cx
, sp
, delim
)]);
578 token
::Literal(token
::Byte(i
), suf
) => {
579 let e_byte
= mk_name(cx
, sp
, i
.ident());
580 return mk_lit
!("Byte", suf
, e_byte
);
583 token
::Literal(token
::Char(i
), suf
) => {
584 let e_char
= mk_name(cx
, sp
, i
.ident());
585 return mk_lit
!("Char", suf
, e_char
);
588 token
::Literal(token
::Integer(i
), suf
) => {
589 let e_int
= mk_name(cx
, sp
, i
.ident());
590 return mk_lit
!("Integer", suf
, e_int
);
593 token
::Literal(token
::Float(fident
), suf
) => {
594 let e_fident
= mk_name(cx
, sp
, fident
.ident());
595 return mk_lit
!("Float", suf
, e_fident
);
598 token
::Literal(token
::Str_(ident
), suf
) => {
599 return mk_lit
!("Str_", suf
, mk_name(cx
, sp
, ident
.ident()))
602 token
::Literal(token
::StrRaw(ident
, n
), suf
) => {
603 return mk_lit
!("StrRaw", suf
, mk_name(cx
, sp
, ident
.ident()), cx
.expr_usize(sp
, n
))
606 token
::Ident(ident
, style
) => {
607 return cx
.expr_call(sp
,
608 mk_token_path(cx
, sp
, "Ident"),
609 vec
![mk_ident(cx
, sp
, ident
),
611 ModName
=> mk_token_path(cx
, sp
, "ModName"),
612 Plain
=> mk_token_path(cx
, sp
, "Plain"),
616 token
::Lifetime(ident
) => {
617 return cx
.expr_call(sp
,
618 mk_token_path(cx
, sp
, "Lifetime"),
619 vec
!(mk_ident(cx
, sp
, ident
)));
622 token
::DocComment(ident
) => {
623 return cx
.expr_call(sp
,
624 mk_token_path(cx
, sp
, "DocComment"),
625 vec
!(mk_name(cx
, sp
, ident
.ident())));
628 token
::MatchNt(name
, kind
, namep
, kindp
) => {
629 return cx
.expr_call(sp
,
630 mk_token_path(cx
, sp
, "MatchNt"),
631 vec
!(mk_ident(cx
, sp
, name
),
632 mk_ident(cx
, sp
, kind
),
634 ModName
=> mk_token_path(cx
, sp
, "ModName"),
635 Plain
=> mk_token_path(cx
, sp
, "Plain"),
638 ModName
=> mk_token_path(cx
, sp
, "ModName"),
639 Plain
=> mk_token_path(cx
, sp
, "Plain"),
643 token
::Interpolated(_
) => panic
!("quote! with interpolated token"),
648 let name
= match *tok
{
652 token
::EqEq
=> "EqEq",
656 token
::AndAnd
=> "AndAnd",
657 token
::OrOr
=> "OrOr",
659 token
::Tilde
=> "Tilde",
662 token
::DotDot
=> "DotDot",
663 token
::Comma
=> "Comma",
664 token
::Semi
=> "Semi",
665 token
::Colon
=> "Colon",
666 token
::ModSep
=> "ModSep",
667 token
::RArrow
=> "RArrow",
668 token
::LArrow
=> "LArrow",
669 token
::FatArrow
=> "FatArrow",
670 token
::Pound
=> "Pound",
671 token
::Dollar
=> "Dollar",
672 token
::Question
=> "Question",
673 token
::Underscore
=> "Underscore",
675 _
=> panic
!("unhandled token in quote!"),
677 mk_token_path(cx
, sp
, name
)
680 fn statements_mk_tt(cx
: &ExtCtxt
, tt
: &ast
::TokenTree
, matcher
: bool
) -> Vec
<P
<ast
::Stmt
>> {
682 ast
::TtToken(sp
, SubstNt(ident
, _
)) => {
683 // tt.extend($ident.to_tokens(ext_cx).into_iter())
686 cx
.expr_method_call(sp
,
687 cx
.expr_ident(sp
, ident
),
689 vec
!(cx
.expr_ident(sp
, id_ext("ext_cx"))));
691 cx
.expr_method_call(sp
, e_to_toks
, id_ext("into_iter"), vec
![]);
694 cx
.expr_method_call(sp
,
695 cx
.expr_ident(sp
, id_ext("tt")),
699 vec
!(cx
.stmt_expr(e_push
))
701 ref tt @ ast
::TtToken(_
, MatchNt(..)) if !matcher
=> {
702 let mut seq
= vec
![];
703 for i
in 0..tt
.len() {
704 seq
.push(tt
.get_tt(i
));
706 statements_mk_tts(cx
, &seq
[..], matcher
)
708 ast
::TtToken(sp
, ref tok
) => {
709 let e_sp
= cx
.expr_ident(sp
, id_ext("_sp"));
710 let e_tok
= cx
.expr_call(sp
,
711 mk_ast_path(cx
, sp
, "TtToken"),
712 vec
!(e_sp
, expr_mk_token(cx
, sp
, tok
)));
714 cx
.expr_method_call(sp
,
715 cx
.expr_ident(sp
, id_ext("tt")),
718 vec
!(cx
.stmt_expr(e_push
))
720 ast
::TtDelimited(_
, ref delimed
) => {
721 statements_mk_tt(cx
, &delimed
.open_tt(), matcher
).into_iter()
722 .chain(delimed
.tts
.iter()
723 .flat_map(|tt
| statements_mk_tt(cx
, tt
, matcher
).into_iter()))
724 .chain(statements_mk_tt(cx
, &delimed
.close_tt(), matcher
).into_iter())
727 ast
::TtSequence(sp
, ref seq
) => {
729 panic
!("TtSequence in quote!");
732 let e_sp
= cx
.expr_ident(sp
, id_ext("_sp"));
734 let stmt_let_tt
= cx
.stmt_let(sp
, true, id_ext("tt"), cx
.expr_vec_ng(sp
));
735 let mut tts_stmts
= vec
![stmt_let_tt
];
736 tts_stmts
.extend(statements_mk_tts(cx
, &seq
.tts
[..], matcher
).into_iter());
737 let e_tts
= cx
.expr_block(cx
.block(sp
, tts_stmts
,
738 Some(cx
.expr_ident(sp
, id_ext("tt")))));
739 let e_separator
= match seq
.separator
{
740 Some(ref sep
) => cx
.expr_some(sp
, expr_mk_token(cx
, sp
, sep
)),
741 None
=> cx
.expr_none(sp
),
743 let e_op
= match seq
.op
{
744 ast
::ZeroOrMore
=> mk_ast_path(cx
, sp
, "ZeroOrMore"),
745 ast
::OneOrMore
=> mk_ast_path(cx
, sp
, "OneOrMore"),
747 let fields
= vec
![cx
.field_imm(sp
, id_ext("tts"), e_tts
),
748 cx
.field_imm(sp
, id_ext("separator"), e_separator
),
749 cx
.field_imm(sp
, id_ext("op"), e_op
),
750 cx
.field_imm(sp
, id_ext("num_captures"),
751 cx
.expr_usize(sp
, seq
.num_captures
))];
752 let seq_path
= vec
![id_ext("syntax"), id_ext("ast"), id_ext("SequenceRepetition")];
753 let e_seq_struct
= cx
.expr_struct(sp
, cx
.path_global(sp
, seq_path
), fields
);
754 let e_rc_new
= cx
.expr_call_global(sp
, vec
![id_ext("std"),
759 let e_tok
= cx
.expr_call(sp
,
760 mk_ast_path(cx
, sp
, "TtSequence"),
761 vec
!(e_sp
, e_rc_new
));
763 cx
.expr_method_call(sp
,
764 cx
.expr_ident(sp
, id_ext("tt")),
767 vec
!(cx
.stmt_expr(e_push
))
772 fn parse_arguments_to_quote(cx
: &ExtCtxt
, tts
: &[ast
::TokenTree
])
773 -> (P
<ast
::Expr
>, Vec
<ast
::TokenTree
>) {
774 // NB: It appears that the main parser loses its mind if we consider
775 // $foo as a SubstNt during the main parse, so we have to re-parse
776 // under quote_depth > 0. This is silly and should go away; the _guess_ is
777 // it has to do with transition away from supporting old-style macros, so
778 // try removing it when enough of them are gone.
780 let mut p
= cx
.new_parser_from_tts(tts
);
783 let cx_expr
= p
.parse_expr();
784 if !p
.eat(&token
::Comma
) {
785 p
.fatal("expected token `,`");
788 let tts
= p
.parse_all_token_trees();
794 fn mk_stmts_let(cx
: &ExtCtxt
, sp
: Span
) -> Vec
<P
<ast
::Stmt
>> {
795 // We also bind a single value, sp, to ext_cx.call_site()
797 // This causes every span in a token-tree quote to be attributed to the
798 // call site of the extension using the quote. We can't really do much
799 // better since the source of the quote may well be in a library that
800 // was not even parsed by this compilation run, that the user has no
801 // source code for (eg. in libsyntax, which they're just _using_).
803 // The old quasiquoter had an elaborate mechanism for denoting input
804 // file locations from which quotes originated; unfortunately this
805 // relied on feeding the source string of the quote back into the
806 // compiler (which we don't really want to do) and, in any case, only
807 // pushed the problem a very small step further back: an error
808 // resulting from a parse of the resulting quote is still attributed to
809 // the site the string literal occurred, which was in a source file
810 // _other_ than the one the user has control over. For example, an
811 // error in a quote from the protocol compiler, invoked in user code
812 // using macro_rules! for example, will be attributed to the macro_rules.rs
813 // file in libsyntax, which the user might not even have source to (unless
814 // they happen to have a compiler on hand). Over all, the phase distinction
815 // just makes quotes "hard to attribute". Possibly this could be fixed
816 // by recreating some of the original qq machinery in the tt regime
817 // (pushing fake FileMaps onto the parser to account for original sites
818 // of quotes, for example) but at this point it seems not likely to be
821 let e_sp
= cx
.expr_method_call(sp
,
822 cx
.expr_ident(sp
, id_ext("ext_cx")),
826 let stmt_let_sp
= cx
.stmt_let(sp
, false,
830 let stmt_let_tt
= cx
.stmt_let(sp
, true, id_ext("tt"), cx
.expr_vec_ng(sp
));
832 vec
!(stmt_let_sp
, stmt_let_tt
)
835 fn statements_mk_tts(cx
: &ExtCtxt
, tts
: &[ast
::TokenTree
], matcher
: bool
) -> Vec
<P
<ast
::Stmt
>> {
836 let mut ss
= Vec
::new();
838 ss
.extend(statements_mk_tt(cx
, tt
, matcher
).into_iter());
843 fn expand_tts(cx
: &ExtCtxt
, sp
: Span
, tts
: &[ast
::TokenTree
])
844 -> (P
<ast
::Expr
>, P
<ast
::Expr
>) {
845 let (cx_expr
, tts
) = parse_arguments_to_quote(cx
, tts
);
847 let mut vector
= mk_stmts_let(cx
, sp
);
848 vector
.extend(statements_mk_tts(cx
, &tts
[..], false).into_iter());
849 let block
= cx
.expr_block(
852 Some(cx
.expr_ident(sp
, id_ext("tt")))));
857 fn expand_wrapper(cx
: &ExtCtxt
,
859 cx_expr
: P
<ast
::Expr
>,
861 imports
: &[&[&str]]) -> P
<ast
::Expr
> {
862 // Explicitly borrow to avoid moving from the invoker (#16992)
863 let cx_expr_borrow
= cx
.expr_addr_of(sp
, cx
.expr_deref(sp
, cx_expr
));
864 let stmt_let_ext_cx
= cx
.stmt_let(sp
, false, id_ext("ext_cx"), cx_expr_borrow
);
866 let stmts
= imports
.iter().map(|path
| {
867 // make item: `use ...;`
868 let path
= path
.iter().map(|s
| s
.to_string()).collect();
869 cx
.stmt_item(sp
, cx
.item_use_glob(sp
, ast
::Inherited
, ids_ext(path
)))
870 }).chain(Some(stmt_let_ext_cx
).into_iter()).collect();
872 cx
.expr_block(cx
.block_all(sp
, stmts
, Some(expr
)))
875 fn expand_parse_call(cx
: &ExtCtxt
,
878 arg_exprs
: Vec
<P
<ast
::Expr
>> ,
879 tts
: &[ast
::TokenTree
]) -> P
<ast
::Expr
> {
880 let (cx_expr
, tts_expr
) = expand_tts(cx
, sp
, tts
);
882 let cfg_call
= || cx
.expr_method_call(
883 sp
, cx
.expr_ident(sp
, id_ext("ext_cx")),
884 id_ext("cfg"), Vec
::new());
886 let parse_sess_call
= || cx
.expr_method_call(
887 sp
, cx
.expr_ident(sp
, id_ext("ext_cx")),
888 id_ext("parse_sess"), Vec
::new());
890 let new_parser_call
=
892 cx
.expr_ident(sp
, id_ext("new_parser_from_tts")),
893 vec
!(parse_sess_call(), cfg_call(), tts_expr
));
895 let expr
= cx
.expr_method_call(sp
, new_parser_call
, id_ext(parse_method
),
898 if parse_method
== "parse_attribute" {
899 expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"],
900 &["syntax", "parse", "attr"]])
902 expand_wrapper(cx
, sp
, cx_expr
, expr
, &[&["syntax", "ext", "quote", "rt"]])