expand.rs 71.6 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, Mac_, Name};
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, WithAttrs};
21
use codemap;
22
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
P
Patrick Walton 已提交
23
use ext::base::*;
24
use feature_gate::{self, Features, GatedCfg};
J
John Clements 已提交
25
use fold;
26
use fold::*;
M
Marvin Löbel 已提交
27
use util::move_map::MoveMap;
28
use parse;
29
use parse::token::{fresh_mark, fresh_name, intern};
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
use std::collections::HashSet;

38

39
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
40
    let expr_span = e.span;
41
    return e.and_then(|ast::Expr {id, node, span, attrs}| match node {
42

43 44
        // expr_mac should really be expr_ext or something; it's the
        // entry-point for all syntax extensions.
45
        ast::ExprMac(mac) => {
46

47 48
            // FIXME: for now, drop attributes on the macro itself
            drop(attrs);
49

50 51 52
            let expanded_expr = match expand_mac_invoc(mac, span,
                                                       |r| r.make_expr(),
                                                       mark_expr, fld) {
J
John Clements 已提交
53 54
                Some(expr) => expr,
                None => {
55
                    return DummyResult::raw_expr(span);
J
John Clements 已提交
56 57
                }
            };
58

J
John Clements 已提交
59
            // Keep going, outside-in.
60
            let fully_expanded = fld.fold_expr(expanded_expr);
N
Nick Cameron 已提交
61
            let span = fld.new_span(span);
J
John Clements 已提交
62
            fld.cx.bt_pop();
63

64
            fully_expanded.map(|e| ast::Expr {
J
John Clements 已提交
65
                id: ast::DUMMY_NODE_ID,
66
                node: e.node,
67
                span: span,
68
                attrs: e.attrs,
69
            })
70
        }
71

72
        ast::ExprInPlace(placer, value_expr) => {
73 74 75 76 77 78
            // Ensure feature-gate is enabled
            feature_gate::check_for_placement_in(
                fld.cx.ecfg.features,
                &fld.cx.parse_sess.span_diagnostic,
                expr_span);

79
            let placer = fld.fold_expr(placer);
80
            let value_expr = fld.fold_expr(value_expr);
N
Nick Cameron 已提交
81
            fld.cx.expr(span, ast::ExprInPlace(placer, value_expr))
82
                .with_attrs(fold_thin_attrs(attrs, fld))
83 84
        }

P
Pythoner6 已提交
85 86 87
        ast::ExprWhile(cond, body, opt_ident) => {
            let cond = fld.fold_expr(cond);
            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
88
            fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
89
                .with_attrs(fold_thin_attrs(attrs, fld))
P
Pythoner6 已提交
90 91
        }

J
John Gallagher 已提交
92
        ast::ExprWhileLet(pat, expr, body, opt_ident) => {
N
Nick Cameron 已提交
93 94
            let pat = fld.fold_pat(pat);
            let expr = fld.fold_expr(expr);
95 96 97 98 99 100 101 102 103 104 105 106

            // Hygienic renaming of the body.
            let ((body, opt_ident), mut rewritten_pats) =
                rename_in_scope(vec![pat],
                                fld,
                                (body, opt_ident),
                                |rename_fld, fld, (body, opt_ident)| {
                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
            });
            assert!(rewritten_pats.len() == 1);

            fld.cx.expr(span, ast::ExprWhileLet(rewritten_pats.remove(0), expr, body, opt_ident))
107
                .with_attrs(fold_thin_attrs(attrs, fld))
108 109
        }

E
Edward Wang 已提交
110
        ast::ExprLoop(loop_block, opt_ident) => {
111
            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
112
            fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
113
                .with_attrs(fold_thin_attrs(attrs, fld))
E
Edward Wang 已提交
114 115
        }

116
        ast::ExprForLoop(pat, head, body, opt_ident) => {
117
            let pat = fld.fold_pat(pat);
118 119 120 121 122 123 124 125 126 127 128

            // Hygienic renaming of the for loop body (for loop binds its pattern).
            let ((body, opt_ident), mut rewritten_pats) =
                rename_in_scope(vec![pat],
                                fld,
                                (body, opt_ident),
                                |rename_fld, fld, (body, opt_ident)| {
                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
            });
            assert!(rewritten_pats.len() == 1);

129
            let head = fld.fold_expr(head);
130
            fld.cx.expr(span, ast::ExprForLoop(rewritten_pats.remove(0), head, body, opt_ident))
131
                .with_attrs(fold_thin_attrs(attrs, fld))
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
        }

        ast::ExprIfLet(pat, sub_expr, body, else_opt) => {
            let pat = fld.fold_pat(pat);

            // Hygienic renaming of the body.
            let (body, mut rewritten_pats) =
                rename_in_scope(vec![pat],
                                fld,
                                body,
                                |rename_fld, fld, body| {
                fld.fold_block(rename_fld.fold_block(body))
            });
            assert!(rewritten_pats.len() == 1);

            let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt));
            let sub_expr = fld.fold_expr(sub_expr);
            fld.cx.expr(span, ast::ExprIfLet(rewritten_pats.remove(0), sub_expr, body, else_opt))
150
                .with_attrs(fold_thin_attrs(attrs, fld))
151 152
        }

153
        ast::ExprClosure(capture_clause, fn_decl, block) => {
154
            let (rewritten_fn_decl, rewritten_block)
155
                = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
156
            let new_node = ast::ExprClosure(capture_clause,
157 158
                                            rewritten_fn_decl,
                                            rewritten_block);
159
            P(ast::Expr{id:id, node: new_node, span: fld.new_span(span),
160
                        attrs: fold_thin_attrs(attrs, fld)})
161 162
        }

163 164 165 166
        _ => {
            P(noop_fold_expr(ast::Expr {
                id: id,
                node: node,
167
                span: span,
168 169
                attrs: attrs
            }, fld))
170
        }
171
    });
172 173
}

J
John Clements 已提交
174 175 176 177
/// 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.
178 179
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                             span: codemap::Span,
J
Jorge Aparicio 已提交
180 181 182 183
                             parse_thunk: F,
                             mark_thunk: G,
                             fld: &mut MacroExpander)
                             -> Option<T> where
184
    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
J
Jorge Aparicio 已提交
185
    G: FnOnce(T, Mrk) -> T,
