expand.rs 88.1 KB
Newer Older
S
Steven Fackler 已提交
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
12
use ast::{Local, Ident, MacInvocTT};
13 14
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
use ast::{StmtExpr, StmtSemi};
15
use ast::TokenTree;
16
use ast;
17
use ext::mtwt;
18
use ext::build::AstBuilder;
19
use attr;
20
use attr::AttrMetaMethods;
21
use codemap;
22
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, CompilerExpansion};
P
Patrick Walton 已提交
23
use ext::base::*;
24
use feature_gate::{self, Features};
J
John Clements 已提交
25
use fold;
26
use fold::*;
27
use parse;
28
use parse::token::{fresh_mark, fresh_name, intern};
29
use parse::token;
30 31
use ptr::P;
use util::small_vector::SmallVector;
J
John Clements 已提交
32
use visit;
H
Huon Wilson 已提交
33
use visit::Visitor;
34
use std_inject;
35

36 37 38 39 40 41 42 43 44 45
// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
fn mk_core_path(fld: &mut MacroExpander,
                span: Span,
                suffix: &[&'static str]) -> ast::Path {
    let mut idents = vec![fld.cx.ident_of_std("core")];
    for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); }
    fld.cx.path_global(span, idents)
}

46
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
47 48 49 50 51 52
    fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) {
        fld.cx.bt_push(ExpnInfo {
            call_site: span,
            callee: NameAndSpan {
                name: expansion_desc.to_string(),
                format: CompilerExpansion,
53 54 55 56 57

                // This does *not* mean code generated after
                // `push_compiler_expansion` is automatically exempt
                // from stability lints; must also tag such code with
                // an appropriate span from `fld.cx.backtrace()`.
58
                allow_internal_unstable: true,
59

60 61 62 63 64
                span: None,
            },
        });
    }

65 66 67 68 69
    // Sets the expn_id so that we can use unstable methods.
    fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span {
        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 {
72

73 74
        // expr_mac should really be expr_ext or something; it's the
        // entry-point for all syntax extensions.
75
        ast::ExprMac(mac) => {
76 77 78
            let expanded_expr = match expand_mac_invoc(mac, span,
                                                       |r| r.make_expr(),
                                                       mark_expr, fld) {
J
John Clements 已提交
79 80
                Some(expr) => expr,
                None => {
81
                    return DummyResult::raw_expr(span);
J
John Clements 已提交
82 83
                }
            };
84

J
John Clements 已提交
85
            // Keep going, outside-in.
86
            let fully_expanded = fld.fold_expr(expanded_expr);
N
Nick Cameron 已提交
87
            let span = fld.new_span(span);
J
John Clements 已提交
88
            fld.cx.bt_pop();
89

90
            fully_expanded.map(|e| ast::Expr {
J
John Clements 已提交
91
                id: ast::DUMMY_NODE_ID,
92
                node: e.node,
93
                span: span,
94
            })
95
        }
96

97 98 99 100 101 102
        // Desugar ExprBox: `in (PLACE) EXPR`
        ast::ExprBox(Some(placer), value_expr) => {
            // to:
            //
            // let p = PLACE;
            // let mut place = Placer::make_place(p);
103 104 105
            // let raw_place = Place::pointer(&mut place);
            // push_unsafe!({
            //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
106
            //     InPlace::finalize(place)
107
            // })
108

109 110 111 112 113 114
            // Ensure feature-gate is enabled
            feature_gate::check_for_placement_in(
                fld.cx.ecfg.features,
                &fld.cx.parse_sess.span_diagnostic,
                expr_span);

115 116
            push_compiler_expansion(fld, expr_span, "placement-in expansion");

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
            let value_span = value_expr.span;
            let placer_span = placer.span;

            let placer_expr = fld.fold_expr(placer);
            let value_expr = fld.fold_expr(value_expr);

            let placer_ident = token::gensym_ident("placer");
            let agent_ident = token::gensym_ident("place");
            let p_ptr_ident = token::gensym_ident("p_ptr");

            let placer = fld.cx.expr_ident(span, placer_ident);
            let agent = fld.cx.expr_ident(span, agent_ident);
            let p_ptr = fld.cx.expr_ident(span, p_ptr_ident);

            let make_place = ["ops", "Placer", "make_place"];
            let place_pointer = ["ops", "Place", "pointer"];
133
            let move_val_init = ["intrinsics", "move_val_init"];
134 135 136
            let inplace_finalize = ["ops", "InPlace", "finalize"];

            let make_call = |fld: &mut MacroExpander, p, args| {
137 138 139 140 141
                // We feed in the `expr_span` because codemap's span_allows_unstable
                // allows the call_site span to inherit the `allow_internal_unstable`
                // setting.
                let span_unstable = allow_unstable(fld, expr_span);
                let path = mk_core_path(fld, span_unstable, p);
142
                let path = fld.cx.expr_path(path);
143 144
                let expr_span_unstable = allow_unstable(fld, span);
                fld.cx.expr_call(expr_span_unstable, path, args)
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
            };

            let stmt_let = |fld: &mut MacroExpander, bind, expr| {
                fld.cx.stmt_let(placer_span, false, bind, expr)
            };
            let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| {
                fld.cx.stmt_let(placer_span, true, bind, expr)
            };

            // let placer = <placer_expr> ;
            let s1 = stmt_let(fld, placer_ident, placer_expr);

            // let mut place = Placer::make_place(placer);
            let s2 = {
                let call = make_call(fld, &make_place, vec![placer]);
                stmt_let_mut(fld, agent_ident, call)
            };

            // let p_ptr = Place::pointer(&mut place);
            let s3 = {
                let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())];
                let call = make_call(fld, &place_pointer, args);
                stmt_let(fld, p_ptr_ident, call)
            };

170 171
            // pop_unsafe!(EXPR));
            let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span);
172

173 174 175 176
            // push_unsafe!({
            //     ptr::write(p_ptr, pop_unsafe!(<value_expr>));
            //     InPlace::finalize(place)
            // })
177
            let expr = {
178 179 180
                let call_move_val_init = StmtSemi(make_call(
                    fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID);
                let call_move_val_init = codemap::respan(value_span, call_move_val_init);
181 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))
184 185
            };

186
            let block = fld.cx.block_all(span, vec![s1, s2, s3], expr);
187 188 189
            let result = fld.cx.expr_block(block);
            fld.cx.bt_pop();
            result
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
        }

        // Issue #22181:
        // Eventually a desugaring for `box EXPR`
        // (similar to the desugaring above for `in PLACE BLOCK`)
        // should go here, desugaring
        //
        // to:
        //
        // let mut place = BoxPlace::make_place();
        // let raw_place = Place::pointer(&mut place);
        // let value = $value;
        // unsafe {
        //     ::std::ptr::write(raw_place, value);
        //     Boxed::finalize(place)
        // }
        //
        // But for now there are type-inference issues doing that.

P
Pythoner6 已提交
209 210 211
        ast::ExprWhile(cond, body, opt_ident) => {
            let cond = fld.fold_expr(cond);
            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
212
            fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
P
Pythoner6 已提交
213 214
        }

J
John Gallagher 已提交
215 216 217 218 219 220 221 222 223 224 225 226
        // Desugar ExprWhileLet
        // From: `[opt_ident]: while let <pat> = <expr> <body>`
        ast::ExprWhileLet(pat, expr, body, opt_ident) => {
            // to:
            //
            //   [opt_ident]: loop {
            //     match <expr> {
            //       <pat> => <body>,
            //       _ => break
            //     }
            //   }

227 228
            push_compiler_expansion(fld, span, "while let expansion");

J
John Gallagher 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
            // `<pat> => <body>`
            let pat_arm = {
                let body_expr = fld.cx.expr_block(body);
                fld.cx.arm(pat.span, vec![pat], body_expr)
            };

            // `_ => break`
            let break_arm = {
                let pat_under = fld.cx.pat_wild(span);
                let break_expr = fld.cx.expr_break(span);
                fld.cx.arm(span, vec![pat_under], break_expr)
            };

            // `match <expr> { ... }`
            let arms = vec![pat_arm, break_arm];
            let match_expr = fld.cx.expr(span,
245
                                    ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
J
John Gallagher 已提交
246 247 248 249

            // `[opt_ident]: loop { ... }`
            let loop_block = fld.cx.block_expr(match_expr);
            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
250 251 252
            let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
            fld.cx.bt_pop();
            result
J
John Gallagher 已提交
253 254
        }

255 256 257 258 259 260 261 262 263 264 265
        // Desugar ExprIfLet
        // From: `if let <pat> = <expr> <body> [<elseopt>]`
        ast::ExprIfLet(pat, expr, body, mut elseopt) => {
            // to:
            //
            //   match <expr> {
            //     <pat> => <body>,
            //     [_ if <elseopt_if_cond> => <elseopt_if_body>,]
            //     _ => [<elseopt> | ()]
            //   }

266 267
            push_compiler_expansion(fld, span, "if let expansion");

268 269 270 271 272 273 274 275 276 277
            // `<pat> => <body>`
            let pat_arm = {
                let body_expr = fld.cx.expr_block(body);
                fld.cx.arm(pat.span, vec![pat], body_expr)
            };

            // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
            let else_if_arms = {
                let mut arms = vec![];
                loop {
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
                    let elseopt_continue = elseopt
                        .and_then(|els| els.and_then(|els| match els.node {
                        // else if
                        ast::ExprIf(cond, then, elseopt) => {
                            let pat_under = fld.cx.pat_wild(span);
                            arms.push(ast::Arm {
                                attrs: vec![],
                                pats: vec![pat_under],
                                guard: Some(cond),
                                body: fld.cx.expr_block(then)
                            });
                            elseopt.map(|elseopt| (elseopt, true))
                        }
                        _ => Some((P(els), false))
                    }));
                    match elseopt_continue {
                        Some((e, true)) => {
                            elseopt = Some(e);
                        }
                        Some((e, false)) => {
                            elseopt = Some(e);
                            break;
                        }
                        None => {
                            elseopt = None;
                            break;
                        }
305 306 307 308 309
                    }
                }
                arms
            };

310 311
            let contains_else_clause = elseopt.is_some();

312 313 314
            // `_ => [<elseopt> | ()]`
            let else_arm = {
                let pat_under = fld.cx.pat_wild(span);
315
                let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![]));
316 317 318 319 320
                fld.cx.arm(span, vec![pat_under], else_expr)
            };

            let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
            arms.push(pat_arm);
