1 // Copyright 2012-2014 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
::{Block, Crate, DeclLocal, ExprMac, PatMac}
;
12 use ast
::{Local, Ident, MacInvocTT}
;
13 use ast
::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac}
;
14 use ast
::{StmtExpr, StmtSemi}
;
18 use ext
::build
::AstBuilder
;
20 use attr
::AttrMetaMethods
;
22 use codemap
::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, CompilerExpansion}
;
24 use feature_gate
::{self, Features}
;
28 use parse
::token
::{fresh_mark, fresh_name, intern}
;
31 use util
::small_vector
::SmallVector
;
36 // Given suffix ["b","c","d"], returns path `::std::b::c::d` when
37 // `fld.cx.use_std`, and `::core::b::c::d` otherwise.
38 fn mk_core_path(fld
: &mut MacroExpander
,
40 suffix
: &[&'
static str]) -> ast
::Path
{
41 let mut idents
= vec
![fld
.cx
.ident_of_std("core")];
42 for s
in suffix
.iter() { idents.push(fld.cx.ident_of(*s)); }
43 fld
.cx
.path_global(span
, idents
)
46 pub fn expand_expr(e
: P
<ast
::Expr
>, fld
: &mut MacroExpander
) -> P
<ast
::Expr
> {
47 fn push_compiler_expansion(fld
: &mut MacroExpander
, span
: Span
, expansion_desc
: &str) {
48 fld
.cx
.bt_push(ExpnInfo
{
51 name
: expansion_desc
.to_string(),
52 format
: CompilerExpansion
,
54 // This does *not* mean code generated after
55 // `push_compiler_expansion` is automatically exempt
56 // from stability lints; must also tag such code with
57 // an appropriate span from `fld.cx.backtrace()`.
58 allow_internal_unstable
: true,
65 // Sets the expn_id so that we can use unstable methods.
66 fn allow_unstable(fld
: &mut MacroExpander
, span
: Span
) -> Span
{
67 Span { expn_id: fld.cx.backtrace(), ..span }
70 let expr_span
= e
.span
;
71 return e
.and_then(|ast
::Expr {id, node, span}
| match node
{
73 // expr_mac should really be expr_ext or something; it's the
74 // entry-point for all syntax extensions.
75 ast
::ExprMac(mac
) => {
76 let expanded_expr
= match expand_mac_invoc(mac
, span
,
81 return DummyResult
::raw_expr(span
);
85 // Keep going, outside-in.
86 let fully_expanded
= fld
.fold_expr(expanded_expr
);
87 let span
= fld
.new_span(span
);
90 fully_expanded
.map(|e
| ast
::Expr
{
91 id
: ast
::DUMMY_NODE_ID
,
97 // Desugar ExprBox: `in (PLACE) EXPR`
98 ast
::ExprBox(Some(placer
), value_expr
) => {
102 // let mut place = Placer::make_place(p);
103 // let raw_place = Place::pointer(&mut place);
105 // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
106 // InPlace::finalize(place)
109 // Ensure feature-gate is enabled
110 feature_gate
::check_for_placement_in(
111 fld
.cx
.ecfg
.features
,
112 &fld
.cx
.parse_sess
.span_diagnostic
,
115 push_compiler_expansion(fld
, expr_span
, "placement-in expansion");
117 let value_span
= value_expr
.span
;
118 let placer_span
= placer
.span
;
120 let placer_expr
= fld
.fold_expr(placer
);
121 let value_expr
= fld
.fold_expr(value_expr
);
123 let placer_ident
= token
::gensym_ident("placer");
124 let agent_ident
= token
::gensym_ident("place");
125 let p_ptr_ident
= token
::gensym_ident("p_ptr");
127 let placer
= fld
.cx
.expr_ident(span
, placer_ident
);
128 let agent
= fld
.cx
.expr_ident(span
, agent_ident
);
129 let p_ptr
= fld
.cx
.expr_ident(span
, p_ptr_ident
);
131 let make_place
= ["ops", "Placer", "make_place"];
132 let place_pointer
= ["ops", "Place", "pointer"];
133 let move_val_init
= ["intrinsics", "move_val_init"];
134 let inplace_finalize
= ["ops", "InPlace", "finalize"];
136 let make_call
= |fld
: &mut MacroExpander
, p
, args
| {
137 // We feed in the `expr_span` because codemap's span_allows_unstable
138 // allows the call_site span to inherit the `allow_internal_unstable`
140 let span_unstable
= allow_unstable(fld
, expr_span
);
141 let path
= mk_core_path(fld
, span_unstable
, p
);
142 let path
= fld
.cx
.expr_path(path
);
143 let expr_span_unstable
= allow_unstable(fld
, span
);
144 fld
.cx
.expr_call(expr_span_unstable
, path
, args
)
147 let stmt_let
= |fld
: &mut MacroExpander
, bind
, expr
| {
148 fld
.cx
.stmt_let(placer_span
, false, bind
, expr
)
150 let stmt_let_mut
= |fld
: &mut MacroExpander
, bind
, expr
| {
151 fld
.cx
.stmt_let(placer_span
, true, bind
, expr
)
154 // let placer = <placer_expr> ;
155 let s1
= stmt_let(fld
, placer_ident
, placer_expr
);
157 // let mut place = Placer::make_place(placer);
159 let call
= make_call(fld
, &make_place
, vec
![placer
]);
160 stmt_let_mut(fld
, agent_ident
, call
)
163 // let p_ptr = Place::pointer(&mut place);
165 let args
= vec
![fld
.cx
.expr_mut_addr_of(placer_span
, agent
.clone())];
166 let call
= make_call(fld
, &place_pointer
, args
);
167 stmt_let(fld
, p_ptr_ident
, call
)
170 // pop_unsafe!(EXPR));
171 let pop_unsafe_expr
= pop_unsafe_expr(fld
.cx
, value_expr
, value_span
);
174 // ptr::write(p_ptr, pop_unsafe!(<value_expr>));
175 // InPlace::finalize(place)
178 let call_move_val_init
= StmtSemi(make_call(
179 fld
, &move_val_init
, vec
![p_ptr
, pop_unsafe_expr
]), ast
::DUMMY_NODE_ID
);
180 let call_move_val_init
= codemap
::respan(value_span
, call_move_val_init
);
182 let call
= make_call(fld
, &inplace_finalize
, vec
![agent
]);
183 Some(push_unsafe_expr(fld
.cx
, vec
![P(call_move_val_init
)], call
, span
))
186 let block
= fld
.cx
.block_all(span
, vec
![s1
, s2
, s3
], expr
);
187 let result
= fld
.cx
.expr_block(block
);
193 // Eventually a desugaring for `box EXPR`
194 // (similar to the desugaring above for `in PLACE BLOCK`)
195 // should go here, desugaring
199 // let mut place = BoxPlace::make_place();
200 // let raw_place = Place::pointer(&mut place);
201 // let value = $value;
203 // ::std::ptr::write(raw_place, value);
204 // Boxed::finalize(place)
207 // But for now there are type-inference issues doing that.
209 ast
::ExprWhile(cond
, body
, opt_ident
) => {
210 let cond
= fld
.fold_expr(cond
);
211 let (body
, opt_ident
) = expand_loop_block(body
, opt_ident
, fld
);
212 fld
.cx
.expr(span
, ast
::ExprWhile(cond
, body
, opt_ident
))
215 // Desugar ExprWhileLet
216 // From: `[opt_ident]: while let <pat> = <expr> <body>`
217 ast
::ExprWhileLet(pat
, expr
, body
, opt_ident
) => {
220 // [opt_ident]: loop {
227 push_compiler_expansion(fld
, span
, "while let expansion");
231 let body_expr
= fld
.cx
.expr_block(body
);
232 fld
.cx
.arm(pat
.span
, vec
![pat
], body_expr
)
237 let pat_under
= fld
.cx
.pat_wild(span
);
238 let break_expr
= fld
.cx
.expr_break(span
);
239 fld
.cx
.arm(span
, vec
![pat_under
], break_expr
)
242 // `match <expr> { ... }`
243 let arms
= vec
![pat_arm
, break_arm
];
244 let match_expr
= fld
.cx
.expr(span
,
245 ast
::ExprMatch(expr
, arms
, ast
::MatchSource
::WhileLetDesugar
));
247 // `[opt_ident]: loop { ... }`
248 let loop_block
= fld
.cx
.block_expr(match_expr
);
249 let (loop_block
, opt_ident
) = expand_loop_block(loop_block
, opt_ident
, fld
);
250 let result
= fld
.cx
.expr(span
, ast
::ExprLoop(loop_block
, opt_ident
));
256 // From: `if let <pat> = <expr> <body> [<elseopt>]`
257 ast
::ExprIfLet(pat
, expr
, body
, mut elseopt
) => {
262 // [_ if <elseopt_if_cond> => <elseopt_if_body>,]
263 // _ => [<elseopt> | ()]
266 push_compiler_expansion(fld
, span
, "if let expansion");
270 let body_expr
= fld
.cx
.expr_block(body
);
271 fld
.cx
.arm(pat
.span
, vec
![pat
], body_expr
)
274 // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
276 let mut arms
= vec
![];
278 let elseopt_continue
= elseopt
279 .and_then(|els
| els
.and_then(|els
| match els
.node
{
281 ast
::ExprIf(cond
, then
, elseopt
) => {
282 let pat_under
= fld
.cx
.pat_wild(span
);
285 pats
: vec
![pat_under
],
287 body
: fld
.cx
.expr_block(then
)
289 elseopt
.map(|elseopt
| (elseopt
, true))
291 _
=> Some((P(els
), false))
293 match elseopt_continue
{
297 Some((e
, false)) => {
310 let contains_else_clause
= elseopt
.is_some();
312 // `_ => [<elseopt> | ()]`
314 let pat_under
= fld
.cx
.pat_wild(span
);
315 let else_expr
= elseopt
.unwrap_or_else(|| fld
.cx
.expr_tuple(span
, vec
![]));
316 fld
.cx
.arm(span
, vec
![pat_under
], else_expr
)
319 let mut arms
= Vec
::with_capacity(else_if_arms
.len() + 2);
321 arms
.extend(else_if_arms
);
324 let match_expr
= fld
.cx
.expr(span
,
325 ast
::ExprMatch(expr
, arms
,
326 ast
::MatchSource
::IfLetDesugar
{
327 contains_else_clause
: contains_else_clause
,
329 let result
= fld
.fold_expr(match_expr
);
334 // Desugar support for ExprIfLet in the ExprIf else position
335 ast
::ExprIf(cond
, blk
, elseopt
) => {
336 let elseopt
= elseopt
.map(|els
| els
.and_then(|els
| match els
.node
{
337 ast
::ExprIfLet(..) => {
338 push_compiler_expansion(fld
, span
, "if let expansion");
339 // wrap the if-let expr in a block
341 let blk
= P(ast
::Block
{
344 id
: ast
::DUMMY_NODE_ID
,
345 rules
: ast
::DefaultBlock
,
348 let result
= fld
.cx
.expr_block(blk
);
354 let if_expr
= fld
.cx
.expr(span
, ast
::ExprIf(cond
, blk
, elseopt
));
355 if_expr
.map(|e
| noop_fold_expr(e
, fld
))
358 ast
::ExprLoop(loop_block
, opt_ident
) => {
359 let (loop_block
, opt_ident
) = expand_loop_block(loop_block
, opt_ident
, fld
);
360 fld
.cx
.expr(span
, ast
::ExprLoop(loop_block
, opt_ident
))
363 // Desugar ExprForLoop
364 // From: `[opt_ident]: for <pat> in <head> <body>`
365 ast
::ExprForLoop(pat
, head
, body
, opt_ident
) => {
369 // let result = match ::std::iter::IntoIterator::into_iter(<head>) {
371 // [opt_ident]: loop {
372 // match ::std::iter::Iterator::next(&mut iter) {
373 // ::std::option::Option::Some(<pat>) => <body>,
374 // ::std::option::Option::None => break
382 push_compiler_expansion(fld
, span
, "for loop expansion");
384 let span
= fld
.new_span(span
);
387 let head
= fld
.fold_expr(head
);
389 // create an hygienic ident
391 let ident
= fld
.cx
.ident_of("iter");
392 let new_ident
= fresh_name(&ident
);
393 let rename
= (ident
, new_ident
);
394 let mut rename_list
= vec
![rename
];
395 let mut rename_fld
= IdentRenamer{ renames: &mut rename_list }
;
397 rename_fld
.fold_ident(ident
)
400 let pat_span
= fld
.new_span(pat
.span
);
401 // `::std::option::Option::Some(<pat>) => <body>`
403 let body_expr
= fld
.cx
.expr_block(body
);
404 let pat
= noop_fold_pat(pat
, fld
);
405 let some_pat
= fld
.cx
.pat_some(pat_span
, pat
);
407 fld
.cx
.arm(pat_span
, vec
![some_pat
], body_expr
)
410 // `::std::option::Option::None => break`
412 let break_expr
= fld
.cx
.expr_break(span
);
414 fld
.cx
.arm(span
, vec
![fld
.cx
.pat_none(span
)], break_expr
)
417 // `match ::std::iter::Iterator::next(&mut iter) { ... }`
421 fld
.cx
.ident_of_std("core"),
422 fld
.cx
.ident_of("iter"),
423 fld
.cx
.ident_of("Iterator"),
424 fld
.cx
.ident_of("next"),
427 fld
.cx
.path_global(span
, strs
)
429 let ref_mut_iter
= fld
.cx
.expr_mut_addr_of(span
, fld
.cx
.expr_ident(span
, iter
));
431 fld
.cx
.expr_call(span
, fld
.cx
.expr_path(next_path
), vec
![ref_mut_iter
]);
432 let arms
= vec
![pat_arm
, break_arm
];
434 fld
.cx
.expr(pat_span
,
435 ast
::ExprMatch(next_expr
, arms
, ast
::MatchSource
::ForLoopDesugar
))
438 // `[opt_ident]: loop { ... }`
439 let loop_block
= fld
.cx
.block_expr(match_expr
);
440 let (loop_block
, opt_ident
) = expand_loop_block(loop_block
, opt_ident
, fld
);
441 let loop_expr
= fld
.cx
.expr(span
, ast
::ExprLoop(loop_block
, opt_ident
));
443 // `mut iter => { ... }`
446 fld
.cx
.pat_ident_binding_mode(span
, iter
, ast
::BindByValue(ast
::MutMutable
));
447 fld
.cx
.arm(span
, vec
![iter_pat
], loop_expr
)
450 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
451 let into_iter_expr
= {
452 let into_iter_path
= {
454 fld
.cx
.ident_of_std("core"),
455 fld
.cx
.ident_of("iter"),
456 fld
.cx
.ident_of("IntoIterator"),
457 fld
.cx
.ident_of("into_iter"),
460 fld
.cx
.path_global(span
, strs
)
463 fld
.cx
.expr_call(span
, fld
.cx
.expr_path(into_iter_path
), vec
![head
])
466 let match_expr
= fld
.cx
.expr_match(span
, into_iter_expr
, vec
![iter_arm
]);
468 // `{ let result = ...; result }`
469 let result_ident
= token
::gensym_ident("result");
470 let result
= fld
.cx
.expr_block(
473 vec
![fld
.cx
.stmt_let(span
, false, result_ident
, match_expr
)],
474 Some(fld
.cx
.expr_ident(span
, result_ident
))));
479 ast
::ExprClosure(capture_clause
, fn_decl
, block
) => {
480 push_compiler_expansion(fld
, span
, "closure expansion");
481 let (rewritten_fn_decl
, rewritten_block
)
482 = expand_and_rename_fn_decl_and_block(fn_decl
, block
, fld
);
483 let new_node
= ast
::ExprClosure(capture_clause
,
486 let result
= P(ast
::Expr{id:id, node: new_node, span: fld.new_span(span)}
);
492 P(noop_fold_expr(ast
::Expr
{
500 fn push_unsafe_expr(cx
: &mut ExtCtxt
, stmts
: Vec
<P
<ast
::Stmt
>>,
501 expr
: P
<ast
::Expr
>, span
: Span
)
503 let rules
= ast
::PushUnsafeBlock(ast
::CompilerGenerated
);
504 cx
.expr_block(P(ast
::Block
{
505 rules
: rules
, span
: span
, id
: ast
::DUMMY_NODE_ID
,
506 stmts
: stmts
, expr
: Some(expr
),
510 fn pop_unsafe_expr(cx
: &mut ExtCtxt
, expr
: P
<ast
::Expr
>, span
: Span
)
512 let rules
= ast
::PopUnsafeBlock(ast
::CompilerGenerated
);
513 cx
.expr_block(P(ast
::Block
{
514 rules
: rules
, span
: span
, id
: ast
::DUMMY_NODE_ID
,
515 stmts
: vec
![], expr
: Some(expr
),
520 /// Expand a (not-ident-style) macro invocation. Returns the result
521 /// of expansion and the mark which must be applied to the result.
522 /// Our current interface doesn't allow us to apply the mark to the
523 /// result until after calling make_expr, make_items, etc.
524 fn expand_mac_invoc
<T
, F
, G
>(mac
: ast
::Mac
,
528 fld
: &mut MacroExpander
)
530 F
: for<'a
> FnOnce(Box
<MacResult
+'a
>) -> Option
<T
>,
531 G
: FnOnce(T
, Mrk
) -> T
,
534 // it would almost certainly be cleaner to pass the whole
535 // macro invocation in, rather than pulling it apart and
536 // marking the tts and the ctxt separately. This also goes
537 // for the other three macro invocation chunks of code
539 // Token-tree macros:
540 MacInvocTT(pth
, tts
, _
) => {
541 if pth
.segments
.len() > 1 {
542 fld
.cx
.span_err(pth
.span
,
543 "expected macro name without module \
545 // let compilation continue
548 let extname
= pth
.segments
[0].identifier
.name
;
549 match fld
.cx
.syntax_env
.find(&extname
) {
553 &format
!("macro undefined: '{}!'",
556 // let compilation continue
559 Some(rc
) => match *rc
{
560 NormalTT(ref expandfun
, exp_span
, allow_internal_unstable
) => {
561 fld
.cx
.bt_push(ExpnInfo
{
563 callee
: NameAndSpan
{
564 name
: extname
.to_string(),
567 allow_internal_unstable
: allow_internal_unstable
,
570 let fm
= fresh_mark();
571 let marked_before
= mark_tts(&tts
[..], fm
);
573 // The span that we pass to the expanders we want to
574 // be the root of the call stack. That's the most
575 // relevant span and it's the actual invocation of
577 let mac_span
= fld
.cx
.original_span();
580 let expanded
= expandfun
.expand(fld
.cx
,
583 parse_thunk(expanded
)
585 let parsed
= match opt_parsed
{
590 &format
!("non-expression macro in expression position: {}",
596 Some(mark_thunk(parsed
,fm
))
601 &format
!("'{}' is not a tt-style macro",
611 /// Rename loop label and expand its loop body
613 /// The renaming procedure for loop is different in the sense that the loop
614 /// body is in a block enclosed by loop head so the renaming of loop label
615 /// must be propagated to the enclosed context.
616 fn expand_loop_block(loop_block
: P
<Block
>,
617 opt_ident
: Option
<Ident
>,
618 fld
: &mut MacroExpander
) -> (P
<Block
>, Option
<Ident
>) {
621 let new_label
= fresh_name(&label
);
622 let rename
= (label
, new_label
);
624 // The rename *must not* be added to the pending list of current
625 // syntax context otherwise an unrelated `break` or `continue` in
626 // the same context will pick that up in the deferred renaming pass
627 // and be renamed incorrectly.
628 let mut rename_list
= vec
!(rename
);
629 let mut rename_fld
= IdentRenamer{renames: &mut rename_list}
;
630 let renamed_ident
= rename_fld
.fold_ident(label
);
632 // The rename *must* be added to the enclosed syntax context for
633 // `break` or `continue` to pick up because by definition they are
634 // in a block enclosed by loop head.
635 fld
.cx
.syntax_env
.push_frame();
636 fld
.cx
.syntax_env
.info().pending_renames
.push(rename
);
637 let expanded_block
= expand_block_elts(loop_block
, fld
);
638 fld
.cx
.syntax_env
.pop_frame();
640 (expanded_block
, Some(renamed_ident
))
642 None
=> (fld
.fold_block(loop_block
), opt_ident
)
646 // eval $e with a new exts frame.
647 // must be a macro so that $e isn't evaluated too early.
648 macro_rules
! with_exts_frame
{
649 ($extsboxexpr
:expr
,$macros_escape
:expr
,$e
:expr
) =>
650 ({$extsboxexpr
.push_frame();
651 $extsboxexpr
.info().macros_escape
= $macros_escape
;
653 $extsboxexpr
.pop_frame();
658 // When we enter a module, record it, for the sake of `module!`
659 pub fn expand_item(it
: P
<ast
::Item
>, fld
: &mut MacroExpander
)
660 -> SmallVector
<P
<ast
::Item
>> {
661 let it
= expand_item_modifiers(it
, fld
);
663 expand_annotatable(Annotatable
::Item(it
), fld
)
664 .into_iter().map(|i
| i
.expect_item()).collect()
667 /// Expand item_underscore
668 fn expand_item_underscore(item
: ast
::Item_
, fld
: &mut MacroExpander
) -> ast
::Item_
{
670 ast
::ItemFn(decl
, unsafety
, constness
, abi
, generics
, body
) => {
671 let (rewritten_fn_decl
, rewritten_body
)
672 = expand_and_rename_fn_decl_and_block(decl
, body
, fld
);
673 let expanded_generics
= fold
::noop_fold_generics(generics
,fld
);
674 ast
::ItemFn(rewritten_fn_decl
, unsafety
, constness
, abi
,
675 expanded_generics
, rewritten_body
)
677 _
=> noop_fold_item_underscore(item
, fld
)
681 // does this attribute list contain "macro_use" ?
682 fn contains_macro_use(fld
: &mut MacroExpander
, attrs
: &[ast
::Attribute
]) -> bool
{
684 let mut is_use
= attr
.check_name("macro_use");
685 if attr
.check_name("macro_escape") {
686 fld
.cx
.span_warn(attr
.span
, "macro_escape is a deprecated synonym for macro_use");
688 if let ast
::AttrInner
= attr
.node
.style
{
689 fld
.cx
.fileline_help(attr
.span
, "consider an outer attribute, \
690 #[macro_use] mod ...");
695 match attr
.node
.value
.node
{
696 ast
::MetaWord(..) => (),
697 _
=> fld
.cx
.span_err(attr
.span
, "arguments to macro_use are not allowed here"),
705 // Support for item-position macro invocations, exactly the same
706 // logic as for expression-position macro invocations.
707 pub fn expand_item_mac(it
: P
<ast
::Item
>,
708 fld
: &mut MacroExpander
) -> SmallVector
<P
<ast
::Item
>> {
709 let (extname
, path_span
, tts
) = match it
.node
{
710 ItemMac(codemap
::Spanned
{
711 node
: MacInvocTT(ref pth
, ref tts
, _
),
714 (pth
.segments
[0].identifier
.name
, pth
.span
, (*tts
).clone())
716 _
=> fld
.cx
.span_bug(it
.span
, "invalid item macro invocation")
719 let fm
= fresh_mark();
721 let expanded
= match fld
.cx
.syntax_env
.find(&extname
) {
723 fld
.cx
.span_err(path_span
,
724 &format
!("macro undefined: '{}!'",
726 // let compilation continue
727 return SmallVector
::zero();
730 Some(rc
) => match *rc
{
731 NormalTT(ref expander
, span
, allow_internal_unstable
) => {
732 if it
.ident
.name
!= parse
::token
::special_idents
::invalid
.name
{
735 &format
!("macro {}! expects no ident argument, given '{}'",
738 return SmallVector
::zero();
740 fld
.cx
.bt_push(ExpnInfo
{
742 callee
: NameAndSpan
{
743 name
: extname
.to_string(),
746 allow_internal_unstable
: allow_internal_unstable
,
749 // mark before expansion:
750 let marked_before
= mark_tts(&tts
[..], fm
);
751 expander
.expand(fld
.cx
, it
.span
, &marked_before
[..])
753 IdentTT(ref expander
, span
, allow_internal_unstable
) => {
754 if it
.ident
.name
== parse
::token
::special_idents
::invalid
.name
{
755 fld
.cx
.span_err(path_span
,
756 &format
!("macro {}! expects an ident argument",
758 return SmallVector
::zero();
760 fld
.cx
.bt_push(ExpnInfo
{
762 callee
: NameAndSpan
{
763 name
: extname
.to_string(),
766 allow_internal_unstable
: allow_internal_unstable
,
769 // mark before expansion:
770 let marked_tts
= mark_tts(&tts
[..], fm
);
771 expander
.expand(fld
.cx
, it
.span
, it
.ident
, marked_tts
)
774 if it
.ident
.name
== parse
::token
::special_idents
::invalid
.name
{
775 fld
.cx
.span_err(path_span
,
776 &format
!("macro_rules! expects an ident argument")
778 return SmallVector
::zero();
781 fld
.cx
.bt_push(ExpnInfo
{
783 callee
: NameAndSpan
{
784 name
: extname
.to_string(),
787 // `macro_rules!` doesn't directly allow
788 // unstable (this is orthogonal to whether
789 // the macro it creates allows it)
790 allow_internal_unstable
: false,
793 // DON'T mark before expansion.
795 let allow_internal_unstable
= attr
::contains_name(&it
.attrs
,
796 "allow_internal_unstable");
798 // ensure any #[allow_internal_unstable]s are
799 // detected (including nested macro definitions
801 if allow_internal_unstable
&& !fld
.cx
.ecfg
.enable_allow_internal_unstable() {
802 feature_gate
::emit_feature_err(
803 &fld
.cx
.parse_sess
.span_diagnostic
,
804 "allow_internal_unstable",
806 feature_gate
::EXPLAIN_ALLOW_INTERNAL_UNSTABLE
)
809 let def
= ast
::MacroDef
{
811 attrs
: it
.attrs
.clone(),
812 id
: ast
::DUMMY_NODE_ID
,
815 export
: attr
::contains_name(&it
.attrs
, "macro_export"),
817 allow_internal_unstable
: allow_internal_unstable
,
820 fld
.cx
.insert_macro(def
);
822 // macro_rules! has a side effect but expands to nothing.
824 return SmallVector
::zero();
827 fld
.cx
.span_err(it
.span
,
828 &format
!("{}! is not legal in item position",
830 return SmallVector
::zero();
835 expanded
.make_items()
838 let items
= match items
{
841 .map(|i
| mark_item(i
, fm
))
842 .flat_map(|i
| fld
.fold_item(i
).into_iter())
846 fld
.cx
.span_err(path_span
,
847 &format
!("non-item macro in item position: {}",
849 return SmallVector
::zero();
858 fn expand_stmt(stmt
: P
<Stmt
>, fld
: &mut MacroExpander
) -> SmallVector
<P
<Stmt
>> {
859 let stmt
= stmt
.and_then(|stmt
| stmt
);
860 let (mac
, style
) = match stmt
.node
{
861 StmtMac(mac
, style
) => (mac
, style
),
862 _
=> return expand_non_macro_stmt(stmt
, fld
)
865 let maybe_new_items
=
866 expand_mac_invoc(mac
.and_then(|m
| m
), stmt
.span
,
868 |stmts
, mark
| stmts
.move_map(|m
| mark_stmt(m
, mark
)),
871 let mut fully_expanded
= match maybe_new_items
{
873 // Keep going, outside-in.
874 let new_items
= stmts
.into_iter().flat_map(|s
| {
875 fld
.fold_stmt(s
).into_iter()
880 None
=> SmallVector
::zero()
883 // If this is a macro invocation with a semicolon, then apply that
884 // semicolon to the final statement produced by expansion.
885 if style
== MacStmtWithSemicolon
{
886 if let Some(stmt
) = fully_expanded
.pop() {
887 let new_stmt
= stmt
.map(|Spanned {node, span}
| {
890 StmtExpr(e
, stmt_id
) => StmtSemi(e
, stmt_id
),
891 _
=> node
/* might already have a semi */
896 fully_expanded
.push(new_stmt
);
903 // expand a non-macro stmt. this is essentially the fallthrough for
904 // expand_stmt, above.
905 fn expand_non_macro_stmt(Spanned {node, span: stmt_span}
: Stmt
, fld
: &mut MacroExpander
)
906 -> SmallVector
<P
<Stmt
>> {
909 StmtDecl(decl
, node_id
) => decl
.and_then(|Spanned {node: decl, span}
| match decl
{
910 DeclLocal(local
) => {
912 let rewritten_local
= local
.map(|Local {id, pat, ty, init, span}
| {
913 // expand the ty since TyFixedLengthVec contains an Expr
914 // and thus may have a macro use
915 let expanded_ty
= ty
.map(|t
| fld
.fold_ty(t
));
916 // expand the pat (it might contain macro uses):
917 let expanded_pat
= fld
.fold_pat(pat
);
918 // find the PatIdents in the pattern:
919 // oh dear heaven... this is going to include the enum
920 // names, as well... but that should be okay, as long as
921 // the new names are gensyms for the old ones.
922 // generate fresh names, push them to a new pending list
923 let idents
= pattern_bindings(&*expanded_pat
);
924 let mut new_pending_renames
=
925 idents
.iter().map(|ident
| (*ident
, fresh_name(ident
))).collect();
926 // rewrite the pattern using the new names (the old
927 // ones have already been applied):
928 let rewritten_pat
= {
929 // nested binding to allow borrow to expire:
930 let mut rename_fld
= IdentRenamer{renames: &mut new_pending_renames}
;
931 rename_fld
.fold_pat(expanded_pat
)
933 // add them to the existing pending renames:
934 fld
.cx
.syntax_env
.info().pending_renames
935 .extend(new_pending_renames
);
940 // also, don't forget to expand the init:
941 init
: init
.map(|e
| fld
.fold_expr(e
)),
945 SmallVector
::one(P(Spanned
{
946 node
: StmtDecl(P(Spanned
{
947 node
: DeclLocal(rewritten_local
),
955 noop_fold_stmt(Spanned
{
956 node
: StmtDecl(P(Spanned
{
966 noop_fold_stmt(Spanned
{
974 // expand the arm of a 'match', renaming for macro hygiene
975 fn expand_arm(arm
: ast
::Arm
, fld
: &mut MacroExpander
) -> ast
::Arm
{
976 // expand pats... they might contain macro uses:
977 let expanded_pats
= arm
.pats
.move_map(|pat
| fld
.fold_pat(pat
));
978 if expanded_pats
.is_empty() {
979 panic
!("encountered match arm with 0 patterns");
981 // all of the pats must have the same set of bindings, so use the
982 // first one to extract them and generate new names:
983 let idents
= pattern_bindings(&*expanded_pats
[0]);
984 let new_renames
= idents
.into_iter().map(|id
| (id
, fresh_name(&id
))).collect();
985 // apply the renaming, but only to the PatIdents:
986 let mut rename_pats_fld
= PatIdentRenamer{renames:&new_renames}
;
987 let rewritten_pats
= expanded_pats
.move_map(|pat
| rename_pats_fld
.fold_pat(pat
));
988 // apply renaming and then expansion to the guard and the body:
989 let mut rename_fld
= IdentRenamer{renames:&new_renames}
;
990 let rewritten_guard
=
991 arm
.guard
.map(|g
| fld
.fold_expr(rename_fld
.fold_expr(g
)));
992 let rewritten_body
= fld
.fold_expr(rename_fld
.fold_expr(arm
.body
));
994 attrs
: fold
::fold_attrs(arm
.attrs
, fld
),
995 pats
: rewritten_pats
,
996 guard
: rewritten_guard
,
997 body
: rewritten_body
,
1001 /// A visitor that extracts the PatIdent (binding) paths
1002 /// from a given thingy and puts them in a mutable
1005 struct PatIdentFinder
{
1006 ident_accumulator
: Vec
<ast
::Ident
>
1009 impl<'v
> Visitor
<'v
> for PatIdentFinder
{
1010 fn visit_pat(&mut self, pattern
: &ast
::Pat
) {
1012 ast
::Pat { id: _, node: ast::PatIdent(_, ref path1, ref inner), span: _ }
=> {
1013 self.ident_accumulator
.push(path1
.node
);
1014 // visit optional subpattern of PatIdent:
1015 if let Some(ref subpat
) = *inner
{
1016 self.visit_pat(&**subpat
)
1019 // use the default traversal for non-PatIdents
1020 _
=> visit
::walk_pat(self, pattern
)
1025 /// find the PatIdent paths in a pattern
1026 fn pattern_bindings(pat
: &ast
::Pat
) -> Vec
<ast
::Ident
> {
1027 let mut name_finder
= PatIdentFinder{ident_accumulator:Vec::new()}
;
1028 name_finder
.visit_pat(pat
);
1029 name_finder
.ident_accumulator
1032 /// find the PatIdent paths in a
1033 fn fn_decl_arg_bindings(fn_decl
: &ast
::FnDecl
) -> Vec
<ast
::Ident
> {
1034 let mut pat_idents
= PatIdentFinder{ident_accumulator:Vec::new()}
;
1035 for arg
in &fn_decl
.inputs
{
1036 pat_idents
.visit_pat(&*arg
.pat
);
1038 pat_idents
.ident_accumulator
1041 // expand a block. pushes a new exts_frame, then calls expand_block_elts
1042 pub fn expand_block(blk
: P
<Block
>, fld
: &mut MacroExpander
) -> P
<Block
> {
1043 // see note below about treatment of exts table
1044 with_exts_frame
!(fld
.cx
.syntax_env
,false,
1045 expand_block_elts(blk
, fld
))
1048 // expand the elements of a block.
1049 pub fn expand_block_elts(b
: P
<Block
>, fld
: &mut MacroExpander
) -> P
<Block
> {
1050 b
.map(|Block {id, stmts, expr, rules, span}
| {
1051 let new_stmts
= stmts
.into_iter().flat_map(|x
| {
1052 // perform all pending renames
1053 let renamed_stmt
= {
1054 let pending_renames
= &mut fld
.cx
.syntax_env
.info().pending_renames
;
1055 let mut rename_fld
= IdentRenamer{renames:pending_renames}
;
1056 rename_fld
.fold_stmt(x
).expect_one("rename_fold didn't return one value")
1058 // expand macros in the statement
1059 fld
.fold_stmt(renamed_stmt
).into_iter()
1061 let new_expr
= expr
.map(|x
| {
1063 let pending_renames
= &mut fld
.cx
.syntax_env
.info().pending_renames
;
1064 let mut rename_fld
= IdentRenamer{renames:pending_renames}
;
1065 rename_fld
.fold_expr(x
)
1079 fn expand_pat(p
: P
<ast
::Pat
>, fld
: &mut MacroExpander
) -> P
<ast
::Pat
> {
1082 _
=> return noop_fold_pat(p
, fld
)
1084 p
.map(|ast
::Pat {node, span, ..}
| {
1085 let (pth
, tts
) = match node
{
1086 PatMac(mac
) => match mac
.node
{
1087 MacInvocTT(pth
, tts
, _
) => {
1093 if pth
.segments
.len() > 1 {
1094 fld
.cx
.span_err(pth
.span
, "expected macro name without module separators");
1095 return DummyResult
::raw_pat(span
);
1097 let extname
= pth
.segments
[0].identifier
.name
;
1098 let marked_after
= match fld
.cx
.syntax_env
.find(&extname
) {
1100 fld
.cx
.span_err(pth
.span
,
1101 &format
!("macro undefined: '{}!'",
1103 // let compilation continue
1104 return DummyResult
::raw_pat(span
);
1107 Some(rc
) => match *rc
{
1108 NormalTT(ref expander
, tt_span
, allow_internal_unstable
) => {
1109 fld
.cx
.bt_push(ExpnInfo
{
1111 callee
: NameAndSpan
{
1112 name
: extname
.to_string(),
1115 allow_internal_unstable
: allow_internal_unstable
,
1119 let fm
= fresh_mark();
1120 let marked_before
= mark_tts(&tts
[..], fm
);
1121 let mac_span
= fld
.cx
.original_span();
1122 let pat
= expander
.expand(fld
.cx
,
1124 &marked_before
[..]).make_pat();
1125 let expanded
= match pat
{
1131 "non-pattern macro in pattern position: {}",
1135 return DummyResult
::raw_pat(span
);
1140 mark_pat(expanded
,fm
)
1143 fld
.cx
.span_err(span
,
1144 &format
!("{}! is not legal in pattern position",
1146 return DummyResult
::raw_pat(span
);
1151 let fully_expanded
=
1152 fld
.fold_pat(marked_after
).node
.clone();
1156 id
: ast
::DUMMY_NODE_ID
,
1157 node
: fully_expanded
,
1163 /// A tree-folder that applies every rename in its (mutable) list
1164 /// to every identifier, including both bindings and varrefs
1165 /// (and lots of things that will turn out to be neither)
1166 pub struct IdentRenamer
<'a
> {
1167 renames
: &'a mtwt
::RenameList
,
1170 impl<'a
> Folder
for IdentRenamer
<'a
> {
1171 fn fold_ident(&mut self, id
: Ident
) -> Ident
{
1174 ctxt
: mtwt
::apply_renames(self.renames
, id
.ctxt
),
1177 fn fold_mac(&mut self, mac
: ast
::Mac
) -> ast
::Mac
{
1178 fold
::noop_fold_mac(mac
, self)
1182 /// A tree-folder that applies every rename in its list to
1183 /// the idents that are in PatIdent patterns. This is more narrowly
1184 /// focused than IdentRenamer, and is needed for FnDecl,
1185 /// where we want to rename the args but not the fn name or the generics etc.
1186 pub struct PatIdentRenamer
<'a
> {
1187 renames
: &'a mtwt
::RenameList
,
1190 impl<'a
> Folder
for PatIdentRenamer
<'a
> {
1191 fn fold_pat(&mut self, pat
: P
<ast
::Pat
>) -> P
<ast
::Pat
> {
1193 ast
::PatIdent(..) => {}
,
1194 _
=> return noop_fold_pat(pat
, self)
1197 pat
.map(|ast
::Pat {id, node, span}
| match node
{
1198 ast
::PatIdent(binding_mode
, Spanned{span: sp, node: ident}
, sub
) => {
1199 let new_ident
= Ident
{name
: ident
.name
,
1200 ctxt
: mtwt
::apply_renames(self.renames
, ident
.ctxt
)};
1202 ast
::PatIdent(binding_mode
,
1203 Spanned{span: self.new_span(sp), node: new_ident}
,
1204 sub
.map(|p
| self.fold_pat(p
)));
1208 span
: self.new_span(span
)
1214 fn fold_mac(&mut self, mac
: ast
::Mac
) -> ast
::Mac
{
1215 fold
::noop_fold_mac(mac
, self)
1219 fn expand_annotatable(a
: Annotatable
,
1220 fld
: &mut MacroExpander
)
1221 -> SmallVector
<Annotatable
> {
1222 let a
= expand_item_multi_modifier(a
, fld
);
1224 let mut decorator_items
= SmallVector
::zero();
1225 let mut new_attrs
= Vec
::new();
1226 expand_decorators(a
.clone(), fld
, &mut decorator_items
, &mut new_attrs
);
1228 let mut new_items
: SmallVector
<Annotatable
> = match a
{
1229 Annotatable
::Item(it
) => match it
.node
{
1230 ast
::ItemMac(..) => {
1231 expand_item_mac(it
, fld
).into_iter().map(|i
| Annotatable
::Item(i
)).collect()
1233 ast
::ItemMod(_
) | ast
::ItemForeignMod(_
) => {
1235 it
.ident
.name
!= parse
::token
::special_idents
::invalid
.name
;
1238 fld
.cx
.mod_push(it
.ident
);
1240 let macro_use
= contains_macro_use(fld
, &new_attrs
[..]);
1241 let result
= with_exts_frame
!(fld
.cx
.syntax_env
,
1243 noop_fold_item(it
, fld
));
1247 result
.into_iter().map(|i
| Annotatable
::Item(i
)).collect()
1250 let it
= P(ast
::Item
{
1254 noop_fold_item(it
, fld
).into_iter().map(|i
| Annotatable
::Item(i
)).collect()
1258 Annotatable
::TraitItem(it
) => match it
.node
{
1259 ast
::MethodTraitItem(_
, Some(_
)) => SmallVector
::one(it
.map(|ti
| ast
::TraitItem
{
1263 node
: match ti
.node
{
1264 ast
::MethodTraitItem(sig
, Some(body
)) => {
1265 let (sig
, body
) = expand_and_rename_method(sig
, body
, fld
);
1266 ast
::MethodTraitItem(sig
, Some(body
))
1270 span
: fld
.new_span(ti
.span
)
1272 _
=> fold
::noop_fold_trait_item(it
, fld
)
1273 }.into_iter().map(Annotatable
::TraitItem
).collect(),
1275 Annotatable
::ImplItem(ii
) => {
1276 expand_impl_item(ii
, fld
).into_iter().map(Annotatable
::ImplItem
).collect()
1280 new_items
.push_all(decorator_items
);
1284 // Partition a set of attributes into one kind of attribute, and other kinds.
1285 macro_rules
! partition
{
1286 ($fn_name
: ident
, $variant
: ident
) => {
1287 #[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
1288 fn $
fn_name(attrs
: &[ast
::Attribute
],
1289 fld
: &MacroExpander
)
1290 -> (Vec
<ast
::Attribute
>, Vec
<ast
::Attribute
>) {
1291 attrs
.iter().cloned().partition(|attr
| {
1292 match fld
.cx
.syntax_env
.find(&intern(&attr
.name())) {
1293 Some(rc
) => match *rc
{
1294 $
variant(..) => true,
1304 partition
!(modifiers
, Modifier
);
1305 partition
!(multi_modifiers
, MultiModifier
);
1308 #[allow(deprecated)] // The `allow` is needed because the `Decorator` variant is used.
1309 fn expand_decorators(a
: Annotatable
,
1310 fld
: &mut MacroExpander
,
1311 decorator_items
: &mut SmallVector
<Annotatable
>,
1312 new_attrs
: &mut Vec
<ast
::Attribute
>)
1314 for attr
in a
.attrs() {
1315 let mname
= attr
.name();
1316 match fld
.cx
.syntax_env
.find(&intern(&mname
)) {
1317 Some(rc
) => match *rc
{
1318 Decorator(ref dec
) => {
1319 attr
::mark_used(&attr
);
1321 fld
.cx
.bt_push(ExpnInfo
{
1322 call_site
: attr
.span
,
1323 callee
: NameAndSpan
{
1324 name
: mname
.to_string(),
1325 format
: MacroAttribute
,
1326 span
: Some(attr
.span
),
1327 // attributes can do whatever they like,
1329 allow_internal_unstable
: true,
1333 // we'd ideally decorator_items.push_all(expand_item(item, fld)),
1334 // but that double-mut-borrows fld
1335 let mut items
: SmallVector
<Annotatable
> = SmallVector
::zero();
1339 &a
.clone().expect_item(),
1340 &mut |item
| items
.push(Annotatable
::Item(item
)));
1341 decorator_items
.extend(items
.into_iter()
1342 .flat_map(|ann
| expand_annotatable(ann
, fld
).into_iter()));
1346 MultiDecorator(ref dec
) => {
1347 attr
::mark_used(&attr
);
1349 fld
.cx
.bt_push(ExpnInfo
{
1350 call_site
: attr
.span
,
1351 callee
: NameAndSpan
{
1352 name
: mname
.to_string(),
1353 format
: MacroAttribute
,
1354 span
: Some(attr
.span
),
1355 // attributes can do whatever they like,
1357 allow_internal_unstable
: true,
1361 // we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
1362 // but that double-mut-borrows fld
1363 let mut items
: SmallVector
<Annotatable
> = SmallVector
::zero();
1368 &mut |ann
| items
.push(ann
));
1369 decorator_items
.extend(items
.into_iter()
1370 .flat_map(|ann
| expand_annotatable(ann
, fld
).into_iter()));
1374 _
=> new_attrs
.push((*attr
).clone()),
1376 _
=> new_attrs
.push((*attr
).clone()),
1381 fn expand_item_multi_modifier(mut it
: Annotatable
,
1382 fld
: &mut MacroExpander
)
1384 let (modifiers
, other_attrs
) = multi_modifiers(it
.attrs(), fld
);
1386 // Update the attrs, leave everything else alone. Is this mutation really a good idea?
1387 it
= it
.fold_attrs(other_attrs
);
1389 if modifiers
.is_empty() {
1393 for attr
in &modifiers
{
1394 let mname
= attr
.name();
1396 match fld
.cx
.syntax_env
.find(&intern(&mname
)) {
1397 Some(rc
) => match *rc
{
1398 MultiModifier(ref mac
) => {
1399 attr
::mark_used(attr
);
1400 fld
.cx
.bt_push(ExpnInfo
{
1401 call_site
: attr
.span
,
1402 callee
: NameAndSpan
{
1403 name
: mname
.to_string(),
1404 format
: MacroAttribute
,
1405 span
: Some(attr
.span
),
1406 // attributes can do whatever they like,
1408 allow_internal_unstable
: true,
1411 it
= mac
.expand(fld
.cx
, attr
.span
, &*attr
.node
.value
, it
);
1420 // Expansion may have added new ItemModifiers.
1421 expand_item_multi_modifier(it
, fld
)
1424 #[allow(deprecated)] // This is needed because the `ItemModifier` trait is used
1425 fn expand_item_modifiers(mut it
: P
<ast
::Item
>,
1426 fld
: &mut MacroExpander
)
1428 // partition the attributes into ItemModifiers and others
1429 let (modifiers
, other_attrs
) = modifiers(&it
.attrs
, fld
);
1431 // update the attrs, leave everything else alone. Is this mutation really a good idea?
1437 if modifiers
.is_empty() {
1438 let it
= expand_item_multi_modifier(Annotatable
::Item(it
), fld
);
1439 return it
.expect_item();
1442 for attr
in &modifiers
{
1443 let mname
= attr
.name();
1445 match fld
.cx
.syntax_env
.find(&intern(&mname
)) {
1446 Some(rc
) => match *rc
{
1447 Modifier(ref mac
) => {
1448 attr
::mark_used(attr
);
1449 fld
.cx
.bt_push(ExpnInfo
{
1450 call_site
: attr
.span
,
1451 callee
: NameAndSpan
{
1452 name
: mname
.to_string(),
1453 format
: MacroAttribute
,
1454 span
: Some(attr
.span
),
1455 // attributes can do whatever they like,
1457 allow_internal_unstable
: true,
1460 it
= mac
.expand(fld
.cx
, attr
.span
, &*attr
.node
.value
, it
);
1469 // Expansion may have added new ItemModifiers.
1470 // It is possible, that an item modifier could expand to a multi-modifier or
1471 // vice versa. In this case we will expand all modifiers before multi-modifiers,
1472 // which might give an odd ordering. However, I think it is unlikely that the
1473 // two kinds will be mixed, and old-style multi-modifiers are deprecated.
1474 expand_item_modifiers(it
, fld
)
1477 fn expand_impl_item(ii
: P
<ast
::ImplItem
>, fld
: &mut MacroExpander
)
1478 -> SmallVector
<P
<ast
::ImplItem
>> {
1480 ast
::MethodImplItem(..) => SmallVector
::one(ii
.map(|ii
| ast
::ImplItem
{
1485 node
: match ii
.node
{
1486 ast
::MethodImplItem(sig
, body
) => {
1487 let (sig
, body
) = expand_and_rename_method(sig
, body
, fld
);
1488 ast
::MethodImplItem(sig
, body
)
1492 span
: fld
.new_span(ii
.span
)
1494 ast
::MacImplItem(_
) => {
1495 let (span
, mac
) = ii
.and_then(|ii
| match ii
.node
{
1496 ast
::MacImplItem(mac
) => (ii
.span
, mac
),
1499 let maybe_new_items
=
1500 expand_mac_invoc(mac
, span
,
1501 |r
| r
.make_impl_items(),
1502 |meths
, mark
| meths
.move_map(|m
| mark_impl_item(m
, mark
)),
1505 match maybe_new_items
{
1506 Some(impl_items
) => {
1507 // expand again if necessary
1508 let new_items
= impl_items
.into_iter().flat_map(|ii
| {
1509 expand_impl_item(ii
, fld
).into_iter()
1514 None
=> SmallVector
::zero()
1517 _
=> fold
::noop_fold_impl_item(ii
, fld
)
1521 /// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
1522 /// PatIdents in its arguments to perform renaming in the FnDecl and
1523 /// the block, returning both the new FnDecl and the new Block.
1524 fn expand_and_rename_fn_decl_and_block(fn_decl
: P
<ast
::FnDecl
>, block
: P
<ast
::Block
>,
1525 fld
: &mut MacroExpander
)
1526 -> (P
<ast
::FnDecl
>, P
<ast
::Block
>) {
1527 let expanded_decl
= fld
.fold_fn_decl(fn_decl
);
1528 let idents
= fn_decl_arg_bindings(&*expanded_decl
);
1530 idents
.iter().map(|id
: &ast
::Ident
| (*id
,fresh_name(id
))).collect();
1531 // first, a renamer for the PatIdents, for the fn_decl:
1532 let mut rename_pat_fld
= PatIdentRenamer{renames: &renames}
;
1533 let rewritten_fn_decl
= rename_pat_fld
.fold_fn_decl(expanded_decl
);
1534 // now, a renamer for *all* idents, for the body:
1535 let mut rename_fld
= IdentRenamer{renames: &renames}
;
1536 let rewritten_body
= fld
.fold_block(rename_fld
.fold_block(block
));
1537 (rewritten_fn_decl
,rewritten_body
)
1540 fn expand_and_rename_method(sig
: ast
::MethodSig
, body
: P
<ast
::Block
>,
1541 fld
: &mut MacroExpander
)
1542 -> (ast
::MethodSig
, P
<ast
::Block
>) {
1543 let (rewritten_fn_decl
, rewritten_body
)
1544 = expand_and_rename_fn_decl_and_block(sig
.decl
, body
, fld
);
1546 generics
: fld
.fold_generics(sig
.generics
),
1548 explicit_self
: fld
.fold_explicit_self(sig
.explicit_self
),
1549 unsafety
: sig
.unsafety
,
1550 constness
: sig
.constness
,
1551 decl
: rewritten_fn_decl
1555 /// A tree-folder that performs macro expansion
1556 pub struct MacroExpander
<'a
, 'b
:'a
> {
1557 pub cx
: &'a
mut ExtCtxt
<'b
>,
1560 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
1561 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>) -> MacroExpander
<'a
, 'b
> {
1562 MacroExpander { cx: cx }
1566 impl<'a
, 'b
> Folder
for MacroExpander
<'a
, 'b
> {
1567 fn fold_expr(&mut self, expr
: P
<ast
::Expr
>) -> P
<ast
::Expr
> {
1568 expand_expr(expr
, self)
1571 fn fold_pat(&mut self, pat
: P
<ast
::Pat
>) -> P
<ast
::Pat
> {
1572 expand_pat(pat
, self)
1575 fn fold_item(&mut self, item
: P
<ast
::Item
>) -> SmallVector
<P
<ast
::Item
>> {
1576 expand_item(item
, self)
1579 fn fold_item_underscore(&mut self, item
: ast
::Item_
) -> ast
::Item_
{
1580 expand_item_underscore(item
, self)
1583 fn fold_stmt(&mut self, stmt
: P
<ast
::Stmt
>) -> SmallVector
<P
<ast
::Stmt
>> {
1584 expand_stmt(stmt
, self)
1587 fn fold_block(&mut self, block
: P
<Block
>) -> P
<Block
> {
1588 expand_block(block
, self)
1591 fn fold_arm(&mut self, arm
: ast
::Arm
) -> ast
::Arm
{
1592 expand_arm(arm
, self)
1595 fn fold_trait_item(&mut self, i
: P
<ast
::TraitItem
>) -> SmallVector
<P
<ast
::TraitItem
>> {
1596 expand_annotatable(Annotatable
::TraitItem(i
), self)
1597 .into_iter().map(|i
| i
.expect_trait_item()).collect()
1600 fn fold_impl_item(&mut self, i
: P
<ast
::ImplItem
>) -> SmallVector
<P
<ast
::ImplItem
>> {
1601 expand_annotatable(Annotatable
::ImplItem(i
), self)
1602 .into_iter().map(|i
| i
.expect_impl_item()).collect()
1605 fn new_span(&mut self, span
: Span
) -> Span
{
1606 new_span(self.cx
, span
)
1610 fn new_span(cx
: &ExtCtxt
, sp
: Span
) -> Span
{
1611 /* this discards information in the case of macro-defining macros */
1615 expn_id
: cx
.backtrace(),
1619 pub struct ExpansionConfig
<'feat
> {
1620 pub crate_name
: String
,
1621 pub features
: Option
<&'feat Features
>,
1622 pub recursion_limit
: usize,
1623 pub trace_mac
: bool
,
1626 macro_rules
! feature_tests
{
1627 ($
( fn $getter
:ident
= $field
:ident
, )*) => {
1629 pub fn $
getter(&self) -> bool
{
1630 match self.features
{
1631 Some(&Features { $field: true, .. }
) => true,
1639 impl<'feat
> ExpansionConfig
<'feat
> {
1640 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1642 crate_name
: crate_name
,
1644 recursion_limit
: 64,
1650 fn enable_quotes
= allow_quote
,
1651 fn enable_asm
= allow_asm
,
1652 fn enable_log_syntax
= allow_log_syntax
,
1653 fn enable_concat_idents
= allow_concat_idents
,
1654 fn enable_trace_macros
= allow_trace_macros
,
1655 fn enable_allow_internal_unstable
= allow_internal_unstable
,
1656 fn enable_custom_derive
= allow_custom_derive
,
1657 fn enable_pushpop_unsafe
= allow_pushpop_unsafe
,
1661 pub fn expand_crate
<'feat
>(parse_sess
: &parse
::ParseSess
,
1662 cfg
: ExpansionConfig
<'feat
>,
1663 // these are the macros being imported to this crate:
1664 imported_macros
: Vec
<ast
::MacroDef
>,
1665 user_exts
: Vec
<NamedSyntaxExtension
>,
1666 c
: Crate
) -> Crate
{
1667 let mut cx
= ExtCtxt
::new(parse_sess
, c
.config
.clone(), cfg
);
1668 cx
.use_std
= std_inject
::use_std(&c
);
1670 let mut expander
= MacroExpander
::new(&mut cx
);
1672 for def
in imported_macros
{
1673 expander
.cx
.insert_macro(def
);
1676 for (name
, extension
) in user_exts
{
1677 expander
.cx
.syntax_env
.insert(name
, extension
);
1680 let mut ret
= expander
.fold_crate(c
);
1681 ret
.exported_macros
= expander
.cx
.exported_macros
.clone();
1682 parse_sess
.span_diagnostic
.handler().abort_if_errors();
1686 // HYGIENIC CONTEXT EXTENSION:
1687 // all of these functions are for walking over
1688 // ASTs and making some change to the context of every
1689 // element that has one. a CtxtFn is a trait-ified
1690 // version of a closure in (SyntaxContext -> SyntaxContext).
1691 // the ones defined here include:
1692 // Marker - add a mark to a context
1694 // A Marker adds the given mark to the syntax context
1695 struct Marker { mark: Mrk }
1697 impl Folder
for Marker
{
1698 fn fold_ident(&mut self, id
: Ident
) -> Ident
{
1701 ctxt
: mtwt
::apply_mark(self.mark
, id
.ctxt
)
1704 fn fold_mac(&mut self, Spanned {node, span}
: ast
::Mac
) -> ast
::Mac
{
1707 MacInvocTT(path
, tts
, ctxt
) => {
1708 MacInvocTT(self.fold_path(path
),
1709 self.fold_tts(&tts
[..]),
1710 mtwt
::apply_mark(self.mark
, ctxt
))
1718 // apply a given mark to the given token trees. Used prior to expansion of a macro.
1719 fn mark_tts(tts
: &[TokenTree
], m
: Mrk
) -> Vec
<TokenTree
> {
1720 noop_fold_tts(tts
, &mut Marker{mark:m}
)
1723 // apply a given mark to the given expr. Used following the expansion of a macro.
1724 fn mark_expr(expr
: P
<ast
::Expr
>, m
: Mrk
) -> P
<ast
::Expr
> {
1725 Marker{mark:m}
.fold_expr(expr
)
1728 // apply a given mark to the given pattern. Used following the expansion of a macro.
1729 fn mark_pat(pat
: P
<ast
::Pat
>, m
: Mrk
) -> P
<ast
::Pat
> {
1730 Marker{mark:m}
.fold_pat(pat
)
1733 // apply a given mark to the given stmt. Used following the expansion of a macro.
1734 fn mark_stmt(stmt
: P
<ast
::Stmt
>, m
: Mrk
) -> P
<ast
::Stmt
> {
1735 Marker{mark:m}
.fold_stmt(stmt
)
1736 .expect_one("marking a stmt didn't return exactly one stmt")
1739 // apply a given mark to the given item. Used following the expansion of a macro.
1740 fn mark_item(expr
: P
<ast
::Item
>, m
: Mrk
) -> P
<ast
::Item
> {
1741 Marker{mark:m}
.fold_item(expr
)
1742 .expect_one("marking an item didn't return exactly one item")
1745 // apply a given mark to the given item. Used following the expansion of a macro.
1746 fn mark_impl_item(ii
: P
<ast
::ImplItem
>, m
: Mrk
) -> P
<ast
::ImplItem
> {
1747 Marker{mark:m}
.fold_impl_item(ii
)
1748 .expect_one("marking an impl item didn't return exactly one impl item")
1751 /// Check that there are no macro invocations left in the AST:
1752 pub fn check_for_macros(sess
: &parse
::ParseSess
, krate
: &ast
::Crate
) {
1753 visit
::walk_crate(&mut MacroExterminator{sess:sess}
, krate
);
1756 /// A visitor that ensures that no macro invocations remain in an AST.
1757 struct MacroExterminator
<'a
>{
1758 sess
: &'a parse
::ParseSess
1761 impl<'a
, 'v
> Visitor
<'v
> for MacroExterminator
<'a
> {
1762 fn visit_mac(&mut self, mac
: &ast
::Mac
) {
1763 self.sess
.span_diagnostic
.span_bug(mac
.span
,
1764 "macro exterminator: expected AST \
1765 with no macro invocations");
1772 use super::{pattern_bindings, expand_crate}
;
1773 use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig}
;
1781 use util
::parser_testing
::{string_to_parser}
;
1782 use util
::parser_testing
::{string_to_pat, string_to_crate, strs_to_idents}
;
1786 // a visitor that extracts the paths
1787 // from a given thingy and puts them in a mutable
1788 // array (passed in to the traversal)
1790 struct PathExprFinderContext
{
1791 path_accumulator
: Vec
<ast
::Path
> ,
1794 impl<'v
> Visitor
<'v
> for PathExprFinderContext
{
1795 fn visit_expr(&mut self, expr
: &ast
::Expr
) {
1796 if let ast
::ExprPath(None
, ref p
) = expr
.node
{
1797 self.path_accumulator
.push(p
.clone());
1799 visit
::walk_expr(self, expr
);
1803 // find the variable references in a crate
1804 fn crate_varrefs(the_crate
: &ast
::Crate
) -> Vec
<ast
::Path
> {
1805 let mut path_finder
= PathExprFinderContext{path_accumulator:Vec::new()}
;
1806 visit
::walk_crate(&mut path_finder
, the_crate
);
1807 path_finder
.path_accumulator
1810 /// A Visitor that extracts the identifiers from a thingy.
1811 // as a side note, I'm starting to want to abstract over these....
1812 struct IdentFinder
{
1813 ident_accumulator
: Vec
<ast
::Ident
>
1816 impl<'v
> Visitor
<'v
> for IdentFinder
{
1817 fn visit_ident(&mut self, _
: codemap
::Span
, id
: ast
::Ident
){
1818 self.ident_accumulator
.push(id
);
1822 /// Find the idents in a crate
1823 fn crate_idents(the_crate
: &ast
::Crate
) -> Vec
<ast
::Ident
> {
1824 let mut ident_finder
= IdentFinder{ident_accumulator: Vec::new()}
;
1825 visit
::walk_crate(&mut ident_finder
, the_crate
);
1826 ident_finder
.ident_accumulator
1829 // these following tests are quite fragile, in that they don't test what
1830 // *kind* of failure occurs.
1832 fn test_ecfg() -> ExpansionConfig
<'
static> {
1833 ExpansionConfig
::default("test".to_string())
1836 // make sure that macros can't escape fns
1838 #[test] fn macros_cant_escape_fns_test () {
1839 let src
= "fn bogus() {macro_rules! z (() => (3+4));}\
1840 fn inty() -> i32 { z!() }".to_string();
1841 let sess
= parse
::ParseSess
::new();
1842 let crate_ast
= parse
::parse_crate_from_source_str(
1843 "<test>".to_string(),
1847 expand_crate(&sess
,test_ecfg(),vec
!(),vec
!(),crate_ast
);
1850 // make sure that macros can't escape modules
1852 #[test] fn macros_cant_escape_mods_test () {
1853 let src
= "mod foo {macro_rules! z (() => (3+4));}\
1854 fn inty() -> i32 { z!() }".to_string();
1855 let sess
= parse
::ParseSess
::new();
1856 let crate_ast
= parse
::parse_crate_from_source_str(
1857 "<test>".to_string(),
1860 expand_crate(&sess
,test_ecfg(),vec
!(),vec
!(),crate_ast
);
1863 // macro_use modules should allow macros to escape
1864 #[test] fn macros_can_escape_flattened_mods_test () {
1865 let src
= "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1866 fn inty() -> i32 { z!() }".to_string();
1867 let sess
= parse
::ParseSess
::new();
1868 let crate_ast
= parse
::parse_crate_from_source_str(
1869 "<test>".to_string(),
1872 expand_crate(&sess
, test_ecfg(), vec
!(), vec
!(), crate_ast
);
1875 fn expand_crate_str(crate_str
: String
) -> ast
::Crate
{
1876 let ps
= parse
::ParseSess
::new();
1877 let crate_ast
= panictry
!(string_to_parser(&ps
, crate_str
).parse_crate_mod());
1878 // the cfg argument actually does matter, here...
1879 expand_crate(&ps
,test_ecfg(),vec
!(),vec
!(),crate_ast
)
1882 // find the pat_ident paths in a crate
1883 fn crate_bindings(the_crate
: &ast
::Crate
) -> Vec
<ast
::Ident
> {
1884 let mut name_finder
= PatIdentFinder{ident_accumulator:Vec::new()}
;
1885 visit
::walk_crate(&mut name_finder
, the_crate
);
1886 name_finder
.ident_accumulator
1889 #[test] fn macro_tokens_should_match(){
1891 "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1894 // should be able to use a bound identifier as a literal in a macro definition:
1895 #[test] fn self_macro_parsing(){
1897 "macro_rules! foo ((zz) => (287;));
1898 fn f(zz: i32) {foo!(zz);}".to_string()
1902 // renaming tests expand a crate and then check that the bindings match
1903 // the right varrefs. The specification of the test case includes the
1904 // text of the crate, and also an array of arrays. Each element in the
1905 // outer array corresponds to a binding in the traversal of the AST
1906 // induced by visit. Each of these arrays contains a list of indexes,
1907 // interpreted as the varrefs in the varref traversal that this binding
1908 // should match. So, for instance, in a program with two bindings and
1909 // three varrefs, the array [[1, 2], [0]] would indicate that the first
1910 // binding should match the second two varrefs, and the second binding
1911 // should match the first varref.
1913 // Put differently; this is a sparse representation of a boolean matrix
1914 // indicating which bindings capture which identifiers.
1916 // Note also that this matrix is dependent on the implicit ordering of
1917 // the bindings and the varrefs discovered by the name-finder and the path-finder.
1919 // The comparisons are done post-mtwt-resolve, so we're comparing renamed
1920 // names; differences in marks don't matter any more.
1922 // oog... I also want tests that check "bound-identifier-=?". That is,
1923 // not just "do these have the same name", but "do they have the same
1924 // name *and* the same marks"? Understanding this is really pretty painful.
1925 // in principle, you might want to control this boolean on a per-varref basis,
1926 // but that would make things even harder to understand, and might not be
1927 // necessary for thorough testing.
1928 type RenamingTest
= (&'
static str, Vec
<Vec
<usize>>, bool
);
1931 fn automatic_renaming () {
1932 let tests
: Vec
<RenamingTest
> =
1933 vec
!(// b & c should get new names throughout, in the expr too:
1934 ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1935 vec
!(vec
!(0,1),vec
!(2)), false),
1936 // both x's should be renamed (how is this causing a bug?)
1937 ("fn main () {let x: i32 = 13;x;}",
1938 vec
!(vec
!(0)), false),
1939 // the use of b after the + should be renamed, the other one not:
1940 ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1941 vec
!(vec
!(1)), false),
1942 // the b before the plus should not be renamed (requires marks)
1943 ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1944 vec
!(vec
!(1)), false),
1945 // the marks going in and out of letty should cancel, allowing that $x to
1946 // capture the one following the semicolon.
1947 // this was an awesome test case, and caught a *lot* of bugs.
1948 ("macro_rules! letty(($x:ident) => (let $x = 15;));
1949 macro_rules! user(($x:ident) => ({letty!($x); $x}));
1950 fn main() -> i32 {user!(z)}",
1951 vec
!(vec
!(0)), false)
1953 for (idx
,s
) in tests
.iter().enumerate() {
1954 run_renaming_test(s
,idx
);
1958 // no longer a fixme #8062: this test exposes a *potential* bug; our system does
1959 // not behave exactly like MTWT, but a conversation with Matthew Flatt
1960 // suggests that this can only occur in the presence of local-expand, which
1961 // we have no plans to support. ... unless it's needed for item hygiene....
1966 &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}",
1967 vec
!(vec
!(0)), true), 0)
1971 // the z flows into and out of two macros (g & f) along one path, and one
1972 // (just g) along the other, so the result of the whole thing should
1973 // be "let z_123 = 3; z_123"
1978 &("macro_rules! g (($x:ident) =>
1979 ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1981 vec
!(vec
!(0)),false),
1985 // match variable hygiene. Should expand into
1986 // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
1990 &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1991 fn z() {match 8 {x => bad_macro!(x)}}",
1992 // NB: the third "binding" is the repeat of the second one.
1993 vec
!(vec
!(1,3),vec
!(0,2),vec
!(0,2)),
1998 // interpolated nodes weren't getting labeled.
1999 // should expand into
2000 // fn main(){let g1_1 = 13; g1_1}}
2002 fn pat_expand_issue_15221(){
2004 &("macro_rules! inner ( ($e:pat ) => ($e));
2005 macro_rules! outer ( ($e:pat ) => (inner!($e)));
2006 fn main() { let outer!(g) = 13; g;}",
2012 // create a really evil test case where a $x appears inside a binding of $x
2013 // but *shouldn't* bind because it was inserted by a different macro....
2014 // can't write this test case until we have macro-generating macros.
2016 // method arg hygiene
2017 // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
2019 fn method_arg_hygiene(){
2021 &("macro_rules! inject_x (()=>(x));
2022 macro_rules! inject_self (()=>(self));
2024 impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
2025 vec
!(vec
!(0),vec
!(3)),
2030 // ooh, got another bite?
2031 // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
2033 fn method_arg_hygiene_2(){
2036 macro_rules! add_method (($T:ty) =>
2037 (impl $T { fn thingy(&self) {self;} }));
2045 // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
2049 &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
2050 fn q(x: i32) { bad_macro!(x); }",
2051 vec
!(vec
!(1),vec
!(0)),true),
2055 // closure arg hygiene (ExprClosure)
2056 // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
2058 fn closure_arg_hygiene(){
2060 &("macro_rules! inject_x (()=>(x));
2061 fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
2067 // macro_rules in method position. Sadly, unimplemented.
2069 fn macro_in_method_posn(){
2071 "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
2073 impl A{ my_method!(); }
2074 fn f(){A.thirteen;}".to_string());
2077 // another nested macro
2078 // expands to impl Entries {fn size_hint(&self_1) {self_1;}
2080 fn item_macro_workaround(){
2082 &("macro_rules! item { ($i:item) => {$i}}
2084 macro_rules! iterator_impl {
2085 () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
2086 iterator_impl! { }",
2087 vec
!(vec
!(0)), true),
2091 // run one of the renaming tests
2092 fn run_renaming_test(t
: &RenamingTest
, test_idx
: usize) {
2093 let invalid_name
= token
::special_idents
::invalid
.name
;
2094 let (teststr
, bound_connections
, bound_ident_check
) = match *t
{
2095 (ref str,ref conns
, bic
) => (str.to_string(), conns
.clone(), bic
)
2097 let cr
= expand_crate_str(teststr
.to_string());
2098 let bindings
= crate_bindings(&cr
);
2099 let varrefs
= crate_varrefs(&cr
);
2101 // must be one check clause for each binding:
2102 assert_eq
!(bindings
.len(),bound_connections
.len());
2103 for (binding_idx
,shouldmatch
) in bound_connections
.iter().enumerate() {
2104 let binding_name
= mtwt
::resolve(bindings
[binding_idx
]);
2105 let binding_marks
= mtwt
::marksof(bindings
[binding_idx
].ctxt
, invalid_name
);
2106 // shouldmatch can't name varrefs that don't exist:
2107 assert
!((shouldmatch
.is_empty()) ||
2108 (varrefs
.len() > *shouldmatch
.iter().max().unwrap()));
2109 for (idx
,varref
) in varrefs
.iter().enumerate() {
2110 let print_hygiene_debug_info
= || {
2111 // good lord, you can't make a path with 0 segments, can you?
2112 let final_varref_ident
= match varref
.segments
.last() {
2113 Some(pathsegment
) => pathsegment
.identifier
,
2114 None
=> panic
!("varref with 0 path segments?")
2116 let varref_name
= mtwt
::resolve(final_varref_ident
);
2117 let varref_idents
: Vec
<ast
::Ident
>
2118 = varref
.segments
.iter().map(|s
| s
.identifier
)
2120 println
!("varref #{}: {:?}, resolves to {}",idx
, varref_idents
, varref_name
);
2121 println
!("varref's first segment's string: \"{}\"", final_varref_ident
);
2122 println
!("binding #{}: {}, resolves to {}",
2123 binding_idx
, bindings
[binding_idx
], binding_name
);
2124 mtwt
::with_sctable(|x
| mtwt
::display_sctable(x
));
2126 if shouldmatch
.contains(&idx
) {
2127 // it should be a path of length 1, and it should
2128 // be free-identifier=? or bound-identifier=? to the given binding
2129 assert_eq
!(varref
.segments
.len(),1);
2130 let varref_name
= mtwt
::resolve(varref
.segments
[0].identifier
);
2131 let varref_marks
= mtwt
::marksof(varref
.segments
[0]
2135 if !(varref_name
==binding_name
) {
2136 println
!("uh oh, should match but doesn't:");
2137 print_hygiene_debug_info();
2139 assert_eq
!(varref_name
,binding_name
);
2140 if bound_ident_check
{
2141 // we're checking bound-identifier=?, and the marks
2142 // should be the same, too:
2143 assert_eq
!(varref_marks
,binding_marks
.clone());
2146 let varref_name
= mtwt
::resolve(varref
.segments
[0].identifier
);
2147 let fail
= (varref
.segments
.len() == 1)
2148 && (varref_name
== binding_name
);
2151 println
!("failure on test {}",test_idx
);
2152 println
!("text of test case: \"{}\"", teststr
);
2154 println
!("uh oh, matches but shouldn't:");
2155 print_hygiene_debug_info();
2164 fn fmt_in_macro_used_inside_module_macro() {
2165 let crate_str
= "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
2166 macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
2169 let cr
= expand_crate_str(crate_str
);
2170 // find the xx binding
2171 let bindings
= crate_bindings(&cr
);
2172 let cxbinds
: Vec
<&ast
::Ident
> =
2173 bindings
.iter().filter(|b
| b
.name
== "xx").collect();
2174 let cxbinds
: &[&ast
::Ident
] = &cxbinds
[..];
2175 let cxbind
= match (cxbinds
.len(), cxbinds
.get(0)) {
2177 _
=> panic
!("expected just one binding for ext_cx")
2179 let resolved_binding
= mtwt
::resolve(*cxbind
);
2180 let varrefs
= crate_varrefs(&cr
);
2182 // the xx binding should bind all of the xx varrefs:
2183 for (idx
,v
) in varrefs
.iter().filter(|p
| {
2184 p
.segments
.len() == 1
2185 && p
.segments
[0].identifier
.name
== "xx"
2187 if mtwt
::resolve(v
.segments
[0].identifier
) != resolved_binding
{
2188 println
!("uh oh, xx binding didn't match xx varref:");
2189 println
!("this is xx varref \\# {}", idx
);
2190 println
!("binding: {}", cxbind
);
2191 println
!("resolves to: {}", resolved_binding
);
2192 println
!("varref: {}", v
.segments
[0].identifier
);
2193 println
!("resolves to: {}",
2194 mtwt
::resolve(v
.segments
[0].identifier
));
2195 mtwt
::with_sctable(|x
| mtwt
::display_sctable(x
));
2197 assert_eq
!(mtwt
::resolve(v
.segments
[0].identifier
),
2204 let pat
= string_to_pat(
2205 "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
2206 let idents
= pattern_bindings(&*pat
);
2207 assert_eq
!(idents
, strs_to_idents(vec
!("a","c","b","d")));
2210 // test the list of identifier patterns gathered by the visitor. Note that
2211 // 'None' is listed as an identifier pattern because we don't yet know that
2212 // it's the name of a 0-ary variant, and that 'i' appears twice in succession.
2214 fn crate_bindings_test(){
2215 let the_crate
= string_to_crate("fn main (a: i32) -> i32 {|b| {
2216 match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
2217 let idents
= crate_bindings(&the_crate
);
2218 assert_eq
!(idents
, strs_to_idents(vec
!("a","b","None","i","i","z","y")));
2221 // test the IdentRenamer directly
2223 fn ident_renamer_test () {
2224 let the_crate
= string_to_crate("fn f(x: i32){let x = x; x}".to_string());
2225 let f_ident
= token
::str_to_ident("f");
2226 let x_ident
= token
::str_to_ident("x");
2227 let int_ident
= token
::str_to_ident("i32");
2228 let renames
= vec
!((x_ident
,Name(16)));
2229 let mut renamer
= IdentRenamer{renames: &renames}
;
2230 let renamed_crate
= renamer
.fold_crate(the_crate
);
2231 let idents
= crate_idents(&renamed_crate
);
2232 let resolved
: Vec
<ast
::Name
> = idents
.iter().map(|id
| mtwt
::resolve(*id
)).collect();
2233 assert_eq
!(resolved
, [f_ident
.name
,Name(16),int_ident
.name
,Name(16),Name(16),Name(16)]);
2236 // test the PatIdentRenamer; only PatIdents get renamed
2238 fn pat_ident_renamer_test () {
2239 let the_crate
= string_to_crate("fn f(x: i32){let x = x; x}".to_string());
2240 let f_ident
= token
::str_to_ident("f");
2241 let x_ident
= token
::str_to_ident("x");
2242 let int_ident
= token
::str_to_ident("i32");
2243 let renames
= vec
!((x_ident
,Name(16)));
2244 let mut renamer
= PatIdentRenamer{renames: &renames}
;
2245 let renamed_crate
= renamer
.fold_crate(the_crate
);
2246 let idents
= crate_idents(&renamed_crate
);
2247 let resolved
: Vec
<ast
::Name
> = idents
.iter().map(|id
| mtwt
::resolve(*id
)).collect();
2248 let x_name
= x_ident
.name
;
2249 assert_eq
!(resolved
, [f_ident
.name
,Name(16),int_ident
.name
,Name(16),x_name
,x_name
]);