186
{
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    // 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.

    let Mac_ { path: pth, tts, .. } = mac.node;
    if pth.segments.len() > 1 {
        fld.cx.span_err(pth.span,
                        "expected macro name without module \
                        separators");
        // let compilation continue
        return None;
    }
    let extname = pth.segments[0].identifier.name;
202
    match fld.cx.syntax_env.find(extname) {
203 204 205 206 207
        None => {
            fld.cx.span_err(
                pth.span,
                &format!("macro undefined: '{}!'",
                        &extname));
J
John Clements 已提交
208

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
            // let compilation continue
            None
        }
        Some(rc) => match *rc {
            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                fld.cx.bt_push(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
                            format: MacroBang(extname),
                            span: exp_span,
                            allow_internal_unstable: allow_internal_unstable,
                        },
                    });
                let fm = fresh_mark();
                let marked_before = mark_tts(&tts[..], fm);

                // 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.
                let mac_span = fld.cx.original_span();

                let opt_parsed = {
                    let expanded = expandfun.expand(fld.cx,
                                                    mac_span,
                                                    &marked_before[..]);
                    parse_thunk(expanded)
                };
                let parsed = match opt_parsed {
                    Some(e) => e,
                    None => {
240 241
                        fld.cx.span_err(
                            pth.span,
242 243 244 245
                            &format!("non-expression macro in expression position: {}",
                                    extname
                                    ));
                        return None;
246
                    }
247 248 249 250 251 252 253 254 255
                };
                Some(mark_thunk(parsed,fm))
            }
            _ => {
                fld.cx.span_err(
                    pth.span,
                    &format!("'{}' is not a tt-style macro",
                            extname));
                None
J
John Clements 已提交
256 257 258 259 260
            }
        }
    }
}

261 262 263 264 265
/// 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.
266 267 268
fn expand_loop_block(loop_block: P<Block>,
                     opt_ident: Option<Ident>,
                     fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
E
Edward Wang 已提交
269 270
    match opt_ident {
        Some(label) => {
271
            let new_label = fresh_name(label);
E
Edward Wang 已提交
272
            let rename = (label, new_label);
273 274 275 276 277 278

            // 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);
279
            let mut rename_fld = IdentRenamer{renames: &mut rename_list};
280 281 282 283 284
            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.
285 286
            fld.cx.syntax_env.push_frame();
            fld.cx.syntax_env.info().pending_renames.push(rename);
287
            let expanded_block = expand_block_elts(loop_block, fld);
288
            fld.cx.syntax_env.pop_frame();
289 290

            (expanded_block, Some(renamed_ident))
E
Edward Wang 已提交
291
        }
292
        None => (fld.fold_block(loop_block), opt_ident)
E
Edward Wang 已提交
293 294 295
    }
}

296 297
// eval $e with a new exts frame.
// must be a macro so that $e isn't evaluated too early.
298
macro_rules! with_exts_frame {
299
    ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
S
Steven Fackler 已提交
300 301
    ({$extsboxexpr.push_frame();
      $extsboxexpr.info().macros_escape = $macros_escape;
J
John Clements 已提交
302
      let result = $e;
S
Steven Fackler 已提交
303
      $extsboxexpr.pop_frame();
J
John Clements 已提交
304 305
      result
     })
306
}
J
John Clements 已提交
307

308
// When we enter a module, record it, for the sake of `module!`
309 310
pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
                   -> SmallVector<P<ast::Item>> {
311
    let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
312

313
    expand_annotatable(it, fld)
314
        .into_iter().map(|i| i.expect_item()).collect()
315 316
}

J
John Clements 已提交
317
/// Expand item_underscore
318 319
fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
    match item {
320
        ast::ItemFn(decl, unsafety, constness, abi, generics, body) => {
J
John Clements 已提交
321
            let (rewritten_fn_decl, rewritten_body)
322
                = expand_and_rename_fn_decl_and_block(decl, body, fld);
M
Marvin Löbel 已提交
323
            let expanded_generics = fold::noop_fold_generics(generics,fld);
324 325
            ast::ItemFn(rewritten_fn_decl, unsafety, constness, abi,
                        expanded_generics, rewritten_body)
J
John Clements 已提交
326
        }
327
        _ => noop_fold_item_underscore(item, fld)
J
John Clements 已提交
328 329 330
    }
}

331 332
// does this attribute list contain "macro_use" ?
fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
333
    for attr in attrs {
334 335 336 337
        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;
338
            if let ast::AttrStyle::Inner = attr.node.style {
339
                fld.cx.fileline_help(attr.span, "consider an outer attribute, \
340 341 342 343 344 345 346 347 348 349 350 351 352
                                             #[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 已提交
353 354
}

355 356
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
357 358
pub fn expand_item_mac(it: P<ast::Item>,
                       fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
359 360 361
    let (extname, path_span, tts, span, attrs, ident) = it.and_then(|it| match it.node {
        ItemMac(codemap::Spanned { node: Mac_ { path, tts, .. }, .. }) =>
            (path.segments[0].identifier.name, path.span, tts, it.span, it.attrs, it.ident),
362
        _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
363
    });
364

365
    let fm = fresh_mark();
366
    let items = {
367
        let expanded = match fld.cx.syntax_env.find(extname) {
368
            None => {
369
                fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
370
                                &format!("macro undefined: '{}!'",
371
                                        extname));
372 373 374
                // let compilation continue
                return SmallVector::zero();
            }
375

376
            Some(rc) => match *rc {
377 378
                NormalTT(ref expander, tt_span, allow_internal_unstable) => {
                    if ident.name != parse::token::special_idents::invalid.name {
379
                        fld.cx
380
                            .span_err(path_span,
381
                                      &format!("macro {}! expects no ident argument, given '{}'",
382
                                               extname,
383
                                               ident));
384 385 386
                        return SmallVector::zero();
                    }
                    fld.cx.bt_push(ExpnInfo {
387
                        call_site: span,
388
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
389
                            format: MacroBang(extname),
390
                            span: tt_span,
391
                            allow_internal_unstable: allow_internal_unstable,
392 393 394
                        }
                    });
                    // mark before expansion:
395
                    let marked_before = mark_tts(&tts[..], fm);
396
                    expander.expand(fld.cx, span, &marked_before[..])
397
                }
398 399
                IdentTT(ref expander, tt_span, allow_internal_unstable) => {
                    if ident.name == parse::token::special_idents::invalid.name {
400
                        fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
401
                                        &format!("macro {}! expects an ident argument",
402
                                                extname));
403
                        return SmallVector::zero();
404
                    }
405
                    fld.cx.bt_push(ExpnInfo {
406
                        call_site: span,
407
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
408
                            format: MacroBang(extname),
409
                            span: tt_span,
410
                            allow_internal_unstable: allow_internal_unstable,
411 412 413
                        }
                    });
                    // mark before expansion:
414
                    let marked_tts = mark_tts(&tts[..], fm);
415
                    expander.expand(fld.cx, span, ident, marked_tts)
416
                }
417
                MacroRulesTT => {
418
                    if ident.name == parse::token::special_idents::invalid.name {
S
Steve Klabnik 已提交
419
                        fld.cx.span_err(path_span, "macro_rules! expects an ident argument");
420
                        return SmallVector::zero();
421
                    }
422

423
                    fld.cx.bt_push(ExpnInfo {
424
                        call_site: span,
425
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
426
                            format: MacroBang(extname),
427
                            span: None,
428 429 430 431
                            // `macro_rules!` doesn't directly allow
                            // unstable (this is orthogonal to whether
                            // the macro it creates allows it)
                            allow_internal_unstable: false,
432 433
                        }
                    });
434
                    // DON'T mark before expansion.
435

436
                    let allow_internal_unstable = attr::contains_name(&attrs,
437 438 439 440 441 442 443 444 445
                                                                      "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",
446
                            span,
447
                            feature_gate::GateIssue::Language,
448 449 450
                            feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
                    }

451
                    let export = attr::contains_name(&attrs, "macro_export");
452
                    let def = ast::MacroDef {
453 454
                        ident: ident,
                        attrs: attrs,
455
                        id: ast::DUMMY_NODE_ID,
456
                        span: span,
457
                        imported_from: None,
458
                        export: export,
K
Keegan McAllister 已提交
459
                        use_locally: true,
460
                        allow_internal_unstable: allow_internal_unstable,
461 462
                        body: tts,
                    };
463
                    fld.cx.insert_macro(def);
464 465 466 467

                    // macro_rules! has a side effect but expands to nothing.
                    fld.cx.bt_pop();
                    return SmallVector::zero();
468 469
                }
                _ => {
470
                    fld.cx.span_err(span,
J
Jorge Aparicio 已提交
471
                                    &format!("{}! is not legal in item position",
472
                                            extname));
473
                    return SmallVector::zero();
474
                }
J
John Clements 已提交
475
            }