321
            arms.extend(else_if_arms);
322 323
            arms.push(else_arm);

324 325 326 327 328
            let match_expr = fld.cx.expr(span,
                                         ast::ExprMatch(expr, arms,
                                                ast::MatchSource::IfLetDesugar {
                                                    contains_else_clause: contains_else_clause,
                                                }));
329 330 331
            let result = fld.fold_expr(match_expr);
            fld.cx.bt_pop();
            result
332 333 334
        }

        // Desugar support for ExprIfLet in the ExprIf else position
K
Kevin Ballard 已提交
335
        ast::ExprIf(cond, blk, elseopt) => {
336
            let elseopt = elseopt.map(|els| els.and_then(|els| match els.node {
K
Kevin Ballard 已提交
337
                ast::ExprIfLet(..) => {
338
                    push_compiler_expansion(fld, span, "if let expansion");
K
Kevin Ballard 已提交
339
                    // wrap the if-let expr in a block
340
                    let span = els.span;
K
Kevin Ballard 已提交
341 342
                    let blk = P(ast::Block {
                        stmts: vec![],
343
                        expr: Some(P(els)),
K
Kevin Ballard 已提交
344 345
                        id: ast::DUMMY_NODE_ID,
                        rules: ast::DefaultBlock,
346
                        span: span
K
Kevin Ballard 已提交
347
                    });
348 349 350
                    let result = fld.cx.expr_block(blk);
                    fld.cx.bt_pop();
                    result
K
Kevin Ballard 已提交
351
                }
352 353 354 355
                _ => P(els)
            }));
            let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt));
            if_expr.map(|e| noop_fold_expr(e, fld))
356 357
        }

E
Edward Wang 已提交
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))
E
Edward Wang 已提交
361 362
        }

J
Jorge Aparicio 已提交
363 364
        // Desugar ExprForLoop
        // From: `[opt_ident]: for <pat> in <head> <body>`
365
        ast::ExprForLoop(pat, head, body, opt_ident) => {
J
Jorge Aparicio 已提交
366 367
            // to:
            //
368 369 370 371 372 373 374 375
            //   {
            //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
            //       mut iter => {
            //         [opt_ident]: loop {
            //           match ::std::iter::Iterator::next(&mut iter) {
            //             ::std::option::Option::Some(<pat>) => <body>,
            //             ::std::option::Option::None => break
            //           }
J
Jorge Aparicio 已提交
376 377
            //         }
            //       }
378 379
            //     };
            //     result
J
Jorge Aparicio 已提交
380 381
            //   }

382 383 384 385
            push_compiler_expansion(fld, span, "for loop expansion");

            let span = fld.new_span(span);

J
Jorge Aparicio 已提交
386
            // expand <head>
387
            let head = fld.fold_expr(head);
J
Jorge Aparicio 已提交
388 389 390 391 392 393 394 395 396 397 398 399

            // create an hygienic ident
            let iter = {
                let ident = fld.cx.ident_of("iter");
                let new_ident = fresh_name(&ident);
                let rename = (ident, new_ident);
                let mut rename_list = vec![rename];
                let mut rename_fld = IdentRenamer{ renames: &mut rename_list };

                rename_fld.fold_ident(ident)
            };

400 401
            let pat_span = fld.new_span(pat.span);
            // `::std::option::Option::Some(<pat>) => <body>`
J
Jorge Aparicio 已提交
402 403
            let pat_arm = {
                let body_expr = fld.cx.expr_block(body);
404
                let pat = noop_fold_pat(pat, fld);
J
Jorge Aparicio 已提交
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
                let some_pat = fld.cx.pat_some(pat_span, pat);

                fld.cx.arm(pat_span, vec![some_pat], body_expr)
            };

            // `::std::option::Option::None => break`
            let break_arm = {
                let break_expr = fld.cx.expr_break(span);

                fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr)
            };

            // `match ::std::iter::Iterator::next(&mut iter) { ... }`
            let match_expr = {
                let next_path = {
                    let strs = vec![
421
                        fld.cx.ident_of_std("core"),
J
Jorge Aparicio 已提交
422 423 424 425 426 427 428 429 430 431 432 433
                        fld.cx.ident_of("iter"),
                        fld.cx.ident_of("Iterator"),
                        fld.cx.ident_of("next"),
                    ];

                    fld.cx.path_global(span, strs)
                };
                let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter));
                let next_expr =
                    fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]);
                let arms = vec![pat_arm, break_arm];

434 435
                fld.cx.expr(pat_span,
                            ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar))
J
Jorge Aparicio 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
            };

            // `[opt_ident]: loop { ... }`
            let loop_block = fld.cx.block_expr(match_expr);
            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
            let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));

            // `mut iter => { ... }`
            let iter_arm = {
                let iter_pat =
                    fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable));
                fld.cx.arm(span, vec![iter_pat], loop_expr)
            };

            // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
            let into_iter_expr = {
                let into_iter_path = {
                    let strs = vec![
454
                        fld.cx.ident_of_std("core"),
J
Jorge Aparicio 已提交
455 456 457 458 459 460 461 462 463 464
                        fld.cx.ident_of("iter"),
                        fld.cx.ident_of("IntoIterator"),
                        fld.cx.ident_of("into_iter"),
                    ];

                    fld.cx.path_global(span, strs)
                };

                fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
            };
465 466 467 468 469

            let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]);

            // `{ let result = ...; result }`
            let result_ident = token::gensym_ident("result");
470
            let result = fld.cx.expr_block(
471 472 473
                fld.cx.block_all(
                    span,
                    vec![fld.cx.stmt_let(span, false, result_ident, match_expr)],
474 475 476
                    Some(fld.cx.expr_ident(span, result_ident))));
            fld.cx.bt_pop();
            result
477 478
        }

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,
484 485
                                            rewritten_fn_decl,
                                            rewritten_block);
486 487 488
            let result = P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)});
            fld.cx.bt_pop();
            result
489 490
        }

491 492 493 494 495 496 497
        _ => {
            P(noop_fold_expr(ast::Expr {
                id: id,
                node: node,
                span: span
            }, fld))
        }
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
    });

    fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec<P<ast::Stmt>>,
                        expr: P<ast::Expr>, span: Span)
                        -> P<ast::Expr> {
        let rules = ast::PushUnsafeBlock(ast::CompilerGenerated);
        cx.expr_block(P(ast::Block {
            rules: rules, span: span, id: ast::DUMMY_NODE_ID,
            stmts: stmts, expr: Some(expr),
        }))
    }

    fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P<ast::Expr>, span: Span)
                       -> P<ast::Expr> {
        let rules = ast::PopUnsafeBlock(ast::CompilerGenerated);
        cx.expr_block(P(ast::Block {
            rules: rules, span: span, id: ast::DUMMY_NODE_ID,
            stmts: vec![], expr: Some(expr),
        }))
    }
518 519
}

J
John Clements 已提交
520 521 522 523
/// Expand a (not-ident-style) macro invocation. Returns the result
/// of expansion and the mark which must be applied to the result.
/// Our current interface doesn't allow us to apply the mark to the
/// result until after calling make_expr, make_items, etc.
524 525
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                             span: codemap::Span,
J
Jorge Aparicio 已提交
526 527 528 529
                             parse_thunk: F,
                             mark_thunk: G,
                             fld: &mut MacroExpander)
                             -> Option<T> where
530
    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
J
Jorge Aparicio 已提交
531
    G: FnOnce(T, Mrk) -> T,
532
{
533
    match mac.node {
J
John Clements 已提交
534 535 536 537 538 539
        // it would almost certainly be cleaner to pass the whole
        // macro invocation in, rather than pulling it apart and
        // marking the tts and the ctxt separately. This also goes
        // for the other three macro invocation chunks of code
        // in this file.
        // Token-tree macros:
540
        MacInvocTT(pth, tts, _) => {
541
            if pth.segments.len() > 1 {
J
John Clements 已提交
542 543 544 545 546 547
                fld.cx.span_err(pth.span,
                                "expected macro name without module \
                                separators");
                // let compilation continue
                return None;
            }
548 549
            let extname = pth.segments[0].identifier.name;
            match fld.cx.syntax_env.find(&extname) {
J
John Clements 已提交
550 551 552
                None => {
                    fld.cx.span_err(
                        pth.span,
J
Jorge Aparicio 已提交
553
                        &format!("macro undefined: '{}!'",
554
                                &extname));
J
John Clements 已提交
555 556 557 558

                    // let compilation continue
                    None
                }
559
                Some(rc) => match *rc {
560
                    NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
561
                        fld.cx.bt_push(ExpnInfo {
562
                                call_site: span,
563
                                callee: NameAndSpan {
564
                                    name: extname.to_string(),
565 566
                                    format: MacroBang,
                                    span: exp_span,
567
                                    allow_internal_unstable: allow_internal_unstable,
568 569 570
                                },
                            });
                        let fm = fresh_mark();
571
                        let marked_before = mark_tts(&tts[..], fm);
572 573 574 575 576

                        // The span that we pass to the expanders we want to
                        // be the root of the call stack. That's the most
                        // relevant span and it's the actual invocation of
                        // the macro.
577
                        let mac_span = fld.cx.original_span();
578

579 580
                        let opt_parsed = {
                            let expanded = expandfun.expand(fld.cx,
581
                                                            mac_span,
582
                                                            &marked_before[..]);
583 584 585
                            parse_thunk(expanded)
                        };
                        let parsed = match opt_parsed {
586 587 588 589
                            Some(e) => e,
                            None => {
                                fld.cx.span_err(
                                    pth.span,
J
Jorge Aparicio 已提交
590
                                    &format!("non-expression macro in expression position: {}",
591
                                            extname
592
                                            ));
593 594 595 596 597 598 599 600
                                return None;
                            }
                        };
                        Some(mark_thunk(parsed,fm))
                    }
                    _ => {
                        fld.cx.span_err(
                            pth.span,
J
Jorge Aparicio 已提交
601
                            &format!("'{}' is not a tt-style macro",
602
                                    extname));
603 604
                        None
                    }
J
John Clements 已提交
605 606 607 608 609 610
                }
            }
        }
    }
}

611 612 613 614 615
/// Rename loop label and expand its loop body
///
/// The renaming procedure for loop is different in the sense that the loop
/// body is in a block enclosed by loop head so the renaming of loop label
/// must be propagated to the enclosed context.
616 617 618
fn expand_loop_block(loop_block: P<Block>,
                     opt_ident: Option<Ident>,
                     fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
E
Edward Wang 已提交
619 620 621 622
    match opt_ident {
        Some(label) => {
            let new_label = fresh_name(&label);
            let rename = (label, new_label);
623 624 625 626 627 628

            // The rename *must not* be added to the pending list of current
            // syntax context otherwise an unrelated `break` or `continue` in
            // the same context will pick that up in the deferred renaming pass
            // and be renamed incorrectly.
            let mut rename_list = vec!(rename);
629
            let mut rename_fld = IdentRenamer{renames: &mut rename_list};
630 631 632 633 634
            let renamed_ident = rename_fld.fold_ident(label);

            // The rename *must* be added to the enclosed syntax context for
            // `break` or `continue` to pick up because by definition they are
            // in a block enclosed by loop head.
635 636
            fld.cx.syntax_env.push_frame();
            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();
639 640

            (expanded_block, Some(renamed_ident))
E
Edward Wang 已提交
641
        }
642
        None => (fld.fold_block(loop_block), opt_ident)
E
Edward Wang 已提交
643 644 645
    }
}

646 647
// eval $e with a new exts frame.
// 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) =>
S
Steven Fackler 已提交
650 651
    ({$extsboxexpr.push_frame();
      $extsboxexpr.info().macros_escape = $macros_escape;
J
John Clements 已提交
652
      let result = $e;
S
Steven Fackler 已提交
653
      $extsboxexpr.pop_frame();
J
John Clements 已提交
654 655
      result
     })
656
}
J
John Clements 已提交
657

658
// When we enter a module, record it, for the sake of `module!`
659 660
pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
                   -> SmallVector<P<ast::Item>> {
661 662
    let it = expand_item_modifiers(it, fld);

663 664
    expand_annotatable(Annotatable::Item(it), fld)
        .into_iter().map(|i| i.expect_item()).collect()
665 666
}

J
John Clements 已提交
667
/// Expand item_underscore
668 669
fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
    match item {
670
        ast::ItemFn(decl, unsafety, constness, abi, generics, body) => {
J
John Clements 已提交
671
            let (rewritten_fn_decl, rewritten_body)
672
                = expand_and_rename_fn_decl_and_block(decl, body, fld);
M
Marvin Löbel 已提交
673
            let expanded_generics = fold::noop_fold_generics(generics,fld);
674 675
            ast::ItemFn(rewritten_fn_decl, unsafety, constness, abi,
                        expanded_generics, rewritten_body)
J
John Clements 已提交
676
        }
677
        _ => noop_fold_item_underscore(item, fld)
J
John Clements 已提交
678 679 680
    }
}

681 682
// does this attribute list contain "macro_use" ?
fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
683
    for attr in attrs {
684 685 686 687 688
        let mut is_use = attr.check_name("macro_use");
        if attr.check_name("macro_escape") {
            fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
            is_use = true;
            if let ast::AttrInner = attr.node.style {
689
                fld.cx.fileline_help(attr.span, "consider an outer attribute, \
690 691 692 693 694 695 696 697 698 699 700 701 702
                                             #[macro_use] mod ...");
            }
        };

        if is_use {
            match attr.node.value.node {
                ast::MetaWord(..) => (),
                _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"),
            }
            return true;
        }
    }
    false
J
John Clements 已提交
703 704
}

705 706
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
707 708
pub fn expand_item_mac(it: P<ast::Item>,
                       fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
709
    let (extname, path_span, tts) = match it.node {
710
        ItemMac(codemap::Spanned {
S
Steven Fackler 已提交
711
            node: MacInvocTT(ref pth, ref tts, _),
A
Alex Crichton 已提交
712
            ..
713
        }) => {
714
            (pth.segments[0].identifier.name, pth.span, (*tts).clone())
715
        }
716
        _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
717
    };
718

719
    let fm = fresh_mark();
720
    let items = {
721
        let expanded = match fld.cx.syntax_env.find(&extname) {
722
            None => {
723
                fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
724
                                &format!("macro undefined: '{}!'",
725
                                        extname));
726 727 728
                // let compilation continue
                return SmallVector::zero();
            }
729

730
            Some(rc) => match *rc {
731
                NormalTT(ref expander, span, allow_internal_unstable) => {
732 733
                    if it.ident.name != parse::token::special_idents::invalid.name {
                        fld.cx
734
                            .span_err(path_span,
735
                                      &format!("macro {}! expects no ident argument, given '{}'",
736 737
                                               extname,
                                               it.ident));
738 739 740 741 742
                        return SmallVector::zero();
                    }
                    fld.cx.bt_push(ExpnInfo {
                        call_site: it.span,
                        callee: NameAndSpan {
743
                            name: extname.to_string(),
744
                            format: MacroBang,
745 746
                            span: span,
                            allow_internal_unstable: allow_internal_unstable,
747 748 749
                        }
                    });
                    // mark before expansion:
750 751
                    let marked_before = mark_tts(&tts[..], fm);
                    expander.expand(fld.cx, it.span, &marked_before[..])
752
                }
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,
J
Jorge Aparicio 已提交
756
                                        &format!("macro {}! expects an ident argument",
757
                                                extname));
758
                        return SmallVector::zero();
759
                    }
760 761 762
                    fld.cx.bt_push(ExpnInfo {
                        call_site: it.span,
                        callee: NameAndSpan {
763
                            name: extname.to_string(),
764
                            format: MacroBang,
765 766
                            span: span,
                            allow_internal_unstable: allow_internal_unstable,
767 768 769
                        }
                    });
                    // mark before expansion:
770
                    let marked_tts = mark_tts(&tts[..], fm);
771
                    expander.expand(fld.cx, it.span, it.ident, marked_tts)
772
                }
773
                MacroRulesTT => {
774
                    if it.ident.name == parse::token::special_idents::invalid.name {
775
                        fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
776
                                        &format!("macro_rules! expects an ident argument")
777
                                        );
778
                        return SmallVector::zero();
779
                    }
780

781 782 783
                    fld.cx.bt_push(ExpnInfo {
                        call_site: it.span,
                        callee: NameAndSpan {
784
                            name: extname.to_string(),
785
                            format: MacroBang,
786
                            span: None,
787 788 789 790
                            // `macro_rules!` doesn't directly allow
                            // unstable (this is orthogonal to whether
                            // the macro it creates allows it)
                            allow_internal_unstable: false,
791 792
                        }
                    });
793
                    // DON'T mark before expansion.
794

795 796 797 798 799 800 801 802 803 804 805 806 807 808
                    let allow_internal_unstable = attr::contains_name(&it.attrs,
                                                                      "allow_internal_unstable");

                    // ensure any #[allow_internal_unstable]s are
                    // detected (including nested macro definitions
                    // etc.)
                    if allow_internal_unstable && !fld.cx.ecfg.enable_allow_internal_unstable() {
                        feature_gate::emit_feature_err(
                            &fld.cx.parse_sess.span_diagnostic,
                            "allow_internal_unstable",
                            it.span,
                            feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
                    }

809 810 811 812 813 814
                    let def = ast::MacroDef {
                        ident: it.ident,
                        attrs: it.attrs.clone(),
                        id: ast::DUMMY_NODE_ID,
                        span: it.span,
                        imported_from: None,
815
                        export: attr::contains_name(&it.attrs, "macro_export"),
K
Keegan McAllister 已提交
816
                        use_locally: true,
817
                        allow_internal_unstable: allow_internal_unstable,
818 819
                        body: tts,
                    };
820
                    fld.cx.insert_macro(def);
821 822 823 824

                    // macro_rules! has a side effect but expands to nothing.
                    fld.cx.bt_pop();
                    return SmallVector::zero();
825 826 827
                }
                _ => {
                    fld.cx.span_err(it.span,
J
Jorge Aparicio 已提交
828
                                    &format!("{}! is not legal in item position",
829
                                            extname));
830
                    return SmallVector::zero();
831
                }
J
John Clements 已提交
832
            }
833 834
        };

835
        expanded.make_items()
836
    };
837

838 839
    let items = match items {
        Some(items) => {
A
Aaron Turon 已提交
840
            items.into_iter()
841
                .map(|i| mark_item(i, fm))
A
Aaron Turon 已提交
842
                .flat_map(|i| fld.fold_item(i).into_iter())
843 844
                .collect()
        }
845
        None => {
846
            fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
847
                            &format!("non-item macro in item position: {}",
848
                                    extname));
849
            return SmallVector::zero();
850
        }
851
    };
852

853
    fld.cx.bt_pop();
854
    items
855 856
}

J
John Clements 已提交
857
/// Expand a stmt
858 859 860
fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
    let stmt = stmt.and_then(|stmt| stmt);
    let (mac, style) = match stmt.node {
861
        StmtMac(mac, style) => (mac, style),
862
        _ => return expand_non_macro_stmt(stmt, fld)
863
    };
864 865 866 867 868 869 870

    let maybe_new_items =
        expand_mac_invoc(mac.and_then(|m| m), stmt.span,
                         |r| r.make_stmts(),
                         |stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
                         fld);

871
    let mut fully_expanded = match maybe_new_items {
872 873
        Some(stmts) => {
            // Keep going, outside-in.
874
            let new_items = stmts.into_iter().flat_map(|s| {
875
                fld.fold_stmt(s).into_iter()
876 877 878
            }).collect();
            fld.cx.bt_pop();
            new_items
879
        }
880
        None => SmallVector::zero()
881 882
    };

883 884
    // If this is a macro invocation with a semicolon, then apply that
    // semicolon to the final statement produced by expansion.
885
    if style == MacStmtWithSemicolon {
886 887 888 889 890 891 892 893 894 895 896
        if let Some(stmt) = fully_expanded.pop() {
            let new_stmt = stmt.map(|Spanned {node, span}| {
                Spanned {
                    node: match node {
                        StmtExpr(e, stmt_id) => StmtSemi(e, stmt_id),
                        _ => node /* might already have a semi */
                    },
                    span: span
                }
            });
            fully_expanded.push(new_stmt);
897
        }
898
    }
899 900

    fully_expanded
901 902
}

903 904
// expand a non-macro stmt. this is essentially the fallthrough for
// expand_stmt, above.
905 906
fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroExpander)
                         -> SmallVector<P<Stmt>> {
907
    // is it a let?
908 909 910 911
    match node {
        StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl {
            DeclLocal(local) => {
                // take it apart:
912
                let rewritten_local = local.map(|Local {id, pat, ty, init, span}| {
913 914
                    // expand the ty since TyFixedLengthVec contains an Expr
                    // and thus may have a macro use
S
Seo Sanghyeon 已提交
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 920 921 922
                    // oh dear heaven... this is going to include the enum
                    // names, as well... but that should be okay, as long as
                    // the new names are gensyms for the old ones.
                    // generate fresh names, push them to a new pending list
923
                    let idents = pattern_bindings(&*expanded_pat);
924 925
                    let mut new_pending_renames =
                        idents.iter().map(|ident| (*ident, fresh_name(ident))).collect();
926 927
                    // rewrite the pattern using the new names (the old
                    // ones have already been applied):
928
                    let rewritten_pat = {
929 930
                        // nested binding to allow borrow to expire:
                        let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
931 932 933
                        rename_fld.fold_pat(expanded_pat)
                    };
                    // add them to the existing pending renames:
934
                    fld.cx.syntax_env.info().pending_renames
935
                          .extend(new_pending_renames);
936 937 938 939 940 941
                    Local {
                        id: id,
                        ty: expanded_ty,
                        pat: rewritten_pat,
                        // also, don't forget to expand the init:
                        init: init.map(|e| fld.fold_expr(e)),
942
                        span: span
943 944 945 946 947 948 949 950 951 952
                    }
                });
                SmallVector::one(P(Spanned {
                    node: StmtDecl(P(Spanned {
                            node: DeclLocal(rewritten_local),
                            span: span
                        }),
                        node_id),
                    span: stmt_span
                }))
S
Steven Fackler 已提交
953
            }
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
            _ => {
                noop_fold_stmt(Spanned {
                    node: StmtDecl(P(Spanned {
                            node: decl,
                            span: span
                        }),
                        node_id),
                    span: stmt_span
                }, fld)
            }
        }),
        _ => {
            noop_fold_stmt(Spanned {
                node: node,
                span: stmt_span
            }, fld)
        }
971 972 973
    }
}

J
John Clements 已提交
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() {
S
Steve Klabnik 已提交
979
        panic!("encountered match arm with 0 patterns");
J
John Clements 已提交
980
    }
J
John Clements 已提交
981 982
    // all of the pats must have the same set of bindings, so use the
    // first one to extract them and generate new names:
983
    let idents = pattern_bindings(&*expanded_pats[0]);
A
Aaron Turon 已提交
984
    let new_renames = idents.into_iter().map(|id| (id, fresh_name(&id))).collect();
985
    // apply the renaming, but only to the PatIdents:
J
John Clements 已提交
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:
J
John Clements 已提交
989
    let mut rename_fld = IdentRenamer{renames:&new_renames};
990 991 992
    let rewritten_guard =
        arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
    let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
J
John Clements 已提交
993
    ast::Arm {
994
        attrs: fold::fold_attrs(arm.attrs, fld),
995 996 997
        pats: rewritten_pats,
        guard: rewritten_guard,
        body: rewritten_body,
J
John Clements 已提交
998
    }
J
John Clements 已提交
999 1000
}

1001 1002 1003
/// A visitor that extracts the PatIdent (binding) paths
/// from a given thingy and puts them in a mutable
/// array
1004
#[derive(Clone)]
1005
struct PatIdentFinder {
1006
    ident_accumulator: Vec<ast::Ident>
1007 1008
}

1009
impl<'v> Visitor<'v> for PatIdentFinder {
1010
    fn visit_pat(&mut self, pattern: &ast::Pat) {
1011
        match *pattern {
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)
J
John Clements 已提交
1017 1018
                }
            }
1019
            // use the default traversal for non-PatIdents
1020
            _ => visit::walk_pat(self, pattern)
1021 1022 1023 1024
        }
    }
}

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
1030 1031
}

J
John Clements 已提交
1032 1033 1034
/// find the PatIdent paths in a
fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec<ast::Ident> {
    let mut pat_idents = PatIdentFinder{ident_accumulator:Vec::new()};
1035
    for arg in &fn_decl.inputs {
1036
        pat_idents.visit_pat(&*arg.pat);
J
John Clements 已提交
1037 1038 1039 1040
    }
    pat_idents.ident_accumulator
}

J
John Clements 已提交
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))
1046 1047
}

J
John Clements 已提交
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}| {
A
Aaron Turon 已提交
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")
1057
            };
1058
            // expand macros in the statement
A
Aaron Turon 已提交
1059
            fld.fold_stmt(renamed_stmt).into_iter()
1060
        }).collect();
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
        let new_expr = expr.map(|x| {
            let expr = {
                let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
                let mut rename_fld = IdentRenamer{renames:pending_renames};
                rename_fld.fold_expr(x)
            };
            fld.fold_expr(expr)
        });
        Block {
            id: fld.new_id(id),
            stmts: new_stmts,
            expr: new_expr,
            rules: rules,
            span: span
        }
1076
    })
J
John Clements 已提交
1077 1078
}

1079 1080 1081 1082
fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
    match p.node {
        PatMac(_) => {}
        _ => return noop_fold_pat(p, fld)
K
Keegan McAllister 已提交
1083
    }
1084 1085 1086 1087 1088 1089 1090 1091 1092
    p.map(|ast::Pat {node, span, ..}| {
        let (pth, tts) = match node {
            PatMac(mac) => match mac.node {
                MacInvocTT(pth, tts, _) => {
                    (pth, tts)
                }
            },
            _ => unreachable!()
        };
1093
        if pth.segments.len() > 1 {
1094 1095
            fld.cx.span_err(pth.span, "expected macro name without module separators");
            return DummyResult::raw_pat(span);
K
Keegan McAllister 已提交
1096
        }
1097 1098
        let extname = pth.segments[0].identifier.name;
        let marked_after = match fld.cx.syntax_env.find(&extname) {
1099 1100
            None => {
                fld.cx.span_err(pth.span,
J
Jorge Aparicio 已提交
1101
                                &format!("macro undefined: '{}!'",
1102
                                        extname));
1103 1104 1105
                // let compilation continue
                return DummyResult::raw_pat(span);
            }
K
Keegan McAllister 已提交
1106

1107
            Some(rc) => match *rc {
1108
                NormalTT(ref expander, tt_span, allow_internal_unstable) => {
1109 1110 1111
                    fld.cx.bt_push(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
1112
                            name: extname.to_string(),
1113
                            format: MacroBang,
1114 1115
                            span: tt_span,
                            allow_internal_unstable: allow_internal_unstable,
1116 1117
                        }
                    });
K
Keegan McAllister 已提交
1118

1119
                    let fm = fresh_mark();
1120
                    let marked_before = mark_tts(&tts[..], fm);
1121
                    let mac_span = fld.cx.original_span();
1122 1123 1124 1125
                    let pat = expander.expand(fld.cx,
                                              mac_span,
                                              &marked_before[..]).make_pat();
                    let expanded = match pat {
1126 1127 1128 1129
                        Some(e) => e,
                        None => {
                            fld.cx.span_err(
                                pth.span,
J
Jorge Aparicio 已提交
1130
                                &format!(
1131
                                    "non-pattern macro in pattern position: {}",
1132
                                    extname
1133
                                    )
1134 1135 1136 1137
                            );
                            return DummyResult::raw_pat(span);
                        }
                    };
1138

1139 1140 1141 1142 1143
                    // mark after:
                    mark_pat(expanded,fm)
                }
                _ => {
                    fld.cx.span_err(span,
J
Jorge Aparicio 已提交
1144
                                    &format!("{}! is not legal in pattern position",
1145
                                            extname));
1146 1147
                    return DummyResult::raw_pat(span);
                }
1148
            }
1149
        };
K
Keegan McAllister 已提交
1150

1151 1152 1153
        let fully_expanded =
            fld.fold_pat(marked_after).node.clone();
        fld.cx.bt_pop();
K
Keegan McAllister 已提交
1154

1155 1156 1157 1158 1159 1160
        ast::Pat {
            id: ast::DUMMY_NODE_ID,
            node: fully_expanded,
            span: span
        }
    })
K
Keegan McAllister 已提交
1161 1162
}

J
John Clements 已提交
1163 1164 1165
/// A tree-folder that applies every rename in its (mutable) list
/// to every identifier, including both bindings and varrefs
/// (and lots of things that will turn out to be neither)
1166
pub struct IdentRenamer<'a> {
1167
    renames: &'a mtwt::RenameList,
1168 1169
}

1170
impl<'a> Folder for IdentRenamer<'a> {
1171 1172
    fn fold_ident(&mut self, id: Ident) -> Ident {
        Ident {
1173
            name: id.name,
1174
            ctxt: mtwt::apply_renames(self.renames, id.ctxt),
1175 1176
        }
    }
K
Keegan McAllister 已提交
1177 1178
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
1179
    }
1180 1181
}

J
John Clements 已提交
1182 1183 1184 1185 1186 1187 1188 1189 1190
/// A tree-folder that applies every rename in its list to
/// the idents that are in PatIdent patterns. This is more narrowly
/// focused than IdentRenamer, and is needed for FnDecl,
/// where we want to rename the args but not the fn name or the generics etc.
pub struct PatIdentRenamer<'a> {
    renames: &'a mtwt::RenameList,
}

impl<'a> Folder for PatIdentRenamer<'a> {
1191
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
J
John Clements 已提交
1192
        match pat.node {
1193 1194 1195 1196 1197 1198 1199 1200
            ast::PatIdent(..) => {},
            _ => return noop_fold_pat(pat, self)
        }

        pat.map(|ast::Pat {id, node, span}| match node {
            ast::PatIdent(binding_mode, Spanned{span: sp, node: ident}, sub) => {
                let new_ident = Ident{name: ident.name,
                                      ctxt: mtwt::apply_renames(self.renames, ident.ctxt)};
J
John Clements 已提交
1201 1202
                let new_node =
                    ast::PatIdent(binding_mode,
1203
                                  Spanned{span: self.new_span(sp), node: new_ident},
J
John Clements 已提交
1204
                                  sub.map(|p| self.fold_pat(p)));
1205 1206
                ast::Pat {
                    id: id,
J
John Clements 已提交
1207
                    node: new_node,
1208
                    span: self.new_span(span)
J
John Clements 已提交
1209 1210
                }
            },
1211 1212
            _ => unreachable!()
        })
1213
    }
K
Keegan McAllister 已提交
1214 1215
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
1216
    }
K
Kevin Atkinson 已提交
1217 1218
}

1219 1220 1221 1222 1223 1224 1225
fn expand_annotatable(a: Annotatable,
                      fld: &mut MacroExpander)
                      -> SmallVector<Annotatable> {
    let a = expand_item_multi_modifier(a, fld);

    let mut decorator_items = SmallVector::zero();
    let mut new_attrs = Vec::new();
1226
    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239

    let mut new_items: SmallVector<Annotatable> = match a {
        Annotatable::Item(it) => match it.node {
            ast::ItemMac(..) => {
                expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
            }
            ast::ItemMod(_) | ast::ItemForeignMod(_) => {
                let valid_ident =
                    it.ident.name != parse::token::special_idents::invalid.name;

                if valid_ident {
                    fld.cx.mod_push(it.ident);
                }
1240
                let macro_use = contains_macro_use(fld, &new_attrs[..]);
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
                let result = with_exts_frame!(fld.cx.syntax_env,
                                              macro_use,
                                              noop_fold_item(it, fld));
                if valid_ident {
                    fld.cx.mod_pop();
                }
                result.into_iter().map(|i| Annotatable::Item(i)).collect()
            },
            _ => {
                let it = P(ast::Item {
                    attrs: new_attrs,
                    ..(*it).clone()
                });
                noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
            }
        },
1257

1258
        Annotatable::TraitItem(it) => match it.node {
1259 1260 1261 1262 1263 1264 1265 1266 1267
            ast::MethodTraitItem(_, Some(_)) => SmallVector::one(it.map(|ti| ast::TraitItem {
                id: ti.id,
                ident: ti.ident,
                attrs: ti.attrs,
                node: match ti.node  {
                    ast::MethodTraitItem(sig, Some(body)) => {
                        let (sig, body) = expand_and_rename_method(sig, body, fld);
                        ast::MethodTraitItem(sig, Some(body))
                    }
1268
                    _ => unreachable!()
1269 1270 1271 1272 1273 1274
                },
                span: fld.new_span(ti.span)
            })),
            _ => fold::noop_fold_trait_item(it, fld)
        }.into_iter().map(Annotatable::TraitItem).collect(),

1275
        Annotatable::ImplItem(ii) => {
1276
            expand_impl_item(ii, fld).into_iter().map(Annotatable::ImplItem).collect()
1277 1278 1279
        }
    };

1280
    new_items.push_all(decorator_items);
1281 1282 1283
    new_items
}

1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
// Partition a set of attributes into one kind of attribute, and other kinds.
macro_rules! partition {
    ($fn_name: ident, $variant: ident) => {
        #[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
        fn $fn_name(attrs: &[ast::Attribute],
                    fld: &MacroExpander)
                     -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
            attrs.iter().cloned().partition(|attr| {
                match fld.cx.syntax_env.find(&intern(&attr.name())) {
                    Some(rc) => match *rc {
                        $variant(..) => true,
                        _ => false
                    },
                    _ => false
                }
            })
1300
        }
1301
    }
1302 1303
}

1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
partition!(modifiers, Modifier);
partition!(multi_modifiers, MultiModifier);


#[allow(deprecated)] // The `allow` is needed because the `Decorator` variant is used.
fn expand_decorators(a: Annotatable,
                     fld: &mut MacroExpander,
                     decorator_items: &mut SmallVector<Annotatable>,
                     new_attrs: &mut Vec<ast::Attribute>)
{
    for attr in a.attrs() {
        let mname = attr.name();
        match fld.cx.syntax_env.find(&intern(&mname)) {
1317
            Some(rc) => match *rc {
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
                Decorator(ref dec) => {
                    attr::mark_used(&attr);

                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
                            name: mname.to_string(),
                            format: MacroAttribute,
                            span: Some(attr.span),
                            // attributes can do whatever they like,
                            // for now.
                            allow_internal_unstable: true,
                        }
                    });

                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
                    // but that double-mut-borrows fld
                    let mut items: SmallVector<Annotatable> = SmallVector::zero();
                    dec.expand(fld.cx,
                               attr.span,
                               &attr.node.value,
                               &a.clone().expect_item(),
                               &mut |item| items.push(Annotatable::Item(item)));
                    decorator_items.extend(items.into_iter()
                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));

                    fld.cx.bt_pop();
                }
                MultiDecorator(ref dec) => {
                    attr::mark_used(&attr);

                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
                            name: mname.to_string(),
                            format: MacroAttribute,
                            span: Some(attr.span),
                            // attributes can do whatever they like,
                            // for now.
                            allow_internal_unstable: true,
                        }
                    });

                    // we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
                    // but that double-mut-borrows fld
                    let mut items: SmallVector<Annotatable> = SmallVector::zero();
                    dec.expand(fld.cx,
                               attr.span,
                               &attr.node.value,
1367
                               &a,
1368 1369 1370 1371 1372 1373 1374
                               &mut |ann| items.push(ann));
                    decorator_items.extend(items.into_iter()
                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));

                    fld.cx.bt_pop();
                }
                _ => new_attrs.push((*attr).clone()),
1375
            },
1376
            _ => new_attrs.push((*attr).clone()),
1377
        }
1378
    }
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
}

fn expand_item_multi_modifier(mut it: Annotatable,
                              fld: &mut MacroExpander)
                              -> Annotatable {
    let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);

    // Update the attrs, leave everything else alone. Is this mutation really a good idea?
    it = it.fold_attrs(other_attrs);

    if modifiers.is_empty() {
        return it
    }

1393
    for attr in &modifiers {
1394 1395
        let mname = attr.name();

1396
        match fld.cx.syntax_env.find(&intern(&mname)) {
1397 1398 1399 1400 1401 1402
            Some(rc) => match *rc {
                MultiModifier(ref mac) => {
                    attr::mark_used(attr);
                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
1403
                            name: mname.to_string(),
1404
                            format: MacroAttribute,
1405
                            span: Some(attr.span),
1406 1407 1408
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
                        }
                    });
                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
                    fld.cx.bt_pop();
                }
                _ => unreachable!()
            },
            _ => unreachable!()
        }
    }

    // Expansion may have added new ItemModifiers.
    expand_item_multi_modifier(it, fld)
}

1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
#[allow(deprecated)] // This is needed because the `ItemModifier` trait is used
fn expand_item_modifiers(mut it: P<ast::Item>,
                         fld: &mut MacroExpander)
                         -> P<ast::Item> {
    // partition the attributes into ItemModifiers and others
    let (modifiers, other_attrs) = modifiers(&it.attrs, fld);

    // update the attrs, leave everything else alone. Is this mutation really a good idea?
    it = P(ast::Item {
        attrs: other_attrs,
        ..(*it).clone()
    });

    if modifiers.is_empty() {
        let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
        return it.expect_item();
    }

    for attr in &modifiers {
        let mname = attr.name();

        match fld.cx.syntax_env.find(&intern(&mname)) {
            Some(rc) => match *rc {
                Modifier(ref mac) => {
                    attr::mark_used(attr);
                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
                            name: mname.to_string(),
                            format: MacroAttribute,
                            span: Some(attr.span),
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
                        }
                    });
                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
                    fld.cx.bt_pop();
                }
                _ => unreachable!()
            },
            _ => unreachable!()
        }
    }

    // Expansion may have added new ItemModifiers.
    // It is possible, that an item modifier could expand to a multi-modifier or
    // vice versa. In this case we will expand all modifiers before multi-modifiers,
    // which might give an odd ordering. However, I think it is unlikely that the
    // two kinds will be mixed, and old-style multi-modifiers are deprecated.
    expand_item_modifiers(it, fld)
}

1477
fn expand_impl_item(ii: P<ast::ImplItem>, fld: &mut MacroExpander)
1478 1479
                 -> SmallVector<P<ast::ImplItem>> {
    match ii.node {
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
        ast::MethodImplItem(..) => SmallVector::one(ii.map(|ii| ast::ImplItem {
            id: ii.id,
            ident: ii.ident,
            attrs: ii.attrs,
            vis: ii.vis,
            node: match ii.node  {
                ast::MethodImplItem(sig, body) => {
                    let (sig, body) = expand_and_rename_method(sig, body, fld);
                    ast::MethodImplItem(sig, body)
                }
                _ => unreachable!()
            },
            span: fld.new_span(ii.span)
        })),
        ast::MacImplItem(_) => {
1495
            let (span, mac) = ii.and_then(|ii| match ii.node {
1496
                ast::MacImplItem(mac) => (ii.span, mac),
1497 1498
                _ => unreachable!()
            });
1499
            let maybe_new_items =
1500
                expand_mac_invoc(mac, span,
1501 1502
                                 |r| r.make_impl_items(),
                                 |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
J
John Clements 已提交
1503 1504
                                 fld);

1505 1506
            match maybe_new_items {
                Some(impl_items) => {
A
Adolfo Ochagavía 已提交
1507
                    // expand again if necessary
1508 1509 1510
                    let new_items = impl_items.into_iter().flat_map(|ii| {
                        expand_impl_item(ii, fld).into_iter()
                    }).collect();
A
Adolfo Ochagavía 已提交
1511
                    fld.cx.bt_pop();
1512
                    new_items
A
Adolfo Ochagavía 已提交
1513
                }
J
John Clements 已提交
1514
                None => SmallVector::zero()
A
Adolfo Ochagavía 已提交
1515
            }
1516
        }
1517
        _ => fold::noop_fold_impl_item(ii, fld)
1518
    }
1519 1520
}

J
John Clements 已提交
1521 1522 1523
/// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
/// PatIdents in its arguments to perform renaming in the FnDecl and
/// 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>,
J
John Clements 已提交
1525
                                       fld: &mut MacroExpander)
1526
                                       -> (P<ast::FnDecl>, P<ast::Block>) {
J
John Clements 已提交
1527
    let expanded_decl = fld.fold_fn_decl(fn_decl);
1528
    let idents = fn_decl_arg_bindings(&*expanded_decl);
J
John Clements 已提交
1529 1530 1531 1532
    let renames =
        idents.iter().map(|id : &ast::Ident| (*id,fresh_name(id))).collect();
    // first, a renamer for the PatIdents, for the fn_decl:
    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
1533
    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
J
John Clements 已提交
1534 1535 1536 1537 1538 1539
    // now, a renamer for *all* idents, for the body:
    let mut rename_fld = IdentRenamer{renames: &renames};
    let rewritten_body = fld.fold_block(rename_fld.fold_block(block));
    (rewritten_fn_decl,rewritten_body)
}

1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
fn expand_and_rename_method(sig: ast::MethodSig, body: P<ast::Block>,
                            fld: &mut MacroExpander)
                            -> (ast::MethodSig, P<ast::Block>) {
    let (rewritten_fn_decl, rewritten_body)
        = expand_and_rename_fn_decl_and_block(sig.decl, body, fld);
    (ast::MethodSig {
        generics: fld.fold_generics(sig.generics),
        abi: sig.abi,
        explicit_self: fld.fold_explicit_self(sig.explicit_self),
        unsafety: sig.unsafety,
N
Niko Matsakis 已提交
1550
        constness: sig.constness,
1551 1552 1553 1554
        decl: rewritten_fn_decl
    }, rewritten_body)
}

1555 1556 1557
pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
    let t = match t.node.clone() {
        ast::Ty_::TyMac(mac) => {
J
Jared Roesch 已提交
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
            if fld.cx.ecfg.features.unwrap().type_macros {
                let expanded_ty = match expand_mac_invoc(mac, t.span,
                                                         |r| r.make_ty(),
                                                         mark_ty,
                                                         fld) {
                    Some(ty) => ty,
                    None => {
                        return DummyResult::raw_ty(t.span);
                    }
                };
1568

J
Jared Roesch 已提交
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
                // Keep going, outside-in.
                let fully_expanded = fld.fold_ty(expanded_ty);
                fld.cx.bt_pop();

                fully_expanded.map(|t| ast::Ty {
                    id: ast::DUMMY_NODE_ID,
                    node: t.node,
                    span: t.span,
                    })
            } else {
                feature_gate::emit_feature_err(
                    &fld.cx.parse_sess.span_diagnostic,
                    "type_macros",
                    t.span,
J
Jared Roesch 已提交
1583
                    "type macros are experimental (see issue: #27336)");
J
Jared Roesch 已提交
1584 1585
                t
            }
1586 1587 1588
        }
        _ => t
    };
J
Jared Roesch 已提交
1589

1590 1591 1592
    fold::noop_fold_ty(t, fld)
}

J
John Clements 已提交
1593
/// A tree-folder that performs macro expansion
1594
pub struct MacroExpander<'a, 'b:'a> {
1595
    pub cx: &'a mut ExtCtxt<'b>,
N
Nick Cameron 已提交
1596 1597 1598 1599
}

impl<'a, 'b> MacroExpander<'a, 'b> {
    pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1600
        MacroExpander { cx: cx }
N
Nick Cameron 已提交
1601
    }
1602 1603
}

E
Eduard Burtescu 已提交
1604
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1605
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1606
        expand_expr(expr, self)
1607 1608
    }

1609
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
K
Keegan McAllister 已提交
1610 1611 1612
        expand_pat(pat, self)
    }

1613
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1614
        expand_item(item, self)
1615 1616
    }

1617
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
J
John Clements 已提交
1618 1619 1620
        expand_item_underscore(item, self)
    }

1621
    fn fold_stmt(&mut self, stmt: P<ast::Stmt>) -> SmallVector<P<ast::Stmt>> {
1622
        expand_stmt(stmt, self)
1623 1624
    }

S
Steven Fackler 已提交
1625
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1626
        expand_block(block, self)
1627 1628
    }

1629
    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
J
John Clements 已提交
1630 1631 1632
        expand_arm(arm, self)
    }

1633 1634 1635
    fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
        expand_annotatable(Annotatable::TraitItem(i), self)
            .into_iter().map(|i| i.expect_trait_item()).collect()
1636 1637
    }

1638 1639 1640
    fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
        expand_annotatable(Annotatable::ImplItem(i), self)
            .into_iter().map(|i| i.expect_impl_item()).collect()
1641 1642
    }

1643 1644 1645 1646
    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
        expand_type(ty, self)
    }

S
Steven Fackler 已提交
1647
    fn new_span(&mut self, span: Span) -> Span {
1648 1649
        new_span(self.cx, span)
    }
1650 1651
}

J
John Clements 已提交
1652 1653 1654 1655 1656
fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
    /* this discards information in the case of macro-defining macros */
    Span {
        lo: sp.lo,
        hi: sp.hi,
1657
        expn_id: cx.backtrace(),
J
John Clements 已提交
1658 1659 1660
    }
}

1661
pub struct ExpansionConfig<'feat> {
1662
    pub crate_name: String,
1663
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1664
    pub recursion_limit: usize,
1665
    pub trace_mac: bool,
1666 1667
}

1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1681 1682
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1683 1684
        ExpansionConfig {
            crate_name: crate_name,
1685
            features: None,
1686
            recursion_limit: 64,
1687
            trace_mac: false,
1688 1689
        }
    }
1690

1691 1692 1693 1694 1695 1696 1697
    feature_tests! {
        fn enable_quotes = allow_quote,
        fn enable_asm = allow_asm,
        fn enable_log_syntax = allow_log_syntax,
        fn enable_concat_idents = allow_concat_idents,
        fn enable_trace_macros = allow_trace_macros,
        fn enable_allow_internal_unstable = allow_internal_unstable,
1698
        fn enable_custom_derive = allow_custom_derive,
1699
        fn enable_pushpop_unsafe = allow_pushpop_unsafe,
1700
    }
1701 1702
}

1703 1704 1705 1706 1707 1708
pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
                           cfg: ExpansionConfig<'feat>,
                           // these are the macros being imported to this crate:
                           imported_macros: Vec<ast::MacroDef>,
                           user_exts: Vec<NamedSyntaxExtension>,
                           c: Crate) -> Crate {
1709
    let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
1710 1711
    cx.use_std = std_inject::use_std(&c);

N
Nick Cameron 已提交
1712
    let mut expander = MacroExpander::new(&mut cx);
1713

1714
    for def in imported_macros {
1715
        expander.cx.insert_macro(def);
1716 1717
    }

1718
    for (name, extension) in user_exts {
1719
        expander.cx.syntax_env.insert(name, extension);
1720 1721
    }

1722 1723
    let mut ret = expander.fold_crate(c);
    ret.exported_macros = expander.cx.exported_macros.clone();
1724 1725
    parse_sess.span_diagnostic.handler().abort_if_errors();
    return ret;
1726
}
J
John Clements 已提交
1727

1728 1729 1730 1731 1732 1733 1734 1735
// HYGIENIC CONTEXT EXTENSION:
// all of these functions are for walking over
// ASTs and making some change to the context of every
// element that has one. a CtxtFn is a trait-ified
// version of a closure in (SyntaxContext -> SyntaxContext).
// the ones defined here include:
// Marker - add a mark to a context

E
Eduard Burtescu 已提交
1736 1737
// A Marker adds the given mark to the syntax context
struct Marker { mark: Mrk }
1738

E
Eduard Burtescu 已提交
1739
impl Folder for Marker {
1740
    fn fold_ident(&mut self, id: Ident) -> Ident {
1741
        ast::Ident {
E
Eduard Burtescu 已提交
1742
            name: id.name,
1743
            ctxt: mtwt::apply_mark(self.mark, id.ctxt)
1744 1745
        }
    }
1746
    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1747
        Spanned {
1748 1749 1750
            node: match node {
                MacInvocTT(path, tts, ctxt) => {
                    MacInvocTT(self.fold_path(path),
1751
                               self.fold_tts(&tts[..]),
1752 1753 1754 1755
                               mtwt::apply_mark(self.mark, ctxt))
                }
            },
            span: span,
1756
        }
1757 1758 1759
    }
}

1760
// apply a given mark to the given token trees. Used prior to expansion of a macro.
1761
fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
M
Marvin Löbel 已提交
1762
    noop_fold_tts(tts, &mut Marker{mark:m})
1763 1764 1765
}

// apply a given mark to the given expr. Used following the expansion of a macro.
1766
fn mark_expr(expr: P<ast::Expr>, m: Mrk) -> P<ast::Expr> {
J
John Clements 已提交
1767
    Marker{mark:m}.fold_expr(expr)
1768 1769
}

K
Keegan McAllister 已提交
1770
// apply a given mark to the given pattern. Used following the expansion of a macro.
1771
fn mark_pat(pat: P<ast::Pat>, m: Mrk) -> P<ast::Pat> {
J
John Clements 已提交
1772
    Marker{mark:m}.fold_pat(pat)
K
Keegan McAllister 已提交
1773 1774
}

1775
// apply a given mark to the given stmt. Used following the expansion of a macro.
1776 1777
fn mark_stmt(stmt: P<ast::Stmt>, m: Mrk) -> P<ast::Stmt> {
    Marker{mark:m}.fold_stmt(stmt)
J
John Clements 已提交
1778
        .expect_one("marking a stmt didn't return exactly one stmt")
1779 1780 1781
}

// apply a given mark to the given item. Used following the expansion of a macro.
1782
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
J
John Clements 已提交
1783
    Marker{mark:m}.fold_item(expr)
J
John Clements 已提交
1784 1785 1786 1787
        .expect_one("marking an item didn't return exactly one item")
}

// apply a given mark to the given item. Used following the expansion of a macro.
1788
fn mark_impl_item(ii: P<ast::ImplItem>, m: Mrk) -> P<ast::ImplItem> {
1789
    Marker{mark:m}.fold_impl_item(ii)
1790
        .expect_one("marking an impl item didn't return exactly one impl item")
1791 1792
}

1793 1794 1795 1796
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
    Marker { mark: m }.fold_ty(ty)
}

J
John Clements 已提交
1797 1798
/// Check that there are no macro invocations left in the AST:
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1799
    visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
J
John Clements 已提交
1800 1801 1802 1803 1804 1805 1806
}

/// A visitor that ensures that no macro invocations remain in an AST.
struct MacroExterminator<'a>{
    sess: &'a parse::ParseSess
}

1807
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
K
Keegan McAllister 已提交
1808 1809
    fn visit_mac(&mut self, mac: &ast::Mac) {
        self.sess.span_diagnostic.span_bug(mac.span,
J
John Clements 已提交
1810 1811 1812 1813 1814 1815
                                           "macro exterminator: expected AST \
                                           with no macro invocations");
    }
}


J
John Clements 已提交
1816
#[cfg(test)]
1817
mod tests {
A
Alex Crichton 已提交
1818
    use super::{pattern_bindings, expand_crate};
1819
    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1820
    use ast;
J
Jorge Aparicio 已提交
1821
    use ast::Name;
1822
    use codemap;
1823
    use ext::mtwt;
1824
    use fold::Folder;
1825
    use parse;
1826
    use parse::token;
E
Eduard Burtescu 已提交
1827
    use util::parser_testing::{string_to_parser};
1828
    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1829
    use visit;
1830 1831 1832 1833 1834
    use visit::Visitor;

    // a visitor that extracts the paths
    // from a given thingy and puts them in a mutable
    // array (passed in to the traversal)
1835
    #[derive(Clone)]
1836
    struct PathExprFinderContext {
1837
        path_accumulator: Vec<ast::Path> ,
1838 1839
    }

1840
    impl<'v> Visitor<'v> for PathExprFinderContext {
1841
        fn visit_expr(&mut self, expr: &ast::Expr) {
1842 1843
            if let ast::ExprPath(None, ref p) = expr.node {
                self.path_accumulator.push(p.clone());
1844
            }
1845
            visit::walk_expr(self, expr);
1846 1847 1848
        }
    }

1849 1850 1851
    // find the variable references in a crate
    fn crate_varrefs(the_crate : &ast::Crate) -> Vec<ast::Path> {
        let mut path_finder = PathExprFinderContext{path_accumulator:Vec::new()};
1852
        visit::walk_crate(&mut path_finder, the_crate);
1853
        path_finder.path_accumulator
1854
    }
J
John Clements 已提交
1855

1856 1857
    /// A Visitor that extracts the identifiers from a thingy.
    // as a side note, I'm starting to want to abstract over these....
1858
    struct IdentFinder {
1859 1860
        ident_accumulator: Vec<ast::Ident>
    }
1861

1862
    impl<'v> Visitor<'v> for IdentFinder {
1863
        fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1864 1865 1866 1867 1868 1869 1870
            self.ident_accumulator.push(id);
        }
    }

    /// Find the idents in a crate
    fn crate_idents(the_crate: &ast::Crate) -> Vec<ast::Ident> {
        let mut ident_finder = IdentFinder{ident_accumulator: Vec::new()};
1871
        visit::walk_crate(&mut ident_finder, the_crate);
1872 1873
        ident_finder.ident_accumulator
    }
1874

J
John Clements 已提交
1875 1876 1877
    // these following tests are quite fragile, in that they don't test what
    // *kind* of failure occurs.

1878
    fn test_ecfg() -> ExpansionConfig<'static> {
1879 1880 1881
        ExpansionConfig::default("test".to_string())
    }

J
John Clements 已提交
1882
    // make sure that macros can't escape fns
1883
    #[should_panic]
J
John Clements 已提交
1884
    #[test] fn macros_cant_escape_fns_test () {
1885
        let src = "fn bogus() {macro_rules! z (() => (3+4));}\
1886
                   fn inty() -> i32 { z!() }".to_string();
1887
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1888
        let crate_ast = parse::parse_crate_from_source_str(
1889
            "<test>".to_string(),
1890
            src,
E
Eduard Burtescu 已提交
1891
            Vec::new(), &sess);
J
John Clements 已提交
1892
        // should fail:
1893
        expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
J
John Clements 已提交
1894 1895
    }

J
John Clements 已提交
1896
    // make sure that macros can't escape modules
1897
    #[should_panic]
J
John Clements 已提交
1898
    #[test] fn macros_cant_escape_mods_test () {
1899
        let src = "mod foo {macro_rules! z (() => (3+4));}\
1900
                   fn inty() -> i32 { z!() }".to_string();
1901
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1902
        let crate_ast = parse::parse_crate_from_source_str(
1903
            "<test>".to_string(),
1904
            src,
E
Eduard Burtescu 已提交
1905
            Vec::new(), &sess);
1906
        expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
J
John Clements 已提交
1907 1908
    }

1909
    // macro_use modules should allow macros to escape
J
John Clements 已提交
1910
    #[test] fn macros_can_escape_flattened_mods_test () {
1911
        let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1912
                   fn inty() -> i32 { z!() }".to_string();
1913
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1914
        let crate_ast = parse::parse_crate_from_source_str(
1915
            "<test>".to_string(),
1916
            src,
E
Eduard Burtescu 已提交
1917
            Vec::new(), &sess);
1918
        expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast);
J
John Clements 已提交
1919 1920
    }

1921
    fn expand_crate_str(crate_str: String) -> ast::Crate {
1922
        let ps = parse::ParseSess::new();
1923
        let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
1924
        // the cfg argument actually does matter, here...
1925
        expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast)
1926 1927
    }

1928 1929
    // find the pat_ident paths in a crate
    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1930
        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1931
        visit::walk_crate(&mut name_finder, the_crate);
1932 1933 1934
        name_finder.ident_accumulator
    }

1935
    #[test] fn macro_tokens_should_match(){
1936
        expand_crate_str(
1937
            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1938 1939
    }

1940 1941 1942
    // should be able to use a bound identifier as a literal in a macro definition:
    #[test] fn self_macro_parsing(){
        expand_crate_str(
1943 1944
            "macro_rules! foo ((zz) => (287;));
            fn f(zz: i32) {foo!(zz);}".to_string()
1945 1946 1947
            );
    }

1948 1949 1950 1951 1952 1953 1954
    // renaming tests expand a crate and then check that the bindings match
    // the right varrefs. The specification of the test case includes the
    // text of the crate, and also an array of arrays.  Each element in the
    // outer array corresponds to a binding in the traversal of the AST
    // induced by visit.  Each of these arrays contains a list of indexes,
    // interpreted as the varrefs in the varref traversal that this binding
    // should match.  So, for instance, in a program with two bindings and
1955
    // three varrefs, the array [[1, 2], [0]] would indicate that the first
1956 1957 1958
    // binding should match the second two varrefs, and the second binding
    // should match the first varref.
    //
J
John Clements 已提交
1959 1960 1961 1962 1963 1964
    // Put differently; this is a sparse representation of a boolean matrix
    // indicating which bindings capture which identifiers.
    //
    // Note also that this matrix is dependent on the implicit ordering of
    // the bindings and the varrefs discovered by the name-finder and the path-finder.
    //
1965 1966
    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
    // names; differences in marks don't matter any more.
J
John Clements 已提交
1967
    //
1968
    // oog... I also want tests that check "bound-identifier-=?". That is,
J
John Clements 已提交
1969 1970 1971 1972 1973
    // not just "do these have the same name", but "do they have the same
    // name *and* the same marks"? Understanding this is really pretty painful.
    // in principle, you might want to control this boolean on a per-varref basis,
    // but that would make things even harder to understand, and might not be
    // necessary for thorough testing.
P
Paul Collier 已提交
1974
    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1975

1976 1977
    #[test]
    fn automatic_renaming () {
1978 1979
        let tests: Vec<RenamingTest> =
            vec!(// b & c should get new names throughout, in the expr too:
1980
                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1981
                 vec!(vec!(0,1),vec!(2)), false),
J
John Clements 已提交
1982
                // both x's should be renamed (how is this causing a bug?)
1983
                ("fn main () {let x: i32 = 13;x;}",
1984
                 vec!(vec!(0)), false),
1985
                // the use of b after the + should be renamed, the other one not:
1986
                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1987
                 vec!(vec!(1)), false),
J
John Clements 已提交
1988
                // the b before the plus should not be renamed (requires marks)
1989
                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1990
                 vec!(vec!(1)), false),
1991 1992 1993
                // the marks going in and out of letty should cancel, allowing that $x to
                // capture the one following the semicolon.
                // this was an awesome test case, and caught a *lot* of bugs.
1994 1995
                ("macro_rules! letty(($x:ident) => (let $x = 15;));
                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
1996
                  fn main() -> i32 {user!(z)}",
1997 1998
                 vec!(vec!(0)), false)
                );
1999 2000
        for (idx,s) in tests.iter().enumerate() {
            run_renaming_test(s,idx);
2001 2002 2003
        }
    }

2004 2005 2006 2007 2008
    // no longer a fixme #8062: this test exposes a *potential* bug; our system does
    // not behave exactly like MTWT, but a conversation with Matthew Flatt
    // suggests that this can only occur in the presence of local-expand, which
    // we have no plans to support. ... unless it's needed for item hygiene....
    #[ignore]
R
Richo Healey 已提交
2009 2010
    #[test]
    fn issue_8062(){
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020
        run_renaming_test(
            &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}",
              vec!(vec!(0)), true), 0)
    }

    // FIXME #6994:
    // the z flows into and out of two macros (g & f) along one path, and one
    // (just g) along the other, so the result of the whole thing should
    // be "let z_123 = 3; z_123"
    #[ignore]
R
Richo Healey 已提交
2021 2022
    #[test]
    fn issue_6994(){
2023 2024
        run_renaming_test(
            &("macro_rules! g (($x:ident) =>
2025
              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
2026 2027 2028
              fn a(){g!(z)}",
              vec!(vec!(0)),false),
            0)
2029 2030
    }

2031
    // match variable hygiene. Should expand into
2032
    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
R
Richo Healey 已提交
2033 2034
    #[test]
    fn issue_9384(){
2035
        run_renaming_test(
2036
            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
2037
              fn z() {match 8 {x => bad_macro!(x)}}",
2038
              // NB: the third "binding" is the repeat of the second one.
2039
              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
2040 2041
              true),
            0)
2042 2043
    }

2044
    // interpolated nodes weren't getting labeled.
2045 2046
    // should expand into
    // fn main(){let g1_1 = 13; g1_1}}
R
Richo Healey 已提交
2047 2048
    #[test]
    fn pat_expand_issue_15221(){
2049
        run_renaming_test(
2050 2051
            &("macro_rules! inner ( ($e:pat ) => ($e));
              macro_rules! outer ( ($e:pat ) => (inner!($e)));
2052 2053 2054 2055 2056 2057
              fn main() { let outer!(g) = 13; g;}",
              vec!(vec!(0)),
              true),
            0)
    }

2058
    // create a really evil test case where a $x appears inside a binding of $x
J
Joseph Crail 已提交
2059
    // but *shouldn't* bind because it was inserted by a different macro....
2060 2061
    // can't write this test case until we have macro-generating macros.

2062
    // method arg hygiene
2063
    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
R
Richo Healey 已提交
2064 2065
    #[test]
    fn method_arg_hygiene(){
2066
        run_renaming_test(
2067 2068
            &("macro_rules! inject_x (()=>(x));
              macro_rules! inject_self (()=>(self));
2069
              struct A;
2070
              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
2071 2072 2073 2074 2075
              vec!(vec!(0),vec!(3)),
              true),
            0)
    }

J
John Clements 已提交
2076 2077
    // ooh, got another bite?
    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
R
Richo Healey 已提交
2078 2079
    #[test]
    fn method_arg_hygiene_2(){
J
John Clements 已提交
2080 2081 2082
        run_renaming_test(
            &("struct A;
              macro_rules! add_method (($T:ty) =>
2083 2084
              (impl $T {  fn thingy(&self) {self;} }));
              add_method!(A);",
J
John Clements 已提交
2085 2086 2087 2088 2089
              vec!(vec!(0)),
              true),
            0)
    }

J
John Clements 已提交
2090
    // item fn hygiene
2091
    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
R
Richo Healey 已提交
2092 2093
    #[test]
    fn issue_9383(){
2094
        run_renaming_test(
2095 2096
            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
              fn q(x: i32) { bad_macro!(x); }",
2097
              vec!(vec!(1),vec!(0)),true),
2098
            0)
2099
    }
2100

2101
    // closure arg hygiene (ExprClosure)
2102
    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
R
Richo Healey 已提交
2103 2104
    #[test]
    fn closure_arg_hygiene(){
2105
        run_renaming_test(
2106
            &("macro_rules! inject_x (()=>(x));
2107
            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
2108 2109 2110 2111 2112
              vec!(vec!(1)),
              true),
            0)
    }

2113
    // macro_rules in method position. Sadly, unimplemented.
R
Richo Healey 已提交
2114 2115
    #[test]
    fn macro_in_method_posn(){
2116
        expand_crate_str(
2117
            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
2118
            struct A;
2119
            impl A{ my_method!(); }
2120 2121 2122
            fn f(){A.thirteen;}".to_string());
    }

2123 2124
    // another nested macro
    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
R
Richo Healey 已提交
2125 2126
    #[test]
    fn item_macro_workaround(){
2127 2128 2129 2130
        run_renaming_test(
            &("macro_rules! item { ($i:item) => {$i}}
              struct Entries;
              macro_rules! iterator_impl {
2131
              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
2132 2133 2134 2135 2136
              iterator_impl! { }",
              vec!(vec!(0)), true),
            0)
    }

J
John Clements 已提交
2137
    // run one of the renaming tests
P
Paul Collier 已提交
2138
    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
J
John Clements 已提交
2139
        let invalid_name = token::special_idents::invalid.name;
J
John Clements 已提交
2140
        let (teststr, bound_connections, bound_ident_check) = match *t {
2141
            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
2142
        };
2143
        let cr = expand_crate_str(teststr.to_string());
2144 2145
        let bindings = crate_bindings(&cr);
        let varrefs = crate_varrefs(&cr);
2146

2147 2148 2149
        // must be one check clause for each binding:
        assert_eq!(bindings.len(),bound_connections.len());
        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
2150 2151
            let binding_name = mtwt::resolve(bindings[binding_idx]);
            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
2152
            // shouldmatch can't name varrefs that don't exist:
2153
            assert!((shouldmatch.is_empty()) ||
2154 2155
                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
            for (idx,varref) in varrefs.iter().enumerate() {
2156
                let print_hygiene_debug_info = || {
J
John Clements 已提交
2157 2158 2159
                    // good lord, you can't make a path with 0 segments, can you?
                    let final_varref_ident = match varref.segments.last() {
                        Some(pathsegment) => pathsegment.identifier,
S
Steve Klabnik 已提交
2160
                        None => panic!("varref with 0 path segments?")
J
John Clements 已提交
2161 2162 2163 2164 2165
                    };
                    let varref_name = mtwt::resolve(final_varref_ident);
                    let varref_idents : Vec<ast::Ident>
                        = varref.segments.iter().map(|s| s.identifier)
                        .collect();
A
Alex Crichton 已提交
2166
                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
2167
                    println!("varref's first segment's string: \"{}\"", final_varref_ident);
J
John Clements 已提交
2168
                    println!("binding #{}: {}, resolves to {}",
2169
                             binding_idx, bindings[binding_idx], binding_name);
J
John Clements 已提交
2170 2171
                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
                };
2172 2173
                if shouldmatch.contains(&idx) {
                    // it should be a path of length 1, and it should
J
John Clements 已提交
2174
                    // be free-identifier=? or bound-identifier=? to the given binding
2175
                    assert_eq!(varref.segments.len(),1);
2176 2177
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
                    let varref_marks = mtwt::marksof(varref.segments[0]
2178 2179 2180
                                                           .identifier
                                                           .ctxt,
                                                     invalid_name);
2181
                    if !(varref_name==binding_name) {
2182
                        println!("uh oh, should match but doesn't:");
J
John Clements 已提交
2183
                        print_hygiene_debug_info();
2184 2185
                    }
                    assert_eq!(varref_name,binding_name);
2186
                    if bound_ident_check {
J
John Clements 已提交
2187 2188
                        // we're checking bound-identifier=?, and the marks
                        // should be the same, too:
J
John Clements 已提交
2189 2190
                        assert_eq!(varref_marks,binding_marks.clone());
                    }
2191
                } else {
2192
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
2193
                    let fail = (varref.segments.len() == 1)
2194
                        && (varref_name == binding_name);
2195
                    // temp debugging:
2196
                    if fail {
2197 2198 2199 2200
                        println!("failure on test {}",test_idx);
                        println!("text of test case: \"{}\"", teststr);
                        println!("");
                        println!("uh oh, matches but shouldn't:");
J
John Clements 已提交
2201
                        print_hygiene_debug_info();
2202 2203 2204 2205
                    }
                    assert!(!fail);
                }
            }
2206 2207
        }
    }
2208

R
Richo Healey 已提交
2209 2210
    #[test]
    fn fmt_in_macro_used_inside_module_macro() {
2211 2212 2213
        let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
foo_module!();
2214
".to_string();
J
John Clements 已提交
2215 2216
        let cr = expand_crate_str(crate_str);
        // find the xx binding
2217
        let bindings = crate_bindings(&cr);
2218
        let cxbinds: Vec<&ast::Ident> =
2219
            bindings.iter().filter(|b| b.name == "xx").collect();
2220
        let cxbinds: &[&ast::Ident] = &cxbinds[..];
2221 2222
        let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
            (1, Some(b)) => *b,
S
Steve Klabnik 已提交
2223
            _ => panic!("expected just one binding for ext_cx")
J
John Clements 已提交
2224
        };
2225
        let resolved_binding = mtwt::resolve(*cxbind);
2226
        let varrefs = crate_varrefs(&cr);
2227

J
John Clements 已提交
2228
        // the xx binding should bind all of the xx varrefs:
2229
        for (idx,v) in varrefs.iter().filter(|p| {
2230
            p.segments.len() == 1
2231
            && p.segments[0].identifier.name == "xx"
2232
        }).enumerate() {
2233
            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
2234
                println!("uh oh, xx binding didn't match xx varref:");
L
Luqman Aden 已提交
2235 2236 2237
                println!("this is xx varref \\# {}", idx);
                println!("binding: {}", cxbind);
                println!("resolves to: {}", resolved_binding);
2238
                println!("varref: {}", v.segments[0].identifier);
L
Luqman Aden 已提交
2239
                println!("resolves to: {}",
2240
                         mtwt::resolve(v.segments[0].identifier));
2241
                mtwt::with_sctable(|x| mtwt::display_sctable(x));
J
John Clements 已提交
2242
            }
2243
            assert_eq!(mtwt::resolve(v.segments[0].identifier),
2244
                       resolved_binding);
J
John Clements 已提交
2245 2246 2247
        };
    }

J
John Clements 已提交
2248 2249
    #[test]
    fn pat_idents(){
2250
        let pat = string_to_pat(
2251
            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
2252
        let idents = pattern_bindings(&*pat);
2253
        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
J
John Clements 已提交
2254
    }
J
John Clements 已提交
2255

2256 2257 2258
    // test the list of identifier patterns gathered by the visitor. Note that
    // 'None' is listed as an identifier pattern because we don't yet know that
    // it's the name of a 0-ary variant, and that 'i' appears twice in succession.
2259
    #[test]
2260
    fn crate_bindings_test(){
2261
        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
2262
        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
2263 2264
        let idents = crate_bindings(&the_crate);
        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
2265 2266
    }

2267 2268 2269
    // test the IdentRenamer directly
    #[test]
    fn ident_renamer_test () {
2270
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
2271 2272
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
2273
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
2274
        let renames = vec!((x_ident,Name(16)));
2275 2276 2277 2278
        let mut renamer = IdentRenamer{renames: &renames};
        let renamed_crate = renamer.fold_crate(the_crate);
        let idents = crate_idents(&renamed_crate);
        let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
2279
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
2280 2281 2282 2283 2284
    }

    // test the PatIdentRenamer; only PatIdents get renamed
    #[test]
    fn pat_ident_renamer_test () {
2285
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
2286 2287
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
2288
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
2289
        let renames = vec!((x_ident,Name(16)));
2290 2291 2292 2293 2294
        let mut renamer = PatIdentRenamer{renames: &renames};
        let renamed_crate = renamer.fold_crate(the_crate);
        let idents = crate_idents(&renamed_crate);
        let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
        let x_name = x_ident.name;
2295
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
2296
    }
J
John Clements 已提交
2297
}