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::*;
27
use parse;
28
use parse::token::{fresh_mark, fresh_name, intern};
29 30
use ptr::P;
use util::small_vector::SmallVector;
J
John Clements 已提交
31
use visit;
H
Huon Wilson 已提交
32
use visit::Visitor;
33
use std_inject;
34

35 36
use std::collections::HashSet;

37

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

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

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

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

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

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

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

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

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

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

            // 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))
106
                .with_attrs(fold_thin_attrs(attrs, fld))
107 108
        }

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

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

            // 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);

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

        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))
149
                .with_attrs(fold_thin_attrs(attrs, fld))
150 151
        }

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

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

J
John Clements 已提交
173 174 175 176
/// 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.
177 178
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                             span: codemap::Span,
J
Jorge Aparicio 已提交
179 180 181 182
                             parse_thunk: F,
                             mark_thunk: G,
                             fld: &mut MacroExpander)
                             -> Option<T> where
183
    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
J
Jorge Aparicio 已提交
184
    G: FnOnce(T, Mrk) -> T,
185
{
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    // 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;
201
    match fld.cx.syntax_env.find(extname) {
202 203 204 205 206
        None => {
            fld.cx.span_err(
                pth.span,
                &format!("macro undefined: '{}!'",
                        &extname));
J
John Clements 已提交
207

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
            // 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 => {
239 240
                        fld.cx.span_err(
                            pth.span,
241 242 243 244
                            &format!("non-expression macro in expression position: {}",
                                    extname
                                    ));
                        return None;
245
                    }
246 247 248 249 250 251 252 253 254
                };
                Some(mark_thunk(parsed,fm))
            }
            _ => {
                fld.cx.span_err(
                    pth.span,
                    &format!("'{}' is not a tt-style macro",
                            extname));
                None
J
John Clements 已提交
255 256 257 258 259
            }
        }
    }
}

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

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

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

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

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

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

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

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

354 355
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
356 357
pub fn expand_item_mac(it: P<ast::Item>,
                       fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
358 359 360
    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),
361
        _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
362
    });
363

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

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

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

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

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

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

477
        expanded.make_items()
478
    };
479

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

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

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

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

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

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

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

    fully_expanded
546 547
}

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

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

628
    // apply renaming and then expansion to the guard and the body:
629 630 631 632 633 634 635 636 637 638
    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 已提交
639
    ast::Arm {
640
        attrs: fold::fold_attrs(arm.attrs, fld),
641 642 643
        pats: rewritten_pats,
        guard: rewritten_guard,
        body: rewritten_body,
J
John Clements 已提交
644
    }
J
John Clements 已提交
645 646
}

647 648 649 650 651 652 653 654 655
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 已提交
656
    let idents = pattern_bindings(&pats[0]);
657 658 659 660 661 662 663 664 665
    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)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

961 962 963 964 965 966 967 968 969
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 已提交
970
        let mname = intern(&attr.name());
971
        match fld.cx.syntax_env.find(mname) {
972
            Some(rc) => match *rc {
973 974 975 976 977 978
                MultiDecorator(ref dec) => {
                    attr::mark_used(&attr);

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

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
    }

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

1022
        match fld.cx.syntax_env.find(mname) {
1023 1024 1025 1026 1027 1028
            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 已提交
1029
                            format: MacroAttribute(mname),
1030
                            span: Some(attr.span),
1031 1032 1033
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
                        }
                    });
                    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)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1304 1305 1306 1307 1308 1309
        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);
1310
}
J
John Clements 已提交
1311

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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