476 477
        };

478
        expanded.make_items()
479
    };
480

481 482
    let items = match items {
        Some(items) => {
A
Aaron Turon 已提交
483
            items.into_iter()
484
                .map(|i| mark_item(i, fm))
A
Aaron Turon 已提交
485
                .flat_map(|i| fld.fold_item(i).into_iter())
486 487
                .collect()
        }
488
        None => {
489
            fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
490
                            &format!("non-item macro in item position: {}",
491
                                    extname));
492
            return SmallVector::zero();
493
        }
494
    };
495

496
    fld.cx.bt_pop();
497
    items
498 499
}

J
John Clements 已提交
500
/// Expand a stmt
501 502
fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
    let stmt = stmt.and_then(|stmt| stmt);
503 504
    let (mac, style, attrs) = match stmt.node {
        StmtMac(mac, style, attrs) => (mac, style, attrs),
505
        _ => return expand_non_macro_stmt(stmt, fld)
506
    };
507

508 509
    // FIXME: for now, drop attrs on macros.
    drop(attrs);
510

511 512 513 514 515 516
    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);

517
    let mut fully_expanded = match maybe_new_items {
518 519
        Some(stmts) => {
            // Keep going, outside-in.
520
            let new_items = stmts.into_iter().flat_map(|s| {
521
                fld.fold_stmt(s).into_iter()
522 523 524
            }).collect();
            fld.cx.bt_pop();
            new_items
525
        }
526
        None => SmallVector::zero()
527 528
    };

529 530
    // If this is a macro invocation with a semicolon, then apply that
    // semicolon to the final statement produced by expansion.
531
    if style == MacStmtWithSemicolon {
532 533 534 535 536 537 538 539 540 541 542
        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);
543
        }
544
    }
545 546

    fully_expanded
547 548
}

549 550
// expand a non-macro stmt. this is essentially the fallthrough for
// expand_stmt, above.
551 552
fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroExpander)
                         -> SmallVector<P<Stmt>> {
553
    // is it a let?
554 555 556 557
    match node {
        StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl {
            DeclLocal(local) => {
                // take it apart:
558
                let rewritten_local = local.map(|Local {id, pat, ty, init, span, attrs}| {
559 560
                    // expand the ty since TyFixedLengthVec contains an Expr
                    // and thus may have a macro use
S
Seo Sanghyeon 已提交
561
                    let expanded_ty = ty.map(|t| fld.fold_ty(t));
562
                    // expand the pat (it might contain macro uses):
563
                    let expanded_pat = fld.fold_pat(pat);
564
                    // find the PatIdents in the pattern:
565 566 567 568
                    // 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
S
Seo Sanghyeon 已提交
569
                    let idents = pattern_bindings(&expanded_pat);
570
                    let mut new_pending_renames =
571
                        idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect();
572 573
                    // rewrite the pattern using the new names (the old
                    // ones have already been applied):
574
                    let rewritten_pat = {
575 576
                        // nested binding to allow borrow to expire:
                        let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
577 578 579
                        rename_fld.fold_pat(expanded_pat)
                    };
                    // add them to the existing pending renames:
580
                    fld.cx.syntax_env.info().pending_renames
581
                          .extend(new_pending_renames);
582 583 584 585 586 587
                    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)),
588 589
                        span: span,
                        attrs: attrs
590 591 592 593 594 595 596 597 598 599
                    }
                });
                SmallVector::one(P(Spanned {
                    node: StmtDecl(P(Spanned {
                            node: DeclLocal(rewritten_local),
                            span: span
                        }),
                        node_id),
                    span: stmt_span
                }))
S
Steven Fackler 已提交
600
            }
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
            _ => {
                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)
        }
618 619 620
    }
}

J
John Clements 已提交
621
// expand the arm of a 'match', renaming for macro hygiene
622
fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
623
    // expand pats... they might contain macro uses:
624
    let expanded_pats = arm.pats.move_map(|pat| fld.fold_pat(pat));
625
    if expanded_pats.is_empty() {
S
Steve Klabnik 已提交
626
        panic!("encountered match arm with 0 patterns");
J
John Clements 已提交
627
    }
628

629
    // apply renaming and then expansion to the guard and the body:
630 631 632 633 634 635 636 637 638 639
    let ((rewritten_guard, rewritten_body), rewritten_pats) =
        rename_in_scope(expanded_pats,
                        fld,
                        (arm.guard, arm.body),
                        |rename_fld, fld, (ag, ab)|{
        let rewritten_guard = ag.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
        let rewritten_body = fld.fold_expr(rename_fld.fold_expr(ab));
        (rewritten_guard, rewritten_body)
    });

J
John Clements 已提交
640
    ast::Arm {
641
        attrs: fold::fold_attrs(arm.attrs, fld),
642 643 644
        pats: rewritten_pats,
        guard: rewritten_guard,
        body: rewritten_body,
J
John Clements 已提交
645
    }
J
John Clements 已提交
646 647
}

648 649 650 651 652 653 654 655 656
fn rename_in_scope<X, F>(pats: Vec<P<ast::Pat>>,
                         fld: &mut MacroExpander,
                         x: X,
                         f: F)
                         -> (X, Vec<P<ast::Pat>>)
    where F: Fn(&mut IdentRenamer, &mut MacroExpander, X) -> X
{
    // all of the pats must have the same set of bindings, so use the
    // first one to extract them and generate new names:
S
Seo Sanghyeon 已提交
657
    let idents = pattern_bindings(&pats[0]);
658 659 660 661 662 663 664 665 666
    let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect();
    // apply the renaming, but only to the PatIdents:
    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
    let rewritten_pats = pats.move_map(|pat| rename_pats_fld.fold_pat(pat));

    let mut rename_fld = IdentRenamer{ renames:&new_renames };
    (f(&mut rename_fld, fld, x), rewritten_pats)
}

667 668 669
/// A visitor that extracts the PatIdent (binding) paths
/// from a given thingy and puts them in a mutable
/// array
670
#[derive(Clone)]
671
struct PatIdentFinder {
672
    ident_accumulator: Vec<ast::Ident>
673 674
}

675
impl<'v> Visitor<'v> for PatIdentFinder {
676
    fn visit_pat(&mut self, pattern: &ast::Pat) {
677
        match *pattern {
678
            ast::Pat { id: _, node: ast::PatIdent(_, ref path1, ref inner), span: _ } => {
679
                self.ident_accumulator.push(path1.node);
680
                // visit optional subpattern of PatIdent:
681
                if let Some(ref subpat) = *inner {
S
Seo Sanghyeon 已提交
682
                    self.visit_pat(subpat)
J
John Clements 已提交
683 684
                }
            }
685
            // use the default traversal for non-PatIdents
686
            _ => visit::walk_pat(self, pattern)
687 688 689 690
        }
    }
}

691
/// find the PatIdent paths in a pattern
692
fn pattern_bindings(pat: &ast::Pat) -> Vec<ast::Ident> {
693
    let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
694
    name_finder.visit_pat(pat);
695
    name_finder.ident_accumulator
696 697
}

J
John Clements 已提交
698 699 700
/// 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()};
701
    for arg in &fn_decl.inputs {
S
Seo Sanghyeon 已提交
702
        pat_idents.visit_pat(&arg.pat);
J
John Clements 已提交
703 704 705 706
    }
    pat_idents.ident_accumulator
}

J
John Clements 已提交
707
// expand a block. pushes a new exts_frame, then calls expand_block_elts
708
pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {
709
    // see note below about treatment of exts table
710
    with_exts_frame!(fld.cx.syntax_env,false,
711
                     expand_block_elts(blk, fld))
712 713
}

J
John Clements 已提交
714
// expand the elements of a block.
715
pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
716
    b.map(|Block {id, stmts, expr, rules, span}| {
A
Aaron Turon 已提交
717
        let new_stmts = stmts.into_iter().flat_map(|x| {
718
            // perform all pending renames
719
            let renamed_stmt = {
720
                let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
721
                let mut rename_fld = IdentRenamer{renames:pending_renames};
722
                rename_fld.fold_stmt(x).expect_one("rename_fold didn't return one value")
723
            };
724
            // expand macros in the statement
A
Aaron Turon 已提交
725
            fld.fold_stmt(renamed_stmt).into_iter()
726
        }).collect();
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
        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
        }
742
    })
J
John Clements 已提交
743 744
}

745 746 747 748
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 已提交
749
    }
750 751
    p.map(|ast::Pat {node, span, ..}| {
        let (pth, tts) = match node {
752
            PatMac(mac) => (mac.node.path, mac.node.tts),
753 754
            _ => unreachable!()
        };
755
        if pth.segments.len() > 1 {
756 757
            fld.cx.span_err(pth.span, "expected macro name without module separators");
            return DummyResult::raw_pat(span);
K
Keegan McAllister 已提交
758
        }
759
        let extname = pth.segments[0].identifier.name;
760
        let marked_after = match fld.cx.syntax_env.find(extname) {
761 762
            None => {
                fld.cx.span_err(pth.span,
J
Jorge Aparicio 已提交
763
                                &format!("macro undefined: '{}!'",
764
                                        extname));
765 766 767
                // let compilation continue
                return DummyResult::raw_pat(span);
            }
K
Keegan McAllister 已提交
768

769
            Some(rc) => match *rc {
770
                NormalTT(ref expander, tt_span, allow_internal_unstable) => {
771 772 773
                    fld.cx.bt_push(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
774
                            format: MacroBang(extname),
775 776
                            span: tt_span,
                            allow_internal_unstable: allow_internal_unstable,
777 778
                        }
                    });
K
Keegan McAllister 已提交
779

780
                    let fm = fresh_mark();
781
                    let marked_before = mark_tts(&tts[..], fm);
782
                    let mac_span = fld.cx.original_span();
783 784 785 786
                    let pat = expander.expand(fld.cx,
                                              mac_span,
                                              &marked_before[..]).make_pat();
                    let expanded = match pat {
787 788 789 790
                        Some(e) => e,
                        None => {
                            fld.cx.span_err(
                                pth.span,
J
Jorge Aparicio 已提交
791
                                &format!(
792
                                    "non-pattern macro in pattern position: {}",
793
                                    extname
794
                                    )
795 796 797 798
                            );
                            return DummyResult::raw_pat(span);
                        }
                    };
799

800 801 802 803 804
                    // mark after:
                    mark_pat(expanded,fm)
                }
                _ => {
                    fld.cx.span_err(span,
J
Jorge Aparicio 已提交
805
                                    &format!("{}! is not legal in pattern position",
806
                                            extname));
807 808
                    return DummyResult::raw_pat(span);
                }
809
            }
810
        };
K
Keegan McAllister 已提交
811

812 813 814
        let fully_expanded =
            fld.fold_pat(marked_after).node.clone();
        fld.cx.bt_pop();
K
Keegan McAllister 已提交
815

816 817 818 819 820 821
        ast::Pat {
            id: ast::DUMMY_NODE_ID,
            node: fully_expanded,
            span: span
        }
    })
K
Keegan McAllister 已提交
822 823
}

J
John Clements 已提交
824 825 826
/// 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)
827
pub struct IdentRenamer<'a> {
828
    renames: &'a mtwt::RenameList,
829 830
}

831
impl<'a> Folder for IdentRenamer<'a> {
832
    fn fold_ident(&mut self, id: Ident) -> Ident {
833
        Ident::new(id.name, mtwt::apply_renames(self.renames, id.ctxt))
834
    }
K
Keegan McAllister 已提交
835 836
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
837
    }
838 839
}

J
John Clements 已提交
840 841 842 843 844 845 846 847 848
/// 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> {
849
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
J
John Clements 已提交
850
        match pat.node {
851 852 853 854 855 856
            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) => {
857 858
                let new_ident = Ident::new(ident.name,
                                           mtwt::apply_renames(self.renames, ident.ctxt));
J
John Clements 已提交
859 860
                let new_node =
                    ast::PatIdent(binding_mode,
861
                                  Spanned{span: self.new_span(sp), node: new_ident},
J
John Clements 已提交
862
                                  sub.map(|p| self.fold_pat(p)));
863 864
                ast::Pat {
                    id: id,
J
John Clements 已提交
865
                    node: new_node,
866
                    span: self.new_span(span)
J
John Clements 已提交
867 868
                }
            },
869 870
            _ => unreachable!()
        })
871
    }
K
Keegan McAllister 已提交
872 873
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
874
    }
K
Kevin Atkinson 已提交
875 876
}

877 878 879 880 881 882 883
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();
884
    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
885 886 887 888 889 890 891 892 893 894 895 896 897

    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);
                }
898
                let macro_use = contains_macro_use(fld, &new_attrs[..]);
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
                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()
            }
        },
915

916
        Annotatable::TraitItem(it) => match it.node {
917 918 919 920 921 922 923 924 925
            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))
                    }
926
                    _ => unreachable!()
927 928 929 930 931 932
                },
                span: fld.new_span(ti.span)
            })),
            _ => fold::noop_fold_trait_item(it, fld)
        }.into_iter().map(Annotatable::TraitItem).collect(),

933
        Annotatable::ImplItem(ii) => {
934
            expand_impl_item(ii, fld).into_iter().map(Annotatable::ImplItem).collect()
935 936 937
        }
    };

938
    new_items.push_all(decorator_items);
939 940 941
    new_items
}

942 943 944 945 946 947 948 949
// 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| {
950
                match fld.cx.syntax_env.find(intern(&attr.name())) {
951 952 953 954 955 956 957
                    Some(rc) => match *rc {
                        $variant(..) => true,
                        _ => false
                    },
                    _ => false
                }
            })
958
        }
959
    }
960 961
}

962 963 964 965 966 967 968 969 970
partition!(multi_modifiers, MultiModifier);


fn expand_decorators(a: Annotatable,
                     fld: &mut MacroExpander,
                     decorator_items: &mut SmallVector<Annotatable>,
                     new_attrs: &mut Vec<ast::Attribute>)
{
    for attr in a.attrs() {
M
Manish Goregaokar 已提交
971
        let mname = intern(&attr.name());
972
        match fld.cx.syntax_env.find(mname) {
973
            Some(rc) => match *rc {
974 975 976 977 978 979
                MultiDecorator(ref dec) => {
                    attr::mark_used(&attr);

                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
980
                            format: MacroAttribute(mname),
981 982 983 984 985 986 987 988 989 990 991 992 993
                            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,
994
                               &a,
995 996 997 998 999 1000 1001
                               &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()),
1002
            },
1003
            _ => new_attrs.push((*attr).clone()),
1004
        }
1005
    }
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
}

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
    }

1020
    for attr in &modifiers {
M
Manish Goregaokar 已提交
1021
        let mname = intern(&attr.name());
1022

1023
        match fld.cx.syntax_env.find(mname) {
1024 1025 1026 1027 1028 1029
            Some(rc) => match *rc {
                MultiModifier(ref mac) => {
                    attr::mark_used(attr);
                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
1030
                            format: MacroAttribute(mname),
1031
                            span: Some(attr.span),
1032 1033 1034
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
                        }
                    });
                    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)
}

1050
fn expand_impl_item(ii: P<ast::ImplItem>, fld: &mut MacroExpander)
1051 1052
                 -> SmallVector<P<ast::ImplItem>> {
    match ii.node {
1053
        ast::ImplItemKind::Method(..) => SmallVector::one(ii.map(|ii| ast::ImplItem {
1054 1055 1056 1057 1058
            id: ii.id,
            ident: ii.ident,
            attrs: ii.attrs,
            vis: ii.vis,
            node: match ii.node  {
1059
                ast::ImplItemKind::Method(sig, body) => {
1060
                    let (sig, body) = expand_and_rename_method(sig, body, fld);
1061
                    ast::ImplItemKind::Method(sig, body)
1062 1063 1064 1065 1066
                }
                _ => unreachable!()
            },
            span: fld.new_span(ii.span)
        })),
1067
        ast::ImplItemKind::Macro(_) => {
1068
            let (span, mac) = ii.and_then(|ii| match ii.node {
1069
                ast::ImplItemKind::Macro(mac) => (ii.span, mac),
1070 1071
                _ => unreachable!()
            });
1072
            let maybe_new_items =
1073
                expand_mac_invoc(mac, span,
1074 1075
                                 |r| r.make_impl_items(),
                                 |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
J
John Clements 已提交
1076 1077
                                 fld);

1078 1079
            match maybe_new_items {
                Some(impl_items) => {
A
Adolfo Ochagavía 已提交
1080
                    // expand again if necessary
1081 1082 1083
                    let new_items = impl_items.into_iter().flat_map(|ii| {
                        expand_impl_item(ii, fld).into_iter()
                    }).collect();
A
Adolfo Ochagavía 已提交
1084
                    fld.cx.bt_pop();
1085
                    new_items
A
Adolfo Ochagavía 已提交
1086
                }
J
John Clements 已提交
1087
                None => SmallVector::zero()
A
Adolfo Ochagavía 已提交
1088
            }
1089
        }
1090
        _ => fold::noop_fold_impl_item(ii, fld)
1091
    }
1092 1093
}

J
John Clements 已提交
1094 1095 1096
/// 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.
1097
fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Block>,
J
John Clements 已提交
1098
                                       fld: &mut MacroExpander)
1099
                                       -> (P<ast::FnDecl>, P<ast::Block>) {
J
John Clements 已提交
1100
    let expanded_decl = fld.fold_fn_decl(fn_decl);
S
Seo Sanghyeon 已提交
1101
    let idents = fn_decl_arg_bindings(&expanded_decl);
J
John Clements 已提交
1102
    let renames =
1103
        idents.iter().map(|id| (*id,fresh_name(*id))).collect();
J
John Clements 已提交
1104 1105
    // first, a renamer for the PatIdents, for the fn_decl:
    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
1106
    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
J
John Clements 已提交
1107 1108 1109 1110 1111 1112
    // 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)
}

1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
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 已提交
1123
        constness: sig.constness,
1124 1125 1126 1127
        decl: rewritten_fn_decl
    }, rewritten_body)
}

1128 1129 1130
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 已提交
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
            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);
                    }
                };
1141

J
Jared Roesch 已提交
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
                // 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,
1156 1157
                    feature_gate::GateIssue::Language,
                    "type macros are experimental");
J
Jared Roesch 已提交
1158 1159

                DummyResult::raw_ty(t.span)
J
Jared Roesch 已提交
1160
            }
1161 1162 1163
        }
        _ => t
    };
J
Jared Roesch 已提交
1164

1165 1166 1167
    fold::noop_fold_ty(t, fld)
}

J
John Clements 已提交
1168
/// A tree-folder that performs macro expansion
1169
pub struct MacroExpander<'a, 'b:'a> {
1170
    pub cx: &'a mut ExtCtxt<'b>,
N
Nick Cameron 已提交
1171 1172 1173 1174
}

impl<'a, 'b> MacroExpander<'a, 'b> {
    pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1175
        MacroExpander { cx: cx }
N
Nick Cameron 已提交
1176
    }
1177 1178
}

E
Eduard Burtescu 已提交
1179
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1180
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1181
        expand_expr(expr, self)
1182 1183
    }

1184
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
K
Keegan McAllister 已提交
1185 1186 1187
        expand_pat(pat, self)
    }

1188
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1189
        expand_item(item, self)
1190 1191
    }

1192
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
J
John Clements 已提交
1193 1194 1195
        expand_item_underscore(item, self)
    }

1196
    fn fold_stmt(&mut self, stmt: P<ast::Stmt>) -> SmallVector<P<ast::Stmt>> {
1197
        expand_stmt(stmt, self)
1198 1199
    }

S
Steven Fackler 已提交
1200
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1201
        expand_block(block, self)
1202 1203
    }

1204
    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
J
John Clements 已提交
1205 1206 1207
        expand_arm(arm, self)
    }

1208 1209 1210
    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()
1211 1212
    }

1213 1214 1215
    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()
1216 1217
    }

1218 1219 1220 1221
    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
        expand_type(ty, self)
    }

S
Steven Fackler 已提交
1222
    fn new_span(&mut self, span: Span) -> Span {
1223 1224
        new_span(self.cx, span)
    }
1225 1226
}

J
John Clements 已提交
1227 1228 1229 1230 1231
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,
1232
        expn_id: cx.backtrace(),
J
John Clements 已提交
1233 1234 1235
    }
}

1236
pub struct ExpansionConfig<'feat> {
1237
    pub crate_name: String,
1238
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1239
    pub recursion_limit: usize,
1240
    pub trace_mac: bool,
1241 1242
}

1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1256 1257
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1258 1259
        ExpansionConfig {
            crate_name: crate_name,
1260
            features: None,
1261
            recursion_limit: 64,
1262
            trace_mac: false,
1263 1264
        }
    }
1265

1266 1267 1268 1269 1270 1271 1272
    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,
1273
        fn enable_custom_derive = allow_custom_derive,
1274
        fn enable_pushpop_unsafe = allow_pushpop_unsafe,
1275
    }
1276 1277
}

1278 1279 1280 1281 1282
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>,
1283
                           feature_gated_cfgs: &mut Vec<GatedCfg>,
1284
                           c: Crate) -> (Crate, HashSet<Name>) {
1285 1286
    let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg,
                              feature_gated_cfgs);
A
Alex Crichton 已提交
1287 1288 1289 1290 1291 1292 1293
    if std_inject::no_core(&c) {
        cx.crate_root = None;
    } else if std_inject::no_std(&c) {
        cx.crate_root = Some("core");
    } else {
        cx.crate_root = Some("std");
    }
1294 1295
    let ret = {
        let mut expander = MacroExpander::new(&mut cx);
1296

1297 1298 1299
        for def in imported_macros {
            expander.cx.insert_macro(def);
        }
1300

1301 1302 1303
        for (name, extension) in user_exts {
            expander.cx.syntax_env.insert(name, extension);
        }
1304

1305 1306 1307 1308 1309 1310
        let mut ret = expander.fold_crate(c);
        ret.exported_macros = expander.cx.exported_macros.clone();
        parse_sess.span_diagnostic.handler().abort_if_errors();
        ret
    };
    return (ret, cx.syntax_env.names);
1311
}
J
John Clements 已提交
1312

1313 1314 1315 1316 1317 1318 1319 1320
// 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 已提交
1321 1322
// A Marker adds the given mark to the syntax context
struct Marker { mark: Mrk }
1323

E
Eduard Burtescu 已提交
1324
impl Folder for Marker {
1325
    fn fold_ident(&mut self, id: Ident) -> Ident {
1326
        ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt))
1327
    }
1328
    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1329
        Spanned {
1330 1331 1332 1333
            node: Mac_ {
                path: self.fold_path(node.path),
                tts: self.fold_tts(&node.tts),
                ctxt: mtwt::apply_mark(self.mark, node.ctxt),
1334 1335
            },
            span: span,
1336
        }
1337 1338 1339
    }
}

1340
// apply a given mark to the given token trees. Used prior to expansion of a macro.
1341
fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
M
Marvin Löbel 已提交
1342
    noop_fold_tts(tts, &mut Marker{mark:m})
1343 1344 1345
}

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

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

1355
// apply a given mark to the given stmt. Used following the expansion of a macro.
1356 1357
fn mark_stmt(stmt: P<ast::Stmt>, m: Mrk) -> P<ast::Stmt> {
    Marker{mark:m}.fold_stmt(stmt)
J
John Clements 已提交
1358
        .expect_one("marking a stmt didn't return exactly one stmt")
1359 1360 1361
}

// apply a given mark to the given item. Used following the expansion of a macro.
1362
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
J
John Clements 已提交
1363
    Marker{mark:m}.fold_item(expr)
J
John Clements 已提交
1364 1365 1366 1367
        .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.
1368
fn mark_impl_item(ii: P<ast::ImplItem>, m: Mrk) -> P<ast::ImplItem> {
1369
    Marker{mark:m}.fold_impl_item(ii)
1370
        .expect_one("marking an impl item didn't return exactly one impl item")
1371 1372
}

1373 1374 1375 1376
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
    Marker { mark: m }.fold_ty(ty)
}

J
John Clements 已提交
1377 1378
/// Check that there are no macro invocations left in the AST:
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1379
    visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
J
John Clements 已提交
1380 1381 1382 1383 1384 1385 1386
}

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

1387
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
K
Keegan McAllister 已提交
1388 1389
    fn visit_mac(&mut self, mac: &ast::Mac) {
        self.sess.span_diagnostic.span_bug(mac.span,
J
John Clements 已提交
1390 1391 1392 1393 1394 1395
                                           "macro exterminator: expected AST \
                                           with no macro invocations");
    }
}


J
John Clements 已提交
1396
#[cfg(test)]
1397
mod tests {
A
Alex Crichton 已提交
1398
    use super::{pattern_bindings, expand_crate};
1399
    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1400
    use ast;
J
Jorge Aparicio 已提交
1401
    use ast::Name;
1402
    use codemap;
1403
    use ext::mtwt;
1404
    use fold::Folder;
1405
    use parse;
1406
    use parse::token;
E
Eduard Burtescu 已提交
1407
    use util::parser_testing::{string_to_parser};
1408
    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1409
    use visit;
1410 1411 1412 1413 1414
    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)
1415
    #[derive(Clone)]
1416
    struct PathExprFinderContext {
1417
        path_accumulator: Vec<ast::Path> ,
1418 1419
    }

1420
    impl<'v> Visitor<'v> for PathExprFinderContext {
1421
        fn visit_expr(&mut self, expr: &ast::Expr) {
1422 1423
            if let ast::ExprPath(None, ref p) = expr.node {
                self.path_accumulator.push(p.clone());
1424
            }
1425
            visit::walk_expr(self, expr);
1426 1427 1428
        }
    }

1429 1430 1431
    // 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()};
1432
        visit::walk_crate(&mut path_finder, the_crate);
1433
        path_finder.path_accumulator
1434
    }
J
John Clements 已提交
1435

1436 1437
    /// A Visitor that extracts the identifiers from a thingy.
    // as a side note, I'm starting to want to abstract over these....
1438
    struct IdentFinder {
1439 1440
        ident_accumulator: Vec<ast::Ident>
    }
1441

1442
    impl<'v> Visitor<'v> for IdentFinder {
1443
        fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1444 1445 1446 1447 1448 1449 1450
            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()};
1451
        visit::walk_crate(&mut ident_finder, the_crate);
1452 1453
        ident_finder.ident_accumulator
    }
1454

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

1458
    fn test_ecfg() -> ExpansionConfig<'static> {
1459 1460 1461
        ExpansionConfig::default("test".to_string())
    }

J
John Clements 已提交
1462
    // make sure that macros can't escape fns
1463
    #[should_panic]
J
John Clements 已提交
1464
    #[test] fn macros_cant_escape_fns_test () {
1465
        let src = "fn bogus() {macro_rules! z (() => (3+4));}\
1466
                   fn inty() -> i32 { z!() }".to_string();
1467
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1468
        let crate_ast = parse::parse_crate_from_source_str(
1469
            "<test>".to_string(),
1470
            src,
E
Eduard Burtescu 已提交
1471
            Vec::new(), &sess);
J
John Clements 已提交
1472
        // should fail:
1473
        expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast);
J
John Clements 已提交
1474 1475
    }

J
John Clements 已提交
1476
    // make sure that macros can't escape modules
1477
    #[should_panic]
J
John Clements 已提交
1478
    #[test] fn macros_cant_escape_mods_test () {
1479
        let src = "mod foo {macro_rules! z (() => (3+4));}\
1480
                   fn inty() -> i32 { z!() }".to_string();
1481
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1482
        let crate_ast = parse::parse_crate_from_source_str(
1483
            "<test>".to_string(),
1484
            src,
E
Eduard Burtescu 已提交
1485
            Vec::new(), &sess);
1486
        expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast);
J
John Clements 已提交
1487 1488
    }

1489
    // macro_use modules should allow macros to escape
J
John Clements 已提交
1490
    #[test] fn macros_can_escape_flattened_mods_test () {
1491
        let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1492
                   fn inty() -> i32 { z!() }".to_string();
1493
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1494
        let crate_ast = parse::parse_crate_from_source_str(
1495
            "<test>".to_string(),
1496
            src,
E
Eduard Burtescu 已提交
1497
            Vec::new(), &sess);
1498
        expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast);
J
John Clements 已提交
1499 1500
    }

1501
    fn expand_crate_str(crate_str: String) -> ast::Crate {
1502
        let ps = parse::ParseSess::new();
1503
        let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
1504
        // the cfg argument actually does matter, here...
1505
        expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0
1506 1507
    }

1508 1509
    // find the pat_ident paths in a crate
    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1510
        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1511
        visit::walk_crate(&mut name_finder, the_crate);
1512 1513 1514
        name_finder.ident_accumulator
    }

1515
    #[test] fn macro_tokens_should_match(){
1516
        expand_crate_str(
1517
            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1518 1519
    }

1520 1521 1522
    // should be able to use a bound identifier as a literal in a macro definition:
    #[test] fn self_macro_parsing(){
        expand_crate_str(
1523 1524
            "macro_rules! foo ((zz) => (287;));
            fn f(zz: i32) {foo!(zz);}".to_string()
1525 1526 1527
            );
    }

1528 1529 1530 1531 1532 1533 1534
    // 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
1535
    // three varrefs, the array [[1, 2], [0]] would indicate that the first
1536 1537 1538
    // binding should match the second two varrefs, and the second binding
    // should match the first varref.
    //
J
John Clements 已提交
1539 1540 1541 1542 1543 1544
    // 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.
    //
1545 1546
    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
    // names; differences in marks don't matter any more.
J
John Clements 已提交
1547
    //
1548
    // oog... I also want tests that check "bound-identifier-=?". That is,
J
John Clements 已提交
1549 1550 1551 1552 1553
    // 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 已提交
1554
    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1555

1556 1557
    #[test]
    fn automatic_renaming () {
1558 1559
        let tests: Vec<RenamingTest> =
            vec!(// b & c should get new names throughout, in the expr too:
1560
                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1561
                 vec!(vec!(0,1),vec!(2)), false),
J
John Clements 已提交
1562
                // both x's should be renamed (how is this causing a bug?)
1563
                ("fn main () {let x: i32 = 13;x;}",
1564
                 vec!(vec!(0)), false),
1565
                // the use of b after the + should be renamed, the other one not:
1566
                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1567
                 vec!(vec!(1)), false),
J
John Clements 已提交
1568
                // the b before the plus should not be renamed (requires marks)
1569
                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1570
                 vec!(vec!(1)), false),
1571 1572 1573
                // 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.
1574 1575
                ("macro_rules! letty(($x:ident) => (let $x = 15;));
                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
1576
                  fn main() -> i32 {user!(z)}",
1577 1578
                 vec!(vec!(0)), false)
                );
1579 1580
        for (idx,s) in tests.iter().enumerate() {
            run_renaming_test(s,idx);
1581 1582 1583
        }
    }

1584 1585 1586 1587 1588
    // 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 已提交
1589 1590
    #[test]
    fn issue_8062(){
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
        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 已提交
1601 1602
    #[test]
    fn issue_6994(){
1603 1604
        run_renaming_test(
            &("macro_rules! g (($x:ident) =>
1605
              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1606 1607 1608
              fn a(){g!(z)}",
              vec!(vec!(0)),false),
            0)
1609 1610
    }

1611
    // match variable hygiene. Should expand into
1612
    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
R
Richo Healey 已提交
1613 1614
    #[test]
    fn issue_9384(){
1615
        run_renaming_test(
1616
            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1617
              fn z() {match 8 {x => bad_macro!(x)}}",
1618
              // NB: the third "binding" is the repeat of the second one.
1619
              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
1620 1621
              true),
            0)
1622 1623
    }

1624
    // interpolated nodes weren't getting labeled.
1625 1626
    // should expand into
    // fn main(){let g1_1 = 13; g1_1}}
R
Richo Healey 已提交
1627 1628
    #[test]
    fn pat_expand_issue_15221(){
1629
        run_renaming_test(
1630 1631
            &("macro_rules! inner ( ($e:pat ) => ($e));
              macro_rules! outer ( ($e:pat ) => (inner!($e)));
1632 1633 1634 1635 1636 1637
              fn main() { let outer!(g) = 13; g;}",
              vec!(vec!(0)),
              true),
            0)
    }

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

1642
    // method arg hygiene
1643
    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
R
Richo Healey 已提交
1644 1645
    #[test]
    fn method_arg_hygiene(){
1646
        run_renaming_test(
1647 1648
            &("macro_rules! inject_x (()=>(x));
              macro_rules! inject_self (()=>(self));
1649
              struct A;
1650
              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
1651 1652 1653 1654 1655
              vec!(vec!(0),vec!(3)),
              true),
            0)
    }

J
John Clements 已提交
1656 1657
    // ooh, got another bite?
    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
R
Richo Healey 已提交
1658 1659
    #[test]
    fn method_arg_hygiene_2(){
J
John Clements 已提交
1660 1661 1662
        run_renaming_test(
            &("struct A;
              macro_rules! add_method (($T:ty) =>
1663 1664
              (impl $T {  fn thingy(&self) {self;} }));
              add_method!(A);",
J
John Clements 已提交
1665 1666 1667 1668 1669
              vec!(vec!(0)),
              true),
            0)
    }

J
John Clements 已提交
1670
    // item fn hygiene
1671
    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
R
Richo Healey 已提交
1672 1673
    #[test]
    fn issue_9383(){
1674
        run_renaming_test(
1675 1676
            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
              fn q(x: i32) { bad_macro!(x); }",
1677
              vec!(vec!(1),vec!(0)),true),
1678
            0)
1679
    }
1680

1681
    // closure arg hygiene (ExprClosure)
1682
    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
R
Richo Healey 已提交
1683 1684
    #[test]
    fn closure_arg_hygiene(){
1685
        run_renaming_test(
1686
            &("macro_rules! inject_x (()=>(x));
1687
            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
1688 1689 1690 1691 1692
              vec!(vec!(1)),
              true),
            0)
    }

1693
    // macro_rules in method position. Sadly, unimplemented.
R
Richo Healey 已提交
1694 1695
    #[test]
    fn macro_in_method_posn(){
1696
        expand_crate_str(
1697
            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
1698
            struct A;
1699
            impl A{ my_method!(); }
1700 1701 1702
            fn f(){A.thirteen;}".to_string());
    }

1703 1704
    // another nested macro
    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
R
Richo Healey 已提交
1705 1706
    #[test]
    fn item_macro_workaround(){
1707 1708 1709 1710
        run_renaming_test(
            &("macro_rules! item { ($i:item) => {$i}}
              struct Entries;
              macro_rules! iterator_impl {
1711
              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
1712 1713 1714 1715 1716
              iterator_impl! { }",
              vec!(vec!(0)), true),
            0)
    }

J
John Clements 已提交
1717
    // run one of the renaming tests
P
Paul Collier 已提交
1718
    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
J
John Clements 已提交
1719
        let invalid_name = token::special_idents::invalid.name;
J
John Clements 已提交
1720
        let (teststr, bound_connections, bound_ident_check) = match *t {
1721
            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
1722
        };
1723
        let cr = expand_crate_str(teststr.to_string());
1724 1725
        let bindings = crate_bindings(&cr);
        let varrefs = crate_varrefs(&cr);
1726

1727 1728 1729
        // must be one check clause for each binding:
        assert_eq!(bindings.len(),bound_connections.len());
        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
1730 1731
            let binding_name = mtwt::resolve(bindings[binding_idx]);
            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
1732
            // shouldmatch can't name varrefs that don't exist:
1733
            assert!((shouldmatch.is_empty()) ||
1734 1735
                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
            for (idx,varref) in varrefs.iter().enumerate() {
1736
                let print_hygiene_debug_info = || {
J
John Clements 已提交
1737 1738 1739
                    // 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 已提交
1740
                        None => panic!("varref with 0 path segments?")
J
John Clements 已提交
1741 1742 1743 1744 1745
                    };
                    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 已提交
1746
                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
1747
                    println!("varref's first segment's string: \"{}\"", final_varref_ident);
J
John Clements 已提交
1748
                    println!("binding #{}: {}, resolves to {}",
1749
                             binding_idx, bindings[binding_idx], binding_name);
J
John Clements 已提交
1750 1751
                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
                };
1752 1753
                if shouldmatch.contains(&idx) {
                    // it should be a path of length 1, and it should
J
John Clements 已提交
1754
                    // be free-identifier=? or bound-identifier=? to the given binding
1755
                    assert_eq!(varref.segments.len(),1);
1756 1757
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
                    let varref_marks = mtwt::marksof(varref.segments[0]
1758 1759 1760
                                                           .identifier
                                                           .ctxt,
                                                     invalid_name);
1761
                    if !(varref_name==binding_name) {
1762
                        println!("uh oh, should match but doesn't:");
J
John Clements 已提交
1763
                        print_hygiene_debug_info();
1764 1765
                    }
                    assert_eq!(varref_name,binding_name);
1766
                    if bound_ident_check {
J
John Clements 已提交
1767 1768
                        // we're checking bound-identifier=?, and the marks
                        // should be the same, too:
J
John Clements 已提交
1769 1770
                        assert_eq!(varref_marks,binding_marks.clone());
                    }
1771
                } else {
1772
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
1773
                    let fail = (varref.segments.len() == 1)
1774
                        && (varref_name == binding_name);
1775
                    // temp debugging:
1776
                    if fail {
1777 1778 1779 1780
                        println!("failure on test {}",test_idx);
                        println!("text of test case: \"{}\"", teststr);
                        println!("");
                        println!("uh oh, matches but shouldn't:");
J
John Clements 已提交
1781
                        print_hygiene_debug_info();
1782 1783 1784 1785
                    }
                    assert!(!fail);
                }
            }
1786 1787
        }
    }
1788

R
Richo Healey 已提交
1789 1790
    #[test]
    fn fmt_in_macro_used_inside_module_macro() {
1791 1792 1793
        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!();
1794
".to_string();
J
John Clements 已提交
1795 1796
        let cr = expand_crate_str(crate_str);
        // find the xx binding
1797
        let bindings = crate_bindings(&cr);
1798
        let cxbinds: Vec<&ast::Ident> =
1799
            bindings.iter().filter(|b| b.name.as_str() == "xx").collect();
1800
        let cxbinds: &[&ast::Ident] = &cxbinds[..];
1801 1802
        let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
            (1, Some(b)) => *b,
S
Steve Klabnik 已提交
1803
            _ => panic!("expected just one binding for ext_cx")
J
John Clements 已提交
1804
        };
1805
        let resolved_binding = mtwt::resolve(*cxbind);
1806
        let varrefs = crate_varrefs(&cr);
1807

J
John Clements 已提交
1808
        // the xx binding should bind all of the xx varrefs:
1809
        for (idx,v) in varrefs.iter().filter(|p| {
1810
            p.segments.len() == 1
1811
            && p.segments[0].identifier.name.as_str() == "xx"
1812
        }).enumerate() {
1813
            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
1814
                println!("uh oh, xx binding didn't match xx varref:");
L
Luqman Aden 已提交
1815 1816 1817
                println!("this is xx varref \\# {}", idx);
                println!("binding: {}", cxbind);
                println!("resolves to: {}", resolved_binding);
1818
                println!("varref: {}", v.segments[0].identifier);
L
Luqman Aden 已提交
1819
                println!("resolves to: {}",
1820
                         mtwt::resolve(v.segments[0].identifier));
1821
                mtwt::with_sctable(|x| mtwt::display_sctable(x));
J
John Clements 已提交
1822
            }
1823
            assert_eq!(mtwt::resolve(v.segments[0].identifier),
1824
                       resolved_binding);
J
John Clements 已提交
1825 1826 1827
        };
    }

J
John Clements 已提交
1828 1829
    #[test]
    fn pat_idents(){
1830
        let pat = string_to_pat(
1831
            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
S
Seo Sanghyeon 已提交
1832
        let idents = pattern_bindings(&pat);
1833
        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
J
John Clements 已提交
1834
    }
J
John Clements 已提交
1835

1836 1837 1838
    // 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.
1839
    #[test]
1840
    fn crate_bindings_test(){
1841
        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
1842
        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
1843 1844
        let idents = crate_bindings(&the_crate);
        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
1845 1846
    }

1847 1848 1849
    // test the IdentRenamer directly
    #[test]
    fn ident_renamer_test () {
1850
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1851 1852
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1853
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1854
        let renames = vec!((x_ident,Name(16)));
1855 1856 1857 1858
        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();
1859
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
1860 1861 1862 1863 1864
    }

    // test the PatIdentRenamer; only PatIdents get renamed
    #[test]
    fn pat_ident_renamer_test () {
1865
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1866 1867
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1868
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1869
        let renames = vec!((x_ident,Name(16)));
1870 1871 1872 1873 1874
        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;
1875
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
1876
    }
J
John Clements 已提交
1877
}