]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/expand.rs
eaee67f9a61746a4c06a4c8ee3eff2faf4094b5d
[rust.git] / src / libsyntax / ext / expand.rs
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.
4 //
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.
10
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};
15 use ast::TokenTree;
16 use ast;
17 use ast_util::path_to_ident;
18 use ext::mtwt;
19 use ext::build::AstBuilder;
20 use attr;
21 use attr::AttrMetaMethods;
22 use codemap;
23 use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
24 use ext::base::*;
25 use fold;
26 use fold::*;
27 use parse;
28 use parse::token::{fresh_mark, fresh_name, intern};
29 use parse::token;
30 use ptr::P;
31 use util::small_vector::SmallVector;
32 use visit;
33 use visit::Visitor;
34
35 pub fn expand_type(t: P<ast::Ty>,
36                    fld: &mut MacroExpander,
37                    impl_ty: Option<P<ast::Ty>>)
38                    -> P<ast::Ty> {
39     debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty);
40     let t = match (t.node.clone(), impl_ty) {
41         // Expand uses of `Self` in impls to the concrete type.
42         (ast::Ty_::TyPath(ref path, _), Some(ref impl_ty)) => {
43             let path_as_ident = path_to_ident(path);
44             // Note unhygenic comparison here. I think this is correct, since
45             // even though `Self` is almost just a type parameter, the treatment
46             // for this expansion is as if it were a keyword.
47             if path_as_ident.is_some() &&
48                path_as_ident.unwrap().name == token::special_idents::type_self.name {
49                 impl_ty.clone()
50             } else {
51                 t
52             }
53         }
54         _ => t
55     };
56     fold::noop_fold_ty(t, fld)
57 }
58
59 pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
60     e.and_then(|ast::Expr {id, node, span}| match node {
61         // expr_mac should really be expr_ext or something; it's the
62         // entry-point for all syntax extensions.
63         ast::ExprMac(mac) => {
64             let expanded_expr = match expand_mac_invoc(mac, span,
65                                                        |r| r.make_expr(),
66                                                        mark_expr, fld) {
67                 Some(expr) => expr,
68                 None => {
69                     return DummyResult::raw_expr(span);
70                 }
71             };
72
73             // Keep going, outside-in.
74             //
75             let fully_expanded = fld.fold_expr(expanded_expr);
76             fld.cx.bt_pop();
77
78             fully_expanded.map(|e| ast::Expr {
79                 id: ast::DUMMY_NODE_ID,
80                 node: e.node,
81                 span: span,
82             })
83         }
84
85         ast::ExprWhile(cond, body, opt_ident) => {
86             let cond = fld.fold_expr(cond);
87             let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
88             fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
89         }
90
91         // Desugar ExprWhileLet
92         // From: `[opt_ident]: while let <pat> = <expr> <body>`
93         ast::ExprWhileLet(pat, expr, body, opt_ident) => {
94             // to:
95             //
96             //   [opt_ident]: loop {
97             //     match <expr> {
98             //       <pat> => <body>,
99             //       _ => break
100             //     }
101             //   }
102
103             // `<pat> => <body>`
104             let pat_arm = {
105                 let body_expr = fld.cx.expr_block(body);
106                 fld.cx.arm(pat.span, vec![pat], body_expr)
107             };
108
109             // `_ => break`
110             let break_arm = {
111                 let pat_under = fld.cx.pat_wild(span);
112                 let break_expr = fld.cx.expr_break(span);
113                 fld.cx.arm(span, vec![pat_under], break_expr)
114             };
115
116             // `match <expr> { ... }`
117             let arms = vec![pat_arm, break_arm];
118             let match_expr = fld.cx.expr(span,
119                                     ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
120
121             // `[opt_ident]: loop { ... }`
122             let loop_block = fld.cx.block_expr(match_expr);
123             let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
124             fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
125         }
126
127         // Desugar ExprIfLet
128         // From: `if let <pat> = <expr> <body> [<elseopt>]`
129         ast::ExprIfLet(pat, expr, body, mut elseopt) => {
130             // to:
131             //
132             //   match <expr> {
133             //     <pat> => <body>,
134             //     [_ if <elseopt_if_cond> => <elseopt_if_body>,]
135             //     _ => [<elseopt> | ()]
136             //   }
137
138             // `<pat> => <body>`
139             let pat_arm = {
140                 let body_expr = fld.cx.expr_block(body);
141                 fld.cx.arm(pat.span, vec![pat], body_expr)
142             };
143
144             // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
145             let else_if_arms = {
146                 let mut arms = vec![];
147                 loop {
148                     let elseopt_continue = elseopt
149                         .and_then(|els| els.and_then(|els| match els.node {
150                         // else if
151                         ast::ExprIf(cond, then, elseopt) => {
152                             let pat_under = fld.cx.pat_wild(span);
153                             arms.push(ast::Arm {
154                                 attrs: vec![],
155                                 pats: vec![pat_under],
156                                 guard: Some(cond),
157                                 body: fld.cx.expr_block(then)
158                             });
159                             elseopt.map(|elseopt| (elseopt, true))
160                         }
161                         _ => Some((P(els), false))
162                     }));
163                     match elseopt_continue {
164                         Some((e, true)) => {
165                             elseopt = Some(e);
166                         }
167                         Some((e, false)) => {
168                             elseopt = Some(e);
169                             break;
170                         }
171                         None => {
172                             elseopt = None;
173                             break;
174                         }
175                     }
176                 }
177                 arms
178             };
179
180             let contains_else_clause = elseopt.is_some();
181
182             // `_ => [<elseopt> | ()]`
183             let else_arm = {
184                 let pat_under = fld.cx.pat_wild(span);
185                 let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![]));
186                 fld.cx.arm(span, vec![pat_under], else_expr)
187             };
188
189             let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
190             arms.push(pat_arm);
191             arms.extend(else_if_arms.into_iter());
192             arms.push(else_arm);
193
194             let match_expr = fld.cx.expr(span,
195                                          ast::ExprMatch(expr, arms,
196                                                 ast::MatchSource::IfLetDesugar {
197                                                     contains_else_clause: contains_else_clause,
198                                                 }));
199             fld.fold_expr(match_expr)
200         }
201
202         // Desugar support for ExprIfLet in the ExprIf else position
203         ast::ExprIf(cond, blk, elseopt) => {
204             let elseopt = elseopt.map(|els| els.and_then(|els| match els.node {
205                 ast::ExprIfLet(..) => {
206                     // wrap the if-let expr in a block
207                     let span = els.span;
208                     let blk = P(ast::Block {
209                         stmts: vec![],
210                         expr: Some(P(els)),
211                         id: ast::DUMMY_NODE_ID,
212                         rules: ast::DefaultBlock,
213                         span: span
214                     });
215                     fld.cx.expr_block(blk)
216                 }
217                 _ => P(els)
218             }));
219             let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt));
220             if_expr.map(|e| noop_fold_expr(e, fld))
221         }
222
223         ast::ExprLoop(loop_block, opt_ident) => {
224             let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
225             fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
226         }
227
228         // Desugar ExprForLoop
229         // From: `[opt_ident]: for <pat> in <head> <body>`
230         ast::ExprForLoop(pat, head, body, opt_ident) => {
231             // to:
232             //
233             //   match ::std::iter::IntoIterator::into_iter(<head>) {
234             //     mut iter => {
235             //       [opt_ident]: loop {
236             //         match ::std::iter::Iterator::next(&mut iter) {
237             //           ::std::option::Option::Some(<pat>) => <body>,
238             //           ::std::option::Option::None => break
239             //         }
240             //       }
241             //     }
242             //   }
243
244             // expand <head>
245             let head = fld.fold_expr(head);
246
247             // create an hygienic ident
248             let iter = {
249                 let ident = fld.cx.ident_of("iter");
250                 let new_ident = fresh_name(&ident);
251                 let rename = (ident, new_ident);
252                 let mut rename_list = vec![rename];
253                 let mut rename_fld = IdentRenamer{ renames: &mut rename_list };
254
255                 rename_fld.fold_ident(ident)
256             };
257
258             let pat_span = pat.span;
259             // `:;std::option::Option::Some(<pat>) => <body>`
260             let pat_arm = {
261                 let body_expr = fld.cx.expr_block(body);
262                 let some_pat = fld.cx.pat_some(pat_span, pat);
263
264                 fld.cx.arm(pat_span, vec![some_pat], body_expr)
265             };
266
267             // `::std::option::Option::None => break`
268             let break_arm = {
269                 let break_expr = fld.cx.expr_break(span);
270
271                 fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr)
272             };
273
274             // `match ::std::iter::Iterator::next(&mut iter) { ... }`
275             let match_expr = {
276                 let next_path = {
277                     let strs = vec![
278                         fld.cx.ident_of("std"),
279                         fld.cx.ident_of("iter"),
280                         fld.cx.ident_of("Iterator"),
281                         fld.cx.ident_of("next"),
282                     ];
283
284                     fld.cx.path_global(span, strs)
285                 };
286                 let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter));
287                 let next_expr =
288                     fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]);
289                 let arms = vec![pat_arm, break_arm];
290
291                 fld.cx.expr(pat_span,
292                             ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar))
293             };
294
295             // `[opt_ident]: loop { ... }`
296             let loop_block = fld.cx.block_expr(match_expr);
297             let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
298             let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
299
300             // `mut iter => { ... }`
301             let iter_arm = {
302                 let iter_pat =
303                     fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable));
304                 fld.cx.arm(span, vec![iter_pat], loop_expr)
305             };
306
307             // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
308             let into_iter_expr = {
309                 let into_iter_path = {
310                     let strs = vec![
311                         fld.cx.ident_of("std"),
312                         fld.cx.ident_of("iter"),
313                         fld.cx.ident_of("IntoIterator"),
314                         fld.cx.ident_of("into_iter"),
315                     ];
316
317                     fld.cx.path_global(span, strs)
318                 };
319
320                 fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
321             };
322             fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
323         }
324
325         ast::ExprClosure(capture_clause, fn_decl, block) => {
326             let (rewritten_fn_decl, rewritten_block)
327                 = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
328             let new_node = ast::ExprClosure(capture_clause,
329                                             rewritten_fn_decl,
330                                             rewritten_block);
331             P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})
332         }
333
334         _ => {
335             P(noop_fold_expr(ast::Expr {
336                 id: id,
337                 node: node,
338                 span: span
339             }, fld))
340         }
341     })
342 }
343
344 /// Expand a (not-ident-style) macro invocation. Returns the result
345 /// of expansion and the mark which must be applied to the result.
346 /// Our current interface doesn't allow us to apply the mark to the
347 /// result until after calling make_expr, make_items, etc.
348 fn expand_mac_invoc<T, F, G>(mac: ast::Mac, span: codemap::Span,
349                              parse_thunk: F,
350                              mark_thunk: G,
351                              fld: &mut MacroExpander)
352                              -> Option<T> where
353     F: FnOnce(Box<MacResult>) -> Option<T>,
354     G: FnOnce(T, Mrk) -> T,
355 {
356     match mac.node {
357         // it would almost certainly be cleaner to pass the whole
358         // macro invocation in, rather than pulling it apart and
359         // marking the tts and the ctxt separately. This also goes
360         // for the other three macro invocation chunks of code
361         // in this file.
362         // Token-tree macros:
363         MacInvocTT(pth, tts, _) => {
364             if pth.segments.len() > 1 {
365                 fld.cx.span_err(pth.span,
366                                 "expected macro name without module \
367                                 separators");
368                 // let compilation continue
369                 return None;
370             }
371             let extname = pth.segments[0].identifier;
372             let extnamestr = token::get_ident(extname);
373             match fld.cx.syntax_env.find(&extname.name) {
374                 None => {
375                     fld.cx.span_err(
376                         pth.span,
377                         &format!("macro undefined: '{}!'",
378                                 extnamestr.get())[]);
379
380                     // let compilation continue
381                     None
382                 }
383                 Some(rc) => match *rc {
384                     NormalTT(ref expandfun, exp_span) => {
385                         fld.cx.bt_push(ExpnInfo {
386                                 call_site: span,
387                                 callee: NameAndSpan {
388                                     name: extnamestr.get().to_string(),
389                                     format: MacroBang,
390                                     span: exp_span,
391                                 },
392                             });
393                         let fm = fresh_mark();
394                         let marked_before = mark_tts(&tts[], fm);
395
396                         // The span that we pass to the expanders we want to
397                         // be the root of the call stack. That's the most
398                         // relevant span and it's the actual invocation of
399                         // the macro.
400                         let mac_span = fld.cx.original_span();
401
402                         let opt_parsed = {
403                             let expanded = expandfun.expand(fld.cx,
404                                                             mac_span,
405                                                             &marked_before[]);
406                             parse_thunk(expanded)
407                         };
408                         let parsed = match opt_parsed {
409                             Some(e) => e,
410                             None => {
411                                 fld.cx.span_err(
412                                     pth.span,
413                                     &format!("non-expression macro in expression position: {}",
414                                             &extnamestr.get()[]
415                                             )[]);
416                                 return None;
417                             }
418                         };
419                         Some(mark_thunk(parsed,fm))
420                     }
421                     _ => {
422                         fld.cx.span_err(
423                             pth.span,
424                             &format!("'{}' is not a tt-style macro",
425                                     extnamestr.get())[]);
426                         None
427                     }
428                 }
429             }
430         }
431     }
432 }
433
434 /// Rename loop label and expand its loop body
435 ///
436 /// The renaming procedure for loop is different in the sense that the loop
437 /// body is in a block enclosed by loop head so the renaming of loop label
438 /// must be propagated to the enclosed context.
439 fn expand_loop_block(loop_block: P<Block>,
440                      opt_ident: Option<Ident>,
441                      fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
442     match opt_ident {
443         Some(label) => {
444             let new_label = fresh_name(&label);
445             let rename = (label, new_label);
446
447             // The rename *must not* be added to the pending list of current
448             // syntax context otherwise an unrelated `break` or `continue` in
449             // the same context will pick that up in the deferred renaming pass
450             // and be renamed incorrectly.
451             let mut rename_list = vec!(rename);
452             let mut rename_fld = IdentRenamer{renames: &mut rename_list};
453             let renamed_ident = rename_fld.fold_ident(label);
454
455             // The rename *must* be added to the enclosed syntax context for
456             // `break` or `continue` to pick up because by definition they are
457             // in a block enclosed by loop head.
458             fld.cx.syntax_env.push_frame();
459             fld.cx.syntax_env.info().pending_renames.push(rename);
460             let expanded_block = expand_block_elts(loop_block, fld);
461             fld.cx.syntax_env.pop_frame();
462
463             (expanded_block, Some(renamed_ident))
464         }
465         None => (fld.fold_block(loop_block), opt_ident)
466     }
467 }
468
469 // eval $e with a new exts frame.
470 // must be a macro so that $e isn't evaluated too early.
471 macro_rules! with_exts_frame {
472     ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
473     ({$extsboxexpr.push_frame();
474       $extsboxexpr.info().macros_escape = $macros_escape;
475       let result = $e;
476       $extsboxexpr.pop_frame();
477       result
478      })
479 }
480
481 // When we enter a module, record it, for the sake of `module!`
482 pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
483                    -> SmallVector<P<ast::Item>> {
484     let it = expand_item_modifiers(it, fld);
485
486     expand_annotatable(Annotatable::Item(it), fld)
487         .into_iter().map(|i| i.expect_item()).collect()
488 }
489
490 fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
491                          -> P<ast::Item> {
492     // partition the attributes into ItemModifiers and others
493     let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
494
495     // update the attrs, leave everything else alone. Is this mutation really a good idea?
496     it = P(ast::Item {
497         attrs: other_attrs,
498         ..(*it).clone()
499     });
500
501     if modifiers.is_empty() {
502         let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
503         return it.expect_item();
504     }
505
506     for attr in &modifiers {
507         let mname = attr.name();
508
509         match fld.cx.syntax_env.find(&intern(mname.get())) {
510             Some(rc) => match *rc {
511                 Modifier(ref mac) => {
512                     attr::mark_used(attr);
513                     fld.cx.bt_push(ExpnInfo {
514                         call_site: attr.span,
515                         callee: NameAndSpan {
516                             name: mname.get().to_string(),
517                             format: MacroAttribute,
518                             span: None,
519                         }
520                     });
521                     it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
522                     fld.cx.bt_pop();
523                 }
524                 _ => unreachable!()
525             },
526             _ => unreachable!()
527         }
528     }
529
530     // Expansion may have added new ItemModifiers.
531     // It is possible, that an item modifier could expand to a multi-modifier or
532     // vice versa. In this case we will expand all modifiers before multi-modifiers,
533     // which might give an odd ordering. However, I think it is unlikely that the
534     // two kinds will be mixed, and I old-style multi-modifiers should be deprecated
535     // anyway.
536     expand_item_modifiers(it, fld)
537 }
538
539 /// Expand item_underscore
540 fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
541     match item {
542         ast::ItemFn(decl, fn_style, abi, generics, body) => {
543             let (rewritten_fn_decl, rewritten_body)
544                 = expand_and_rename_fn_decl_and_block(decl, body, fld);
545             let expanded_generics = fold::noop_fold_generics(generics,fld);
546             ast::ItemFn(rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body)
547         }
548         _ => noop_fold_item_underscore(item, fld)
549     }
550 }
551
552 // does this attribute list contain "macro_use" ?
553 fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
554     for attr in attrs {
555         let mut is_use = attr.check_name("macro_use");
556         if attr.check_name("macro_escape") {
557             fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
558             is_use = true;
559             if let ast::AttrInner = attr.node.style {
560                 fld.cx.span_help(attr.span, "consider an outer attribute, \
561                                              #[macro_use] mod ...");
562             }
563         };
564
565         if is_use {
566             match attr.node.value.node {
567                 ast::MetaWord(..) => (),
568                 _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"),
569             }
570             return true;
571         }
572     }
573     false
574 }
575
576 // Support for item-position macro invocations, exactly the same
577 // logic as for expression-position macro invocations.
578 pub fn expand_item_mac(it: P<ast::Item>,
579                        fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
580     let (extname, path_span, tts) = match it.node {
581         ItemMac(codemap::Spanned {
582             node: MacInvocTT(ref pth, ref tts, _),
583             ..
584         }) => {
585             (pth.segments[0].identifier, pth.span, (*tts).clone())
586         }
587         _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
588     };
589
590     let extnamestr = token::get_ident(extname);
591     let fm = fresh_mark();
592     let items = {
593         let expanded = match fld.cx.syntax_env.find(&extname.name) {
594             None => {
595                 fld.cx.span_err(path_span,
596                                 &format!("macro undefined: '{}!'",
597                                         extnamestr)[]);
598                 // let compilation continue
599                 return SmallVector::zero();
600             }
601
602             Some(rc) => match *rc {
603                 NormalTT(ref expander, span) => {
604                     if it.ident.name != parse::token::special_idents::invalid.name {
605                         fld.cx
606                             .span_err(path_span,
607                                       &format!("macro {}! expects no ident argument, \
608                                         given '{}'",
609                                       extnamestr,
610                                       token::get_ident(it.ident))[]);
611                         return SmallVector::zero();
612                     }
613                     fld.cx.bt_push(ExpnInfo {
614                         call_site: it.span,
615                         callee: NameAndSpan {
616                             name: extnamestr.get().to_string(),
617                             format: MacroBang,
618                             span: span
619                         }
620                     });
621                     // mark before expansion:
622                     let marked_before = mark_tts(&tts[], fm);
623                     expander.expand(fld.cx, it.span, &marked_before[])
624                 }
625                 IdentTT(ref expander, span) => {
626                     if it.ident.name == parse::token::special_idents::invalid.name {
627                         fld.cx.span_err(path_span,
628                                         &format!("macro {}! expects an ident argument",
629                                                 extnamestr.get())[]);
630                         return SmallVector::zero();
631                     }
632                     fld.cx.bt_push(ExpnInfo {
633                         call_site: it.span,
634                         callee: NameAndSpan {
635                             name: extnamestr.get().to_string(),
636                             format: MacroBang,
637                             span: span
638                         }
639                     });
640                     // mark before expansion:
641                     let marked_tts = mark_tts(&tts[], fm);
642                     expander.expand(fld.cx, it.span, it.ident, marked_tts)
643                 }
644                 MacroRulesTT => {
645                     if it.ident.name == parse::token::special_idents::invalid.name {
646                         fld.cx.span_err(path_span,
647                                         &format!("macro_rules! expects an ident argument")
648                                         []);
649                         return SmallVector::zero();
650                     }
651                     fld.cx.bt_push(ExpnInfo {
652                         call_site: it.span,
653                         callee: NameAndSpan {
654                             name: extnamestr.get().to_string(),
655                             format: MacroBang,
656                             span: None,
657                         }
658                     });
659                     // DON'T mark before expansion.
660
661                     let def = ast::MacroDef {
662                         ident: it.ident,
663                         attrs: it.attrs.clone(),
664                         id: ast::DUMMY_NODE_ID,
665                         span: it.span,
666                         imported_from: None,
667                         export: attr::contains_name(&it.attrs, "macro_export"),
668                         use_locally: true,
669                         body: tts,
670                     };
671                     fld.cx.insert_macro(def);
672
673                     // macro_rules! has a side effect but expands to nothing.
674                     fld.cx.bt_pop();
675                     return SmallVector::zero();
676                 }
677                 _ => {
678                     fld.cx.span_err(it.span,
679                                     &format!("{}! is not legal in item position",
680                                             extnamestr.get())[]);
681                     return SmallVector::zero();
682                 }
683             }
684         };
685
686         expanded.make_items()
687     };
688
689     let items = match items {
690         Some(items) => {
691             items.into_iter()
692                 .map(|i| mark_item(i, fm))
693                 .flat_map(|i| fld.fold_item(i).into_iter())
694                 .collect()
695         }
696         None => {
697             fld.cx.span_err(path_span,
698                             &format!("non-item macro in item position: {}",
699                                     extnamestr.get())[]);
700             return SmallVector::zero();
701         }
702     };
703
704     fld.cx.bt_pop();
705     items
706 }
707
708 /// Expand a stmt
709 fn expand_stmt(s: Stmt, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
710     let (mac, style) = match s.node {
711         StmtMac(mac, style) => (mac, style),
712         _ => return expand_non_macro_stmt(s, fld)
713     };
714     let expanded_stmt = match expand_mac_invoc(mac.and_then(|m| m), s.span,
715                                                 |r| r.make_stmt(),
716                                                 mark_stmt, fld) {
717         Some(stmt) => stmt,
718         None => {
719             return SmallVector::zero();
720         }
721     };
722
723     // Keep going, outside-in.
724     let fully_expanded = fld.fold_stmt(expanded_stmt);
725     fld.cx.bt_pop();
726
727     if style == MacStmtWithSemicolon {
728         fully_expanded.into_iter().map(|s| s.map(|Spanned {node, span}| {
729             Spanned {
730                 node: match node {
731                     StmtExpr(e, stmt_id) => StmtSemi(e, stmt_id),
732                     _ => node /* might already have a semi */
733                 },
734                 span: span
735             }
736         })).collect()
737     } else {
738         fully_expanded
739     }
740 }
741
742 // expand a non-macro stmt. this is essentially the fallthrough for
743 // expand_stmt, above.
744 fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroExpander)
745                          -> SmallVector<P<Stmt>> {
746     // is it a let?
747     match node {
748         StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl {
749             DeclLocal(local) => {
750                 // take it apart:
751                 let rewritten_local = local.map(|Local {id, pat, ty, init, source, span}| {
752                     // expand the ty since TyFixedLengthVec contains an Expr
753                     // and thus may have a macro use
754                     let expanded_ty = ty.map(|t| fld.fold_ty(t));
755                     // expand the pat (it might contain macro uses):
756                     let expanded_pat = fld.fold_pat(pat);
757                     // find the PatIdents in the pattern:
758                     // oh dear heaven... this is going to include the enum
759                     // names, as well... but that should be okay, as long as
760                     // the new names are gensyms for the old ones.
761                     // generate fresh names, push them to a new pending list
762                     let idents = pattern_bindings(&*expanded_pat);
763                     let mut new_pending_renames =
764                         idents.iter().map(|ident| (*ident, fresh_name(ident))).collect();
765                     // rewrite the pattern using the new names (the old
766                     // ones have already been applied):
767                     let rewritten_pat = {
768                         // nested binding to allow borrow to expire:
769                         let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
770                         rename_fld.fold_pat(expanded_pat)
771                     };
772                     // add them to the existing pending renames:
773                     fld.cx.syntax_env.info().pending_renames
774                           .extend(new_pending_renames.into_iter());
775                     Local {
776                         id: id,
777                         ty: expanded_ty,
778                         pat: rewritten_pat,
779                         // also, don't forget to expand the init:
780                         init: init.map(|e| fld.fold_expr(e)),
781                         source: source,
782                         span: span
783                     }
784                 });
785                 SmallVector::one(P(Spanned {
786                     node: StmtDecl(P(Spanned {
787                             node: DeclLocal(rewritten_local),
788                             span: span
789                         }),
790                         node_id),
791                     span: stmt_span
792                 }))
793             }
794             _ => {
795                 noop_fold_stmt(Spanned {
796                     node: StmtDecl(P(Spanned {
797                             node: decl,
798                             span: span
799                         }),
800                         node_id),
801                     span: stmt_span
802                 }, fld)
803             }
804         }),
805         _ => {
806             noop_fold_stmt(Spanned {
807                 node: node,
808                 span: stmt_span
809             }, fld)
810         }
811     }
812 }
813
814 // expand the arm of a 'match', renaming for macro hygiene
815 fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
816     // expand pats... they might contain macro uses:
817     let expanded_pats = arm.pats.move_map(|pat| fld.fold_pat(pat));
818     if expanded_pats.len() == 0 {
819         panic!("encountered match arm with 0 patterns");
820     }
821     // all of the pats must have the same set of bindings, so use the
822     // first one to extract them and generate new names:
823     let idents = pattern_bindings(&*expanded_pats[0]);
824     let new_renames = idents.into_iter().map(|id| (id, fresh_name(&id))).collect();
825     // apply the renaming, but only to the PatIdents:
826     let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
827     let rewritten_pats = expanded_pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
828     // apply renaming and then expansion to the guard and the body:
829     let mut rename_fld = IdentRenamer{renames:&new_renames};
830     let rewritten_guard =
831         arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
832     let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
833     ast::Arm {
834         attrs: arm.attrs.move_map(|x| fld.fold_attribute(x)),
835         pats: rewritten_pats,
836         guard: rewritten_guard,
837         body: rewritten_body,
838     }
839 }
840
841 /// A visitor that extracts the PatIdent (binding) paths
842 /// from a given thingy and puts them in a mutable
843 /// array
844 #[derive(Clone)]
845 struct PatIdentFinder {
846     ident_accumulator: Vec<ast::Ident>
847 }
848
849 impl<'v> Visitor<'v> for PatIdentFinder {
850     fn visit_pat(&mut self, pattern: &ast::Pat) {
851         match *pattern {
852             ast::Pat { id: _, node: ast::PatIdent(_, ref path1, ref inner), span: _ } => {
853                 self.ident_accumulator.push(path1.node);
854                 // visit optional subpattern of PatIdent:
855                 if let Some(ref subpat) = *inner {
856                     self.visit_pat(&**subpat)
857                 }
858             }
859             // use the default traversal for non-PatIdents
860             _ => visit::walk_pat(self, pattern)
861         }
862     }
863 }
864
865 /// find the PatIdent paths in a pattern
866 fn pattern_bindings(pat: &ast::Pat) -> Vec<ast::Ident> {
867     let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
868     name_finder.visit_pat(pat);
869     name_finder.ident_accumulator
870 }
871
872 /// find the PatIdent paths in a
873 fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec<ast::Ident> {
874     let mut pat_idents = PatIdentFinder{ident_accumulator:Vec::new()};
875     for arg in &fn_decl.inputs {
876         pat_idents.visit_pat(&*arg.pat);
877     }
878     pat_idents.ident_accumulator
879 }
880
881 // expand a block. pushes a new exts_frame, then calls expand_block_elts
882 pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {
883     // see note below about treatment of exts table
884     with_exts_frame!(fld.cx.syntax_env,false,
885                      expand_block_elts(blk, fld))
886 }
887
888 // expand the elements of a block.
889 pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
890     b.map(|Block {id, stmts, expr, rules, span}| {
891         let new_stmts = stmts.into_iter().flat_map(|x| {
892             // perform all pending renames
893             let renamed_stmt = {
894                 let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
895                 let mut rename_fld = IdentRenamer{renames:pending_renames};
896                 rename_fld.fold_stmt(x).expect_one("rename_fold didn't return one value")
897             };
898             // expand macros in the statement
899             fld.fold_stmt(renamed_stmt).into_iter()
900         }).collect();
901         let new_expr = expr.map(|x| {
902             let expr = {
903                 let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
904                 let mut rename_fld = IdentRenamer{renames:pending_renames};
905                 rename_fld.fold_expr(x)
906             };
907             fld.fold_expr(expr)
908         });
909         Block {
910             id: fld.new_id(id),
911             stmts: new_stmts,
912             expr: new_expr,
913             rules: rules,
914             span: span
915         }
916     })
917 }
918
919 fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
920     match p.node {
921         PatMac(_) => {}
922         _ => return noop_fold_pat(p, fld)
923     }
924     p.map(|ast::Pat {node, span, ..}| {
925         let (pth, tts) = match node {
926             PatMac(mac) => match mac.node {
927                 MacInvocTT(pth, tts, _) => {
928                     (pth, tts)
929                 }
930             },
931             _ => unreachable!()
932         };
933         if pth.segments.len() > 1 {
934             fld.cx.span_err(pth.span, "expected macro name without module separators");
935             return DummyResult::raw_pat(span);
936         }
937         let extname = pth.segments[0].identifier;
938         let extnamestr = token::get_ident(extname);
939         let marked_after = match fld.cx.syntax_env.find(&extname.name) {
940             None => {
941                 fld.cx.span_err(pth.span,
942                                 &format!("macro undefined: '{}!'",
943                                         extnamestr)[]);
944                 // let compilation continue
945                 return DummyResult::raw_pat(span);
946             }
947
948             Some(rc) => match *rc {
949                 NormalTT(ref expander, tt_span) => {
950                     fld.cx.bt_push(ExpnInfo {
951                         call_site: span,
952                         callee: NameAndSpan {
953                             name: extnamestr.get().to_string(),
954                             format: MacroBang,
955                             span: tt_span
956                         }
957                     });
958
959                     let fm = fresh_mark();
960                     let marked_before = mark_tts(&tts[], fm);
961                     let mac_span = fld.cx.original_span();
962                     let expanded = match expander.expand(fld.cx,
963                                         mac_span,
964                                         &marked_before[]).make_pat() {
965                         Some(e) => e,
966                         None => {
967                             fld.cx.span_err(
968                                 pth.span,
969                                 &format!(
970                                     "non-pattern macro in pattern position: {}",
971                                     extnamestr.get()
972                                     )[]
973                             );
974                             return DummyResult::raw_pat(span);
975                         }
976                     };
977
978                     // mark after:
979                     mark_pat(expanded,fm)
980                 }
981                 _ => {
982                     fld.cx.span_err(span,
983                                     &format!("{}! is not legal in pattern position",
984                                             extnamestr.get())[]);
985                     return DummyResult::raw_pat(span);
986                 }
987             }
988         };
989
990         let fully_expanded =
991             fld.fold_pat(marked_after).node.clone();
992         fld.cx.bt_pop();
993
994         ast::Pat {
995             id: ast::DUMMY_NODE_ID,
996             node: fully_expanded,
997             span: span
998         }
999     })
1000 }
1001
1002 /// A tree-folder that applies every rename in its (mutable) list
1003 /// to every identifier, including both bindings and varrefs
1004 /// (and lots of things that will turn out to be neither)
1005 pub struct IdentRenamer<'a> {
1006     renames: &'a mtwt::RenameList,
1007 }
1008
1009 impl<'a> Folder for IdentRenamer<'a> {
1010     fn fold_ident(&mut self, id: Ident) -> Ident {
1011         Ident {
1012             name: id.name,
1013             ctxt: mtwt::apply_renames(self.renames, id.ctxt),
1014         }
1015     }
1016     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
1017         fold::noop_fold_mac(mac, self)
1018     }
1019 }
1020
1021 /// A tree-folder that applies every rename in its list to
1022 /// the idents that are in PatIdent patterns. This is more narrowly
1023 /// focused than IdentRenamer, and is needed for FnDecl,
1024 /// where we want to rename the args but not the fn name or the generics etc.
1025 pub struct PatIdentRenamer<'a> {
1026     renames: &'a mtwt::RenameList,
1027 }
1028
1029 impl<'a> Folder for PatIdentRenamer<'a> {
1030     fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
1031         match pat.node {
1032             ast::PatIdent(..) => {},
1033             _ => return noop_fold_pat(pat, self)
1034         }
1035
1036         pat.map(|ast::Pat {id, node, span}| match node {
1037             ast::PatIdent(binding_mode, Spanned{span: sp, node: ident}, sub) => {
1038                 let new_ident = Ident{name: ident.name,
1039                                       ctxt: mtwt::apply_renames(self.renames, ident.ctxt)};
1040                 let new_node =
1041                     ast::PatIdent(binding_mode,
1042                                   Spanned{span: self.new_span(sp), node: new_ident},
1043                                   sub.map(|p| self.fold_pat(p)));
1044                 ast::Pat {
1045                     id: id,
1046                     node: new_node,
1047                     span: self.new_span(span)
1048                 }
1049             },
1050             _ => unreachable!()
1051         })
1052     }
1053     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
1054         fold::noop_fold_mac(mac, self)
1055     }
1056 }
1057
1058 fn expand_annotatable(a: Annotatable,
1059                       fld: &mut MacroExpander)
1060                       -> SmallVector<Annotatable> {
1061     let a = expand_item_multi_modifier(a, fld);
1062
1063     let mut decorator_items = SmallVector::zero();
1064     let mut new_attrs = Vec::new();
1065     for attr in a.attrs() {
1066         let mname = attr.name();
1067
1068         match fld.cx.syntax_env.find(&intern(mname.get())) {
1069             Some(rc) => match *rc {
1070                 Decorator(ref dec) => {
1071                     let it = match a {
1072                         Annotatable::Item(ref it) => it,
1073                         // ItemDecorators are only implemented for Items.
1074                         _ => break,
1075                     };
1076
1077                     attr::mark_used(attr);
1078
1079                     fld.cx.bt_push(ExpnInfo {
1080                         call_site: attr.span,
1081                         callee: NameAndSpan {
1082                             name: mname.get().to_string(),
1083                             format: MacroAttribute,
1084                             span: None
1085                         }
1086                     });
1087
1088                     // we'd ideally decorator_items.push_all(expand_item(item, fld)),
1089                     // but that double-mut-borrows fld
1090                     let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
1091                     dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
1092                                box |item| items.push(item));
1093                     decorator_items.extend(items.into_iter()
1094                         .flat_map(|item| expand_item(item, fld).into_iter()));
1095
1096                     fld.cx.bt_pop();
1097                 }
1098                 _ => new_attrs.push((*attr).clone()),
1099             },
1100             _ => new_attrs.push((*attr).clone()),
1101         }
1102     }
1103
1104     let mut new_items: SmallVector<Annotatable> = match a {
1105         Annotatable::Item(it) => match it.node {
1106             ast::ItemMac(..) => {
1107                 expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
1108             }
1109             ast::ItemMod(_) | ast::ItemForeignMod(_) => {
1110                 let valid_ident =
1111                     it.ident.name != parse::token::special_idents::invalid.name;
1112
1113                 if valid_ident {
1114                     fld.cx.mod_push(it.ident);
1115                 }
1116                 let macro_use = contains_macro_use(fld, &new_attrs[]);
1117                 let result = with_exts_frame!(fld.cx.syntax_env,
1118                                               macro_use,
1119                                               noop_fold_item(it, fld));
1120                 if valid_ident {
1121                     fld.cx.mod_pop();
1122                 }
1123                 result.into_iter().map(|i| Annotatable::Item(i)).collect()
1124             },
1125             _ => {
1126                 let it = P(ast::Item {
1127                     attrs: new_attrs,
1128                     ..(*it).clone()
1129                 });
1130                 noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
1131             }
1132         },
1133         Annotatable::TraitItem(it) => match it {
1134             ast::TraitItem::ProvidedMethod(m) => {
1135                 expand_method(m, fld).into_iter().map(|m|
1136                     Annotatable::TraitItem(ast::TraitItem::ProvidedMethod(m))).collect()
1137             }
1138             ast::TraitItem::RequiredMethod(m) => {
1139                 SmallVector::one(Annotatable::TraitItem(
1140                     ast::TraitItem::RequiredMethod(fld.fold_type_method(m))))
1141             }
1142             ast::TraitItem::TypeTraitItem(t) => {
1143                 SmallVector::one(Annotatable::TraitItem(
1144                     ast::TraitItem::TypeTraitItem(P(fld.fold_associated_type((*t).clone())))))
1145             }
1146         },
1147         Annotatable::ImplItem(it) => match it {
1148             ast::ImplItem::MethodImplItem(m) => {
1149                 expand_method(m, fld).into_iter().map(|m|
1150                     Annotatable::ImplItem(ast::ImplItem::MethodImplItem(m))).collect()
1151             }
1152             ast::ImplItem::TypeImplItem(t) => {
1153                 SmallVector::one(Annotatable::ImplItem(
1154                     ast::ImplItem::TypeImplItem(P(fld.fold_typedef((*t).clone())))))
1155             }
1156         }
1157     };
1158
1159     new_items.push_all(decorator_items.into_iter().map(|i| Annotatable::Item(i)).collect());
1160     new_items
1161 }
1162
1163 fn expand_trait_item(i: ast::TraitItem,
1164                      fld: &mut MacroExpander)
1165                      -> SmallVector<ast::TraitItem> {
1166     expand_annotatable(Annotatable::TraitItem(i), fld)
1167         .into_iter().map(|i| i.expect_trait_item()).collect()
1168
1169 }
1170
1171 fn expand_impl_item(i: ast::ImplItem,
1172                     fld: &mut MacroExpander)
1173                     -> SmallVector<ast::ImplItem> {
1174     expand_annotatable(Annotatable::ImplItem(i), fld)
1175         .into_iter().map(|i| i.expect_impl_item()).collect()
1176 }
1177
1178 // partition the attributes into ItemModifiers and others
1179 fn modifiers(attrs: &Vec<ast::Attribute>,
1180              fld: &MacroExpander)
1181              -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
1182     attrs.iter().cloned().partition(|attr| {
1183         match fld.cx.syntax_env.find(&intern(attr.name().get())) {
1184             Some(rc) => match *rc {
1185                 Modifier(_) => true,
1186                 _ => false
1187             },
1188             _ => false
1189         }
1190     })
1191 }
1192
1193 // partition the attributes into MultiModifiers and others
1194 fn multi_modifiers(attrs: &[ast::Attribute],
1195                    fld: &MacroExpander)
1196                    -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
1197     attrs.iter().cloned().partition(|attr| {
1198         match fld.cx.syntax_env.find(&intern(attr.name().get())) {
1199             Some(rc) => match *rc {
1200                 MultiModifier(_) => true,
1201                 _ => false
1202             },
1203             _ => false
1204         }
1205     })
1206 }
1207
1208 fn expand_item_multi_modifier(mut it: Annotatable,
1209                               fld: &mut MacroExpander)
1210                               -> Annotatable {
1211     let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);
1212
1213     // Update the attrs, leave everything else alone. Is this mutation really a good idea?
1214     it = it.fold_attrs(other_attrs);
1215
1216     if modifiers.is_empty() {
1217         return it
1218     }
1219
1220     for attr in &modifiers {
1221         let mname = attr.name();
1222
1223         match fld.cx.syntax_env.find(&intern(mname.get())) {
1224             Some(rc) => match *rc {
1225                 MultiModifier(ref mac) => {
1226                     attr::mark_used(attr);
1227                     fld.cx.bt_push(ExpnInfo {
1228                         call_site: attr.span,
1229                         callee: NameAndSpan {
1230                             name: mname.get().to_string(),
1231                             format: MacroAttribute,
1232                             span: None,
1233                         }
1234                     });
1235                     it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
1236                     fld.cx.bt_pop();
1237                 }
1238                 _ => unreachable!()
1239             },
1240             _ => unreachable!()
1241         }
1242     }
1243
1244     // Expansion may have added new ItemModifiers.
1245     expand_item_multi_modifier(it, fld)
1246 }
1247
1248 // expand a method
1249 fn expand_method(m: P<ast::Method>, fld: &mut MacroExpander) -> SmallVector<P<ast::Method>> {
1250     m.and_then(|m| match m.node {
1251         ast::MethDecl(ident,
1252                       generics,
1253                       abi,
1254                       explicit_self,
1255                       fn_style,
1256                       decl,
1257                       body,
1258                       vis) => {
1259             let id = fld.new_id(m.id);
1260             let (rewritten_fn_decl, rewritten_body)
1261                 = expand_and_rename_fn_decl_and_block(decl, body, fld);
1262             SmallVector::one(P(ast::Method {
1263                     attrs: m.attrs.move_map(|a| fld.fold_attribute(a)),
1264                     id: id,
1265                     span: fld.new_span(m.span),
1266                     node: ast::MethDecl(fld.fold_ident(ident),
1267                                         noop_fold_generics(generics, fld),
1268                                         abi,
1269                                         fld.fold_explicit_self(explicit_self),
1270                                         fn_style,
1271                                         rewritten_fn_decl,
1272                                         rewritten_body,
1273                                         vis)
1274                 }))
1275         },
1276         ast::MethMac(mac) => {
1277             let maybe_new_methods =
1278                 expand_mac_invoc(mac, m.span,
1279                                  |r| r.make_methods(),
1280                                  |meths, mark| meths.move_map(|m| mark_method(m, mark)),
1281                                  fld);
1282
1283             match maybe_new_methods {
1284                 Some(methods) => {
1285                     // expand again if necessary
1286                     let new_methods = methods.into_iter()
1287                                              .flat_map(|m| fld.fold_method(m).into_iter())
1288                                              .collect();
1289                     fld.cx.bt_pop();
1290                     new_methods
1291                 }
1292                 None => SmallVector::zero()
1293             }
1294         }
1295     })
1296 }
1297
1298 /// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
1299 /// PatIdents in its arguments to perform renaming in the FnDecl and
1300 /// the block, returning both the new FnDecl and the new Block.
1301 fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Block>,
1302                                        fld: &mut MacroExpander)
1303     -> (P<ast::FnDecl>, P<ast::Block>) {
1304     let expanded_decl = fld.fold_fn_decl(fn_decl);
1305     let idents = fn_decl_arg_bindings(&*expanded_decl);
1306     let renames =
1307         idents.iter().map(|id : &ast::Ident| (*id,fresh_name(id))).collect();
1308     // first, a renamer for the PatIdents, for the fn_decl:
1309     let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
1310     let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
1311     // now, a renamer for *all* idents, for the body:
1312     let mut rename_fld = IdentRenamer{renames: &renames};
1313     let rewritten_body = fld.fold_block(rename_fld.fold_block(block));
1314     (rewritten_fn_decl,rewritten_body)
1315 }
1316
1317 /// A tree-folder that performs macro expansion
1318 pub struct MacroExpander<'a, 'b:'a> {
1319     pub cx: &'a mut ExtCtxt<'b>,
1320     // The type of the impl currently being expanded.
1321     current_impl_type: Option<P<ast::Ty>>,
1322 }
1323
1324 impl<'a, 'b> MacroExpander<'a, 'b> {
1325     pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1326         MacroExpander { cx: cx, current_impl_type: None }
1327     }
1328 }
1329
1330 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1331     fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1332         expand_expr(expr, self)
1333     }
1334
1335     fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
1336         expand_pat(pat, self)
1337     }
1338
1339     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1340         let prev_type = self.current_impl_type.clone();
1341         if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node {
1342             self.current_impl_type = Some(ty.clone());
1343         }
1344
1345         let result = expand_item(item, self);
1346         self.current_impl_type = prev_type;
1347         result
1348     }
1349
1350     fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
1351         expand_item_underscore(item, self)
1352     }
1353
1354     fn fold_stmt(&mut self, stmt: P<ast::Stmt>) -> SmallVector<P<ast::Stmt>> {
1355         stmt.and_then(|stmt| expand_stmt(stmt, self))
1356     }
1357
1358     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1359         expand_block(block, self)
1360     }
1361
1362     fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
1363         expand_arm(arm, self)
1364     }
1365
1366     fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
1367         expand_trait_item(i, self)
1368     }
1369
1370     fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
1371         expand_impl_item(i, self)
1372     }
1373
1374     fn fold_method(&mut self, method: P<ast::Method>) -> SmallVector<P<ast::Method>> {
1375         expand_method(method, self)
1376     }
1377
1378     fn fold_ty(&mut self, t: P<ast::Ty>) -> P<ast::Ty> {
1379         let impl_type = self.current_impl_type.clone();
1380         expand_type(t, self, impl_type)
1381     }
1382
1383     fn new_span(&mut self, span: Span) -> Span {
1384         new_span(self.cx, span)
1385     }
1386 }
1387
1388 fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
1389     /* this discards information in the case of macro-defining macros */
1390     Span {
1391         lo: sp.lo,
1392         hi: sp.hi,
1393         expn_id: cx.backtrace(),
1394     }
1395 }
1396
1397 pub struct ExpansionConfig {
1398     pub crate_name: String,
1399     pub enable_quotes: bool,
1400     pub recursion_limit: usize,
1401 }
1402
1403 impl ExpansionConfig {
1404     pub fn default(crate_name: String) -> ExpansionConfig {
1405         ExpansionConfig {
1406             crate_name: crate_name,
1407             enable_quotes: false,
1408             recursion_limit: 64,
1409         }
1410     }
1411 }
1412
1413 pub fn expand_crate(parse_sess: &parse::ParseSess,
1414                     cfg: ExpansionConfig,
1415                     // these are the macros being imported to this crate:
1416                     imported_macros: Vec<ast::MacroDef>,
1417                     user_exts: Vec<NamedSyntaxExtension>,
1418                     c: Crate) -> Crate {
1419     let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
1420     let mut expander = MacroExpander::new(&mut cx);
1421
1422     for def in imported_macros {
1423         expander.cx.insert_macro(def);
1424     }
1425
1426     for (name, extension) in user_exts {
1427         expander.cx.syntax_env.insert(name, extension);
1428     }
1429
1430     let mut ret = expander.fold_crate(c);
1431     ret.exported_macros = expander.cx.exported_macros.clone();
1432     parse_sess.span_diagnostic.handler().abort_if_errors();
1433     return ret;
1434 }
1435
1436 // HYGIENIC CONTEXT EXTENSION:
1437 // all of these functions are for walking over
1438 // ASTs and making some change to the context of every
1439 // element that has one. a CtxtFn is a trait-ified
1440 // version of a closure in (SyntaxContext -> SyntaxContext).
1441 // the ones defined here include:
1442 // Marker - add a mark to a context
1443
1444 // A Marker adds the given mark to the syntax context
1445 struct Marker { mark: Mrk }
1446
1447 impl Folder for Marker {
1448     fn fold_ident(&mut self, id: Ident) -> Ident {
1449         ast::Ident {
1450             name: id.name,
1451             ctxt: mtwt::apply_mark(self.mark, id.ctxt)
1452         }
1453     }
1454     fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1455         Spanned {
1456             node: match node {
1457                 MacInvocTT(path, tts, ctxt) => {
1458                     MacInvocTT(self.fold_path(path),
1459                                self.fold_tts(&tts[]),
1460                                mtwt::apply_mark(self.mark, ctxt))
1461                 }
1462             },
1463             span: span,
1464         }
1465     }
1466 }
1467
1468 // apply a given mark to the given token trees. Used prior to expansion of a macro.
1469 fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
1470     noop_fold_tts(tts, &mut Marker{mark:m})
1471 }
1472
1473 // apply a given mark to the given expr. Used following the expansion of a macro.
1474 fn mark_expr(expr: P<ast::Expr>, m: Mrk) -> P<ast::Expr> {
1475     Marker{mark:m}.fold_expr(expr)
1476 }
1477
1478 // apply a given mark to the given pattern. Used following the expansion of a macro.
1479 fn mark_pat(pat: P<ast::Pat>, m: Mrk) -> P<ast::Pat> {
1480     Marker{mark:m}.fold_pat(pat)
1481 }
1482
1483 // apply a given mark to the given stmt. Used following the expansion of a macro.
1484 fn mark_stmt(expr: P<ast::Stmt>, m: Mrk) -> P<ast::Stmt> {
1485     Marker{mark:m}.fold_stmt(expr)
1486         .expect_one("marking a stmt didn't return exactly one stmt")
1487 }
1488
1489 // apply a given mark to the given item. Used following the expansion of a macro.
1490 fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
1491     Marker{mark:m}.fold_item(expr)
1492         .expect_one("marking an item didn't return exactly one item")
1493 }
1494
1495 // apply a given mark to the given item. Used following the expansion of a macro.
1496 fn mark_method(expr: P<ast::Method>, m: Mrk) -> P<ast::Method> {
1497     Marker{mark:m}.fold_method(expr)
1498         .expect_one("marking an item didn't return exactly one method")
1499 }
1500
1501 /// Check that there are no macro invocations left in the AST:
1502 pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1503     visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
1504 }
1505
1506 /// A visitor that ensures that no macro invocations remain in an AST.
1507 struct MacroExterminator<'a>{
1508     sess: &'a parse::ParseSess
1509 }
1510
1511 impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
1512     fn visit_mac(&mut self, mac: &ast::Mac) {
1513         self.sess.span_diagnostic.span_bug(mac.span,
1514                                            "macro exterminator: expected AST \
1515                                            with no macro invocations");
1516     }
1517 }
1518
1519
1520 #[cfg(test)]
1521 mod test {
1522     use super::{pattern_bindings, expand_crate};
1523     use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1524     use ast;
1525     use ast::Name;
1526     use codemap;
1527     use ext::mtwt;
1528     use fold::Folder;
1529     use parse;
1530     use parse::token;
1531     use util::parser_testing::{string_to_parser};
1532     use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1533     use visit;
1534     use visit::Visitor;
1535
1536     // a visitor that extracts the paths
1537     // from a given thingy and puts them in a mutable
1538     // array (passed in to the traversal)
1539     #[derive(Clone)]
1540     struct PathExprFinderContext {
1541         path_accumulator: Vec<ast::Path> ,
1542     }
1543
1544     impl<'v> Visitor<'v> for PathExprFinderContext {
1545         fn visit_expr(&mut self, expr: &ast::Expr) {
1546             match expr.node {
1547                 ast::ExprPath(ref p) => {
1548                     self.path_accumulator.push(p.clone());
1549                     // not calling visit_path, but it should be fine.
1550                 }
1551                 _ => visit::walk_expr(self, expr)
1552             }
1553         }
1554     }
1555
1556     // find the variable references in a crate
1557     fn crate_varrefs(the_crate : &ast::Crate) -> Vec<ast::Path> {
1558         let mut path_finder = PathExprFinderContext{path_accumulator:Vec::new()};
1559         visit::walk_crate(&mut path_finder, the_crate);
1560         path_finder.path_accumulator
1561     }
1562
1563     /// A Visitor that extracts the identifiers from a thingy.
1564     // as a side note, I'm starting to want to abstract over these....
1565     struct IdentFinder {
1566         ident_accumulator: Vec<ast::Ident>
1567     }
1568
1569     impl<'v> Visitor<'v> for IdentFinder {
1570         fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1571             self.ident_accumulator.push(id);
1572         }
1573     }
1574
1575     /// Find the idents in a crate
1576     fn crate_idents(the_crate: &ast::Crate) -> Vec<ast::Ident> {
1577         let mut ident_finder = IdentFinder{ident_accumulator: Vec::new()};
1578         visit::walk_crate(&mut ident_finder, the_crate);
1579         ident_finder.ident_accumulator
1580     }
1581
1582     // these following tests are quite fragile, in that they don't test what
1583     // *kind* of failure occurs.
1584
1585     fn test_ecfg() -> ExpansionConfig {
1586         ExpansionConfig::default("test".to_string())
1587     }
1588
1589     // make sure that macros can't escape fns
1590     #[should_fail]
1591     #[test] fn macros_cant_escape_fns_test () {
1592         let src = "fn bogus() {macro_rules! z (() => (3+4));}\
1593                    fn inty() -> i32 { z!() }".to_string();
1594         let sess = parse::new_parse_sess();
1595         let crate_ast = parse::parse_crate_from_source_str(
1596             "<test>".to_string(),
1597             src,
1598             Vec::new(), &sess);
1599         // should fail:
1600         expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
1601     }
1602
1603     // make sure that macros can't escape modules
1604     #[should_fail]
1605     #[test] fn macros_cant_escape_mods_test () {
1606         let src = "mod foo {macro_rules! z (() => (3+4));}\
1607                    fn inty() -> i32 { z!() }".to_string();
1608         let sess = parse::new_parse_sess();
1609         let crate_ast = parse::parse_crate_from_source_str(
1610             "<test>".to_string(),
1611             src,
1612             Vec::new(), &sess);
1613         expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
1614     }
1615
1616     // macro_use modules should allow macros to escape
1617     #[test] fn macros_can_escape_flattened_mods_test () {
1618         let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1619                    fn inty() -> i32 { z!() }".to_string();
1620         let sess = parse::new_parse_sess();
1621         let crate_ast = parse::parse_crate_from_source_str(
1622             "<test>".to_string(),
1623             src,
1624             Vec::new(), &sess);
1625         expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast);
1626     }
1627
1628     fn expand_crate_str(crate_str: String) -> ast::Crate {
1629         let ps = parse::new_parse_sess();
1630         let crate_ast = string_to_parser(&ps, crate_str).parse_crate_mod();
1631         // the cfg argument actually does matter, here...
1632         expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast)
1633     }
1634
1635     // find the pat_ident paths in a crate
1636     fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1637         let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1638         visit::walk_crate(&mut name_finder, the_crate);
1639         name_finder.ident_accumulator
1640     }
1641
1642     #[test] fn macro_tokens_should_match(){
1643         expand_crate_str(
1644             "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1645     }
1646
1647     // should be able to use a bound identifier as a literal in a macro definition:
1648     #[test] fn self_macro_parsing(){
1649         expand_crate_str(
1650             "macro_rules! foo ((zz) => (287;));
1651             fn f(zz: i32) {foo!(zz);}".to_string()
1652             );
1653     }
1654
1655     // renaming tests expand a crate and then check that the bindings match
1656     // the right varrefs. The specification of the test case includes the
1657     // text of the crate, and also an array of arrays.  Each element in the
1658     // outer array corresponds to a binding in the traversal of the AST
1659     // induced by visit.  Each of these arrays contains a list of indexes,
1660     // interpreted as the varrefs in the varref traversal that this binding
1661     // should match.  So, for instance, in a program with two bindings and
1662     // three varrefs, the array ~[~[1,2],~[0]] would indicate that the first
1663     // binding should match the second two varrefs, and the second binding
1664     // should match the first varref.
1665     //
1666     // Put differently; this is a sparse representation of a boolean matrix
1667     // indicating which bindings capture which identifiers.
1668     //
1669     // Note also that this matrix is dependent on the implicit ordering of
1670     // the bindings and the varrefs discovered by the name-finder and the path-finder.
1671     //
1672     // The comparisons are done post-mtwt-resolve, so we're comparing renamed
1673     // names; differences in marks don't matter any more.
1674     //
1675     // oog... I also want tests that check "bound-identifier-=?". That is,
1676     // not just "do these have the same name", but "do they have the same
1677     // name *and* the same marks"? Understanding this is really pretty painful.
1678     // in principle, you might want to control this boolean on a per-varref basis,
1679     // but that would make things even harder to understand, and might not be
1680     // necessary for thorough testing.
1681     type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1682
1683     #[test]
1684     fn automatic_renaming () {
1685         let tests: Vec<RenamingTest> =
1686             vec!(// b & c should get new names throughout, in the expr too:
1687                 ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1688                  vec!(vec!(0,1),vec!(2)), false),
1689                 // both x's should be renamed (how is this causing a bug?)
1690                 ("fn main () {let x: i32 = 13;x;}",
1691                  vec!(vec!(0)), false),
1692                 // the use of b after the + should be renamed, the other one not:
1693                 ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1694                  vec!(vec!(1)), false),
1695                 // the b before the plus should not be renamed (requires marks)
1696                 ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1697                  vec!(vec!(1)), false),
1698                 // the marks going in and out of letty should cancel, allowing that $x to
1699                 // capture the one following the semicolon.
1700                 // this was an awesome test case, and caught a *lot* of bugs.
1701                 ("macro_rules! letty(($x:ident) => (let $x = 15;));
1702                   macro_rules! user(($x:ident) => ({letty!($x); $x}));
1703                   fn main() -> i32 {user!(z)}",
1704                  vec!(vec!(0)), false)
1705                 );
1706         for (idx,s) in tests.iter().enumerate() {
1707             run_renaming_test(s,idx);
1708         }
1709     }
1710
1711     // no longer a fixme #8062: this test exposes a *potential* bug; our system does
1712     // not behave exactly like MTWT, but a conversation with Matthew Flatt
1713     // suggests that this can only occur in the presence of local-expand, which
1714     // we have no plans to support. ... unless it's needed for item hygiene....
1715     #[ignore]
1716     #[test] fn issue_8062(){
1717         run_renaming_test(
1718             &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}",
1719               vec!(vec!(0)), true), 0)
1720     }
1721
1722     // FIXME #6994:
1723     // the z flows into and out of two macros (g & f) along one path, and one
1724     // (just g) along the other, so the result of the whole thing should
1725     // be "let z_123 = 3; z_123"
1726     #[ignore]
1727     #[test] fn issue_6994(){
1728         run_renaming_test(
1729             &("macro_rules! g (($x:ident) =>
1730               ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1731               fn a(){g!(z)}",
1732               vec!(vec!(0)),false),
1733             0)
1734     }
1735
1736     // match variable hygiene. Should expand into
1737     // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
1738     #[test] fn issue_9384(){
1739         run_renaming_test(
1740             &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1741               fn z() {match 8 {x => bad_macro!(x)}}",
1742               // NB: the third "binding" is the repeat of the second one.
1743               vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
1744               true),
1745             0)
1746     }
1747
1748     // interpolated nodes weren't getting labeled.
1749     // should expand into
1750     // fn main(){let g1_1 = 13; g1_1}}
1751     #[test] fn pat_expand_issue_15221(){
1752         run_renaming_test(
1753             &("macro_rules! inner ( ($e:pat ) => ($e));
1754               macro_rules! outer ( ($e:pat ) => (inner!($e)));
1755               fn main() { let outer!(g) = 13; g;}",
1756               vec!(vec!(0)),
1757               true),
1758             0)
1759     }
1760
1761     // create a really evil test case where a $x appears inside a binding of $x
1762     // but *shouldn't* bind because it was inserted by a different macro....
1763     // can't write this test case until we have macro-generating macros.
1764
1765     // method arg hygiene
1766     // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
1767     #[test] fn method_arg_hygiene(){
1768         run_renaming_test(
1769             &("macro_rules! inject_x (()=>(x));
1770               macro_rules! inject_self (()=>(self));
1771               struct A;
1772               impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
1773               vec!(vec!(0),vec!(3)),
1774               true),
1775             0)
1776     }
1777
1778     // ooh, got another bite?
1779     // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
1780     #[test] fn method_arg_hygiene_2(){
1781         run_renaming_test(
1782             &("struct A;
1783               macro_rules! add_method (($T:ty) =>
1784               (impl $T {  fn thingy(&self) {self;} }));
1785               add_method!(A);",
1786               vec!(vec!(0)),
1787               true),
1788             0)
1789     }
1790
1791     // item fn hygiene
1792     // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
1793     #[test] fn issue_9383(){
1794         run_renaming_test(
1795             &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
1796               fn q(x: i32) { bad_macro!(x); }",
1797               vec!(vec!(1),vec!(0)),true),
1798             0)
1799     }
1800
1801     // closure arg hygiene (ExprClosure)
1802     // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
1803     #[test] fn closure_arg_hygiene(){
1804         run_renaming_test(
1805             &("macro_rules! inject_x (()=>(x));
1806             fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
1807               vec!(vec!(1)),
1808               true),
1809             0)
1810     }
1811
1812     // macro_rules in method position. Sadly, unimplemented.
1813     #[test] fn macro_in_method_posn(){
1814         expand_crate_str(
1815             "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
1816             struct A;
1817             impl A{ my_method!(); }
1818             fn f(){A.thirteen;}".to_string());
1819     }
1820
1821     // another nested macro
1822     // expands to impl Entries {fn size_hint(&self_1) {self_1;}
1823     #[test] fn item_macro_workaround(){
1824         run_renaming_test(
1825             &("macro_rules! item { ($i:item) => {$i}}
1826               struct Entries;
1827               macro_rules! iterator_impl {
1828               () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
1829               iterator_impl! { }",
1830               vec!(vec!(0)), true),
1831             0)
1832     }
1833
1834     // run one of the renaming tests
1835     fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
1836         let invalid_name = token::special_idents::invalid.name;
1837         let (teststr, bound_connections, bound_ident_check) = match *t {
1838             (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
1839         };
1840         let cr = expand_crate_str(teststr.to_string());
1841         let bindings = crate_bindings(&cr);
1842         let varrefs = crate_varrefs(&cr);
1843
1844         // must be one check clause for each binding:
1845         assert_eq!(bindings.len(),bound_connections.len());
1846         for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
1847             let binding_name = mtwt::resolve(bindings[binding_idx]);
1848             let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
1849             // shouldmatch can't name varrefs that don't exist:
1850             assert!((shouldmatch.len() == 0) ||
1851                     (varrefs.len() > *shouldmatch.iter().max().unwrap()));
1852             for (idx,varref) in varrefs.iter().enumerate() {
1853                 let print_hygiene_debug_info = || {
1854                     // good lord, you can't make a path with 0 segments, can you?
1855                     let final_varref_ident = match varref.segments.last() {
1856                         Some(pathsegment) => pathsegment.identifier,
1857                         None => panic!("varref with 0 path segments?")
1858                     };
1859                     let varref_name = mtwt::resolve(final_varref_ident);
1860                     let varref_idents : Vec<ast::Ident>
1861                         = varref.segments.iter().map(|s| s.identifier)
1862                         .collect();
1863                     println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
1864                     let string = token::get_ident(final_varref_ident);
1865                     println!("varref's first segment's string: \"{}\"", string.get());
1866                     println!("binding #{}: {}, resolves to {}",
1867                              binding_idx, bindings[binding_idx], binding_name);
1868                     mtwt::with_sctable(|x| mtwt::display_sctable(x));
1869                 };
1870                 if shouldmatch.contains(&idx) {
1871                     // it should be a path of length 1, and it should
1872                     // be free-identifier=? or bound-identifier=? to the given binding
1873                     assert_eq!(varref.segments.len(),1);
1874                     let varref_name = mtwt::resolve(varref.segments[0].identifier);
1875                     let varref_marks = mtwt::marksof(varref.segments[0]
1876                                                            .identifier
1877                                                            .ctxt,
1878                                                      invalid_name);
1879                     if !(varref_name==binding_name) {
1880                         println!("uh oh, should match but doesn't:");
1881                         print_hygiene_debug_info();
1882                     }
1883                     assert_eq!(varref_name,binding_name);
1884                     if bound_ident_check {
1885                         // we're checking bound-identifier=?, and the marks
1886                         // should be the same, too:
1887                         assert_eq!(varref_marks,binding_marks.clone());
1888                     }
1889                 } else {
1890                     let varref_name = mtwt::resolve(varref.segments[0].identifier);
1891                     let fail = (varref.segments.len() == 1)
1892                         && (varref_name == binding_name);
1893                     // temp debugging:
1894                     if fail {
1895                         println!("failure on test {}",test_idx);
1896                         println!("text of test case: \"{}\"", teststr);
1897                         println!("");
1898                         println!("uh oh, matches but shouldn't:");
1899                         print_hygiene_debug_info();
1900                     }
1901                     assert!(!fail);
1902                 }
1903             }
1904         }
1905     }
1906
1907     #[test] fn fmt_in_macro_used_inside_module_macro() {
1908         let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
1909 macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
1910 foo_module!();
1911 ".to_string();
1912         let cr = expand_crate_str(crate_str);
1913         // find the xx binding
1914         let bindings = crate_bindings(&cr);
1915         let cxbinds: Vec<&ast::Ident> =
1916             bindings.iter().filter(|b| {
1917                 let ident = token::get_ident(**b);
1918                 let string = ident.get();
1919                 "xx" == string
1920             }).collect();
1921         let cxbinds: &[&ast::Ident] = &cxbinds[];
1922         let cxbind = match cxbinds {
1923             [b] => b,
1924             _ => panic!("expected just one binding for ext_cx")
1925         };
1926         let resolved_binding = mtwt::resolve(*cxbind);
1927         let varrefs = crate_varrefs(&cr);
1928
1929         // the xx binding should bind all of the xx varrefs:
1930         for (idx,v) in varrefs.iter().filter(|p| {
1931             p.segments.len() == 1
1932             && "xx" == token::get_ident(p.segments[0].identifier).get()
1933         }).enumerate() {
1934             if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
1935                 println!("uh oh, xx binding didn't match xx varref:");
1936                 println!("this is xx varref \\# {}", idx);
1937                 println!("binding: {}", cxbind);
1938                 println!("resolves to: {}", resolved_binding);
1939                 println!("varref: {}", v.segments[0].identifier);
1940                 println!("resolves to: {}",
1941                          mtwt::resolve(v.segments[0].identifier));
1942                 mtwt::with_sctable(|x| mtwt::display_sctable(x));
1943             }
1944             assert_eq!(mtwt::resolve(v.segments[0].identifier),
1945                        resolved_binding);
1946         };
1947     }
1948
1949     #[test]
1950     fn pat_idents(){
1951         let pat = string_to_pat(
1952             "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
1953         let idents = pattern_bindings(&*pat);
1954         assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
1955     }
1956
1957     // test the list of identifier patterns gathered by the visitor. Note that
1958     // 'None' is listed as an identifier pattern because we don't yet know that
1959     // it's the name of a 0-ary variant, and that 'i' appears twice in succession.
1960     #[test]
1961     fn crate_bindings_test(){
1962         let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
1963         match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
1964         let idents = crate_bindings(&the_crate);
1965         assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
1966     }
1967
1968     // test the IdentRenamer directly
1969     #[test]
1970     fn ident_renamer_test () {
1971         let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1972         let f_ident = token::str_to_ident("f");
1973         let x_ident = token::str_to_ident("x");
1974         let int_ident = token::str_to_ident("i32");
1975         let renames = vec!((x_ident,Name(16)));
1976         let mut renamer = IdentRenamer{renames: &renames};
1977         let renamed_crate = renamer.fold_crate(the_crate);
1978         let idents = crate_idents(&renamed_crate);
1979         let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
1980         assert_eq!(resolved,vec!(f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)));
1981     }
1982
1983     // test the PatIdentRenamer; only PatIdents get renamed
1984     #[test]
1985     fn pat_ident_renamer_test () {
1986         let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1987         let f_ident = token::str_to_ident("f");
1988         let x_ident = token::str_to_ident("x");
1989         let int_ident = token::str_to_ident("i32");
1990         let renames = vec!((x_ident,Name(16)));
1991         let mut renamer = PatIdentRenamer{renames: &renames};
1992         let renamed_crate = renamer.fold_crate(the_crate);
1993         let idents = crate_idents(&renamed_crate);
1994         let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
1995         let x_name = x_ident.name;
1996         assert_eq!(resolved,vec!(f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name));
1997     }
1998
1999
2000 }