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

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

36 37
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
    e.and_then(|ast::Expr {id, node, span}| match node {
38 39
        // expr_mac should really be expr_ext or something; it's the
        // entry-point for all syntax extensions.
40
        ast::ExprMac(mac) => {
41 42 43
            let expanded_expr = match expand_mac_invoc(mac, span,
                                                       |r| r.make_expr(),
                                                       mark_expr, fld) {
J
John Clements 已提交
44 45
                Some(expr) => expr,
                None => {
46
                    return DummyResult::raw_expr(span);
J
John Clements 已提交
47 48
                }
            };
49

J
John Clements 已提交
50 51
            // Keep going, outside-in.
            //
52
            let fully_expanded = fld.fold_expr(expanded_expr);
J
John Clements 已提交
53
            fld.cx.bt_pop();
54

55
            fully_expanded.map(|e| ast::Expr {
J
John Clements 已提交
56
                id: ast::DUMMY_NODE_ID,
57
                node: e.node,
58
                span: fld.new_span(span),
59
            })
60
        }
61

P
Pythoner6 已提交
62 63 64
        ast::ExprWhile(cond, body, opt_ident) => {
            let cond = fld.fold_expr(cond);
            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
65
            fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
P
Pythoner6 已提交
66 67
        }

J
John Gallagher 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
        // Desugar ExprWhileLet
        // From: `[opt_ident]: while let <pat> = <expr> <body>`
        ast::ExprWhileLet(pat, expr, body, opt_ident) => {
            // to:
            //
            //   [opt_ident]: loop {
            //     match <expr> {
            //       <pat> => <body>,
            //       _ => break
            //     }
            //   }

            // `<pat> => <body>`
            let pat_arm = {
                let body_expr = fld.cx.expr_block(body);
                fld.cx.arm(pat.span, vec![pat], body_expr)
            };

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

            // `match <expr> { ... }`
            let arms = vec![pat_arm, break_arm];
            let match_expr = fld.cx.expr(span,
96
                                    ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
J
John Gallagher 已提交
97 98 99 100 101 102 103

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

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
        // Desugar ExprIfLet
        // From: `if let <pat> = <expr> <body> [<elseopt>]`
        ast::ExprIfLet(pat, expr, body, mut elseopt) => {
            // to:
            //
            //   match <expr> {
            //     <pat> => <body>,
            //     [_ if <elseopt_if_cond> => <elseopt_if_body>,]
            //     _ => [<elseopt> | ()]
            //   }

            // `<pat> => <body>`
            let pat_arm = {
                let body_expr = fld.cx.expr_block(body);
                fld.cx.arm(pat.span, vec![pat], body_expr)
            };

            // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
            let else_if_arms = {
                let mut arms = vec![];
                loop {
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
                    let elseopt_continue = elseopt
                        .and_then(|els| els.and_then(|els| match els.node {
                        // else if
                        ast::ExprIf(cond, then, elseopt) => {
                            let pat_under = fld.cx.pat_wild(span);
                            arms.push(ast::Arm {
                                attrs: vec![],
                                pats: vec![pat_under],
                                guard: Some(cond),
                                body: fld.cx.expr_block(then)
                            });
                            elseopt.map(|elseopt| (elseopt, true))
                        }
                        _ => Some((P(els), false))
                    }));
                    match elseopt_continue {
                        Some((e, true)) => {
                            elseopt = Some(e);
                        }
                        Some((e, false)) => {
                            elseopt = Some(e);
                            break;
                        }
                        None => {
                            elseopt = None;
                            break;
                        }
152 153 154 155 156
                    }
                }
                arms
            };

157 158
            let contains_else_clause = elseopt.is_some();

159 160 161
            // `_ => [<elseopt> | ()]`
            let else_arm = {
                let pat_under = fld.cx.pat_wild(span);
162
                let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![]));
163 164 165 166 167
                fld.cx.arm(span, vec![pat_under], else_expr)
            };

            let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
            arms.push(pat_arm);
168
            arms.extend(else_if_arms.into_iter());
169 170
            arms.push(else_arm);

171 172 173 174 175
            let match_expr = fld.cx.expr(span,
                                         ast::ExprMatch(expr, arms,
                                                ast::MatchSource::IfLetDesugar {
                                                    contains_else_clause: contains_else_clause,
                                                }));
176 177 178 179
            fld.fold_expr(match_expr)
        }

        // Desugar support for ExprIfLet in the ExprIf else position
K
Kevin Ballard 已提交
180
        ast::ExprIf(cond, blk, elseopt) => {
181
            let elseopt = elseopt.map(|els| els.and_then(|els| match els.node {
K
Kevin Ballard 已提交
182 183
                ast::ExprIfLet(..) => {
                    // wrap the if-let expr in a block
184
                    let span = els.span;
K
Kevin Ballard 已提交
185 186
                    let blk = P(ast::Block {
                        stmts: vec![],
187
                        expr: Some(P(els)),
K
Kevin Ballard 已提交
188 189
                        id: ast::DUMMY_NODE_ID,
                        rules: ast::DefaultBlock,
190
                        span: span
K
Kevin Ballard 已提交
191 192 193
                    });
                    fld.cx.expr_block(blk)
                }
194 195 196 197
                _ => P(els)
            }));
            let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt));
            if_expr.map(|e| noop_fold_expr(e, fld))
198 199
        }

E
Edward Wang 已提交
200
        ast::ExprLoop(loop_block, opt_ident) => {
201
            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
202
            fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
E
Edward Wang 已提交
203 204
        }

J
Jorge Aparicio 已提交
205 206
        // Desugar ExprForLoop
        // From: `[opt_ident]: for <pat> in <head> <body>`
207
        ast::ExprForLoop(pat, head, body, opt_ident) => {
J
Jorge Aparicio 已提交
208 209
            // to:
            //
210 211 212 213 214 215 216 217
            //   {
            //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
            //       mut iter => {
            //         [opt_ident]: loop {
            //           match ::std::iter::Iterator::next(&mut iter) {
            //             ::std::option::Option::Some(<pat>) => <body>,
            //             ::std::option::Option::None => break
            //           }
J
Jorge Aparicio 已提交
218 219
            //         }
            //       }
220 221
            //     };
            //     result
J
Jorge Aparicio 已提交
222 223 224
            //   }

            // expand <head>
225
            let head = fld.fold_expr(head);
J
Jorge Aparicio 已提交
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

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

                rename_fld.fold_ident(ident)
            };

            let pat_span = pat.span;
            // `:;std::option::Option::Some(<pat>) => <body>`
            let pat_arm = {
                let body_expr = fld.cx.expr_block(body);
                let some_pat = fld.cx.pat_some(pat_span, pat);

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

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

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

            // `match ::std::iter::Iterator::next(&mut iter) { ... }`
            let match_expr = {
                let next_path = {
                    let strs = vec![
258
                        fld.cx.ident_of_std("core"),
J
Jorge Aparicio 已提交
259 260 261 262 263 264 265 266 267 268 269 270
                        fld.cx.ident_of("iter"),
                        fld.cx.ident_of("Iterator"),
                        fld.cx.ident_of("next"),
                    ];

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

271 272
                fld.cx.expr(pat_span,
                            ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar))
J
Jorge Aparicio 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
            };

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

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

            // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
            let into_iter_expr = {
                let into_iter_path = {
                    let strs = vec![
291
                        fld.cx.ident_of_std("core"),
J
Jorge Aparicio 已提交
292 293 294 295 296 297 298 299 300 301
                        fld.cx.ident_of("iter"),
                        fld.cx.ident_of("IntoIterator"),
                        fld.cx.ident_of("into_iter"),
                    ];

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

                fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
            };
302 303 304 305 306 307 308 309 310 311

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

            // `{ let result = ...; result }`
            let result_ident = token::gensym_ident("result");
            fld.cx.expr_block(
                fld.cx.block_all(
                    span,
                    vec![fld.cx.stmt_let(span, false, result_ident, match_expr)],
                    Some(fld.cx.expr_ident(span, result_ident))))
312 313
        }

314
        ast::ExprClosure(capture_clause, fn_decl, block) => {
315
            let (rewritten_fn_decl, rewritten_block)
316
                = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
317
            let new_node = ast::ExprClosure(capture_clause,
318 319
                                            rewritten_fn_decl,
                                            rewritten_block);
320
            P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})
321 322
        }

323 324 325 326 327 328 329 330
        _ => {
            P(noop_fold_expr(ast::Expr {
                id: id,
                node: node,
                span: span
            }, fld))
        }
    })
331 332
}

J
John Clements 已提交
333 334 335 336
/// 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.
J
Jorge Aparicio 已提交
337 338 339 340 341
fn expand_mac_invoc<T, F, G>(mac: ast::Mac, span: codemap::Span,
                             parse_thunk: F,
                             mark_thunk: G,
                             fld: &mut MacroExpander)
                             -> Option<T> where
342
    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
J
Jorge Aparicio 已提交
343
    G: FnOnce(T, Mrk) -> T,
344
{
345
    match mac.node {
J
John Clements 已提交
346 347 348 349 350 351
        // it would almost certainly be cleaner to pass the whole
        // macro invocation in, rather than pulling it apart and
        // marking the tts and the ctxt separately. This also goes
        // for the other three macro invocation chunks of code
        // in this file.
        // Token-tree macros:
352
        MacInvocTT(pth, tts, _) => {
353
            if pth.segments.len() > 1 {
J
John Clements 已提交
354 355 356 357 358 359
                fld.cx.span_err(pth.span,
                                "expected macro name without module \
                                separators");
                // let compilation continue
                return None;
            }
360
            let extname = pth.segments[0].identifier;
J
John Clements 已提交
361
            let extnamestr = token::get_ident(extname);
362
            match fld.cx.syntax_env.find(&extname.name) {
J
John Clements 已提交
363 364 365
                None => {
                    fld.cx.span_err(
                        pth.span,
J
Jorge Aparicio 已提交
366
                        &format!("macro undefined: '{}!'",
367
                                &extnamestr));
J
John Clements 已提交
368 369 370 371

                    // let compilation continue
                    None
                }
372
                Some(rc) => match *rc {
373
                    NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
374
                        fld.cx.bt_push(ExpnInfo {
375
                                call_site: span,
376
                                callee: NameAndSpan {
G
GuillaumeGomez 已提交
377
                                    name: extnamestr.to_string(),
378 379
                                    format: MacroBang,
                                    span: exp_span,
380
                                    allow_internal_unstable: allow_internal_unstable,
381 382 383
                                },
                            });
                        let fm = fresh_mark();
384
                        let marked_before = mark_tts(&tts[..], fm);
385 386 387 388 389

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

392 393
                        let opt_parsed = {
                            let expanded = expandfun.expand(fld.cx,
394
                                                            mac_span,
395
                                                            &marked_before[..]);
396 397 398
                            parse_thunk(expanded)
                        };
                        let parsed = match opt_parsed {
399 400 401 402
                            Some(e) => e,
                            None => {
                                fld.cx.span_err(
                                    pth.span,
J
Jorge Aparicio 已提交
403
                                    &format!("non-expression macro in expression position: {}",
404
                                            &extnamestr[..]
405
                                            ));
406 407 408 409 410 411 412 413
                                return None;
                            }
                        };
                        Some(mark_thunk(parsed,fm))
                    }
                    _ => {
                        fld.cx.span_err(
                            pth.span,
J
Jorge Aparicio 已提交
414
                            &format!("'{}' is not a tt-style macro",
415
                                    &extnamestr));
416 417
                        None
                    }
J
John Clements 已提交
418 419 420 421 422 423
                }
            }
        }
    }
}

424 425 426 427 428
/// 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.
429 430 431
fn expand_loop_block(loop_block: P<Block>,
                     opt_ident: Option<Ident>,
                     fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
E
Edward Wang 已提交
432 433 434 435
    match opt_ident {
        Some(label) => {
            let new_label = fresh_name(&label);
            let rename = (label, new_label);
436 437 438 439 440 441

            // 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);
442
            let mut rename_fld = IdentRenamer{renames: &mut rename_list};
443 444 445 446 447
            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.
448 449
            fld.cx.syntax_env.push_frame();
            fld.cx.syntax_env.info().pending_renames.push(rename);
450
            let expanded_block = expand_block_elts(loop_block, fld);
451
            fld.cx.syntax_env.pop_frame();
452 453

            (expanded_block, Some(renamed_ident))
E
Edward Wang 已提交
454
        }
455
        None => (fld.fold_block(loop_block), opt_ident)
E
Edward Wang 已提交
456 457 458
    }
}

459 460
// eval $e with a new exts frame.
// must be a macro so that $e isn't evaluated too early.
461
macro_rules! with_exts_frame {
462
    ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
S
Steven Fackler 已提交
463 464
    ({$extsboxexpr.push_frame();
      $extsboxexpr.info().macros_escape = $macros_escape;
J
John Clements 已提交
465
      let result = $e;
S
Steven Fackler 已提交
466
      $extsboxexpr.pop_frame();
J
John Clements 已提交
467 468
      result
     })
469
}
J
John Clements 已提交
470

471
// When we enter a module, record it, for the sake of `module!`
472 473
pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
                   -> SmallVector<P<ast::Item>> {
474 475
    let it = expand_item_modifiers(it, fld);

476 477
    expand_annotatable(Annotatable::Item(it), fld)
        .into_iter().map(|i| i.expect_item()).collect()
478 479
}

480 481
fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
                         -> P<ast::Item> {
482
    // partition the attributes into ItemModifiers and others
483 484
    let (modifiers, other_attrs) = modifiers(&it.attrs, fld);

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

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

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

499
        match fld.cx.syntax_env.find(&intern(&mname)) {
500
            Some(rc) => match *rc {
501
                Modifier(ref mac) => {
502 503 504 505
                    attr::mark_used(attr);
                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
506
                            name: mname.to_string(),
507 508
                            format: MacroAttribute,
                            span: None,
509 510 511
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
512 513
                        }
                    });
514
                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
515 516 517 518
                    fld.cx.bt_pop();
                }
                _ => unreachable!()
            },
519 520 521 522
            _ => unreachable!()
        }
    }

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

J
John Clements 已提交
532
/// Expand item_underscore
533 534 535
fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
    match item {
        ast::ItemFn(decl, fn_style, abi, generics, body) => {
J
John Clements 已提交
536
            let (rewritten_fn_decl, rewritten_body)
537
                = expand_and_rename_fn_decl_and_block(decl, body, fld);
M
Marvin Löbel 已提交
538
            let expanded_generics = fold::noop_fold_generics(generics,fld);
J
John Clements 已提交
539 540
            ast::ItemFn(rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body)
        }
541
        _ => noop_fold_item_underscore(item, fld)
J
John Clements 已提交
542 543 544
    }
}

545 546
// does this attribute list contain "macro_use" ?
fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
547
    for attr in attrs {
548 549 550 551 552
        let mut is_use = attr.check_name("macro_use");
        if attr.check_name("macro_escape") {
            fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
            is_use = true;
            if let ast::AttrInner = attr.node.style {
553
                fld.cx.fileline_help(attr.span, "consider an outer attribute, \
554 555 556 557 558 559 560 561 562 563 564 565 566
                                             #[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 已提交
567 568
}

569 570
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
571 572
pub fn expand_item_mac(it: P<ast::Item>,
                       fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
573
    let (extname, path_span, tts) = match it.node {
574
        ItemMac(codemap::Spanned {
S
Steven Fackler 已提交
575
            node: MacInvocTT(ref pth, ref tts, _),
A
Alex Crichton 已提交
576
            ..
577
        }) => {
578
            (pth.segments[0].identifier, pth.span, (*tts).clone())
579
        }
580
        _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
581
    };
582

583
    let extnamestr = token::get_ident(extname);
584
    let fm = fresh_mark();
585 586
    let items = {
        let expanded = match fld.cx.syntax_env.find(&extname.name) {
587
            None => {
588
                fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
589
                                &format!("macro undefined: '{}!'",
590
                                        extnamestr));
591 592 593
                // let compilation continue
                return SmallVector::zero();
            }
594

595
            Some(rc) => match *rc {
596
                NormalTT(ref expander, span, allow_internal_unstable) => {
597 598
                    if it.ident.name != parse::token::special_idents::invalid.name {
                        fld.cx
599
                            .span_err(path_span,
600 601 602
                                      &format!("macro {}! expects no ident argument, given '{}'",
                                               extnamestr,
                                               token::get_ident(it.ident)));
603 604 605 606 607
                        return SmallVector::zero();
                    }
                    fld.cx.bt_push(ExpnInfo {
                        call_site: it.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
608
                            name: extnamestr.to_string(),
609
                            format: MacroBang,
610 611
                            span: span,
                            allow_internal_unstable: allow_internal_unstable,
612 613 614
                        }
                    });
                    // mark before expansion:
615 616
                    let marked_before = mark_tts(&tts[..], fm);
                    expander.expand(fld.cx, it.span, &marked_before[..])
617
                }
618
                IdentTT(ref expander, span, allow_internal_unstable) => {
619
                    if it.ident.name == parse::token::special_idents::invalid.name {
620
                        fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
621
                                        &format!("macro {}! expects an ident argument",
622
                                                &extnamestr));
623
                        return SmallVector::zero();
624
                    }
625 626 627
                    fld.cx.bt_push(ExpnInfo {
                        call_site: it.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
628
                            name: extnamestr.to_string(),
629
                            format: MacroBang,
630 631
                            span: span,
                            allow_internal_unstable: allow_internal_unstable,
632 633 634
                        }
                    });
                    // mark before expansion:
635
                    let marked_tts = mark_tts(&tts[..], fm);
636
                    expander.expand(fld.cx, it.span, it.ident, marked_tts)
637
                }
638
                MacroRulesTT => {
639
                    if it.ident.name == parse::token::special_idents::invalid.name {
640
                        fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
641
                                        &format!("macro_rules! expects an ident argument")
642
                                        );
643
                        return SmallVector::zero();
644
                    }
645

646 647 648
                    fld.cx.bt_push(ExpnInfo {
                        call_site: it.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
649
                            name: extnamestr.to_string(),
650
                            format: MacroBang,
651
                            span: None,
652 653 654 655
                            // `macro_rules!` doesn't directly allow
                            // unstable (this is orthogonal to whether
                            // the macro it creates allows it)
                            allow_internal_unstable: false,
656 657
                        }
                    });
658
                    // DON'T mark before expansion.
659

660 661 662 663 664 665 666 667 668 669 670 671 672 673
                    let allow_internal_unstable = attr::contains_name(&it.attrs,
                                                                      "allow_internal_unstable");

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

674 675 676 677 678 679
                    let def = ast::MacroDef {
                        ident: it.ident,
                        attrs: it.attrs.clone(),
                        id: ast::DUMMY_NODE_ID,
                        span: it.span,
                        imported_from: None,
680
                        export: attr::contains_name(&it.attrs, "macro_export"),
K
Keegan McAllister 已提交
681
                        use_locally: true,
682
                        allow_internal_unstable: allow_internal_unstable,
683 684
                        body: tts,
                    };
685
                    fld.cx.insert_macro(def);
686 687 688 689

                    // macro_rules! has a side effect but expands to nothing.
                    fld.cx.bt_pop();
                    return SmallVector::zero();
690 691 692
                }
                _ => {
                    fld.cx.span_err(it.span,
J
Jorge Aparicio 已提交
693
                                    &format!("{}! is not legal in item position",
694
                                            &extnamestr));
695
                    return SmallVector::zero();
696
                }
J
John Clements 已提交
697
            }
698 699
        };

700
        expanded.make_items()
701
    };
702

703 704
    let items = match items {
        Some(items) => {
A
Aaron Turon 已提交
705
            items.into_iter()
706
                .map(|i| mark_item(i, fm))
A
Aaron Turon 已提交
707
                .flat_map(|i| fld.fold_item(i).into_iter())
708 709
                .collect()
        }
710
        None => {
711
            fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
712
                            &format!("non-item macro in item position: {}",
713
                                    &extnamestr));
714
            return SmallVector::zero();
715
        }
716
    };
717

718
    fld.cx.bt_pop();
719
    items
720 721
}

J
John Clements 已提交
722
/// Expand a stmt
723 724 725
fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
    let stmt = stmt.and_then(|stmt| stmt);
    let (mac, style) = match stmt.node {
726
        StmtMac(mac, style) => (mac, style),
727
        _ => return expand_non_macro_stmt(stmt, fld)
728
    };
729 730 731 732 733 734 735

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

736
    let mut fully_expanded = match maybe_new_items {
737 738
        Some(stmts) => {
            // Keep going, outside-in.
739
            let new_items = stmts.into_iter().flat_map(|s| {
740
                fld.fold_stmt(s).into_iter()
741 742 743
            }).collect();
            fld.cx.bt_pop();
            new_items
744
        }
745
        None => SmallVector::zero()
746 747
    };

748 749
    // If this is a macro invocation with a semicolon, then apply that
    // semicolon to the final statement produced by expansion.
750
    if style == MacStmtWithSemicolon {
751 752 753 754 755 756 757 758 759 760 761
        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);
762
        }
763
    }
764 765

    fully_expanded
766 767
}

768 769
// expand a non-macro stmt. this is essentially the fallthrough for
// expand_stmt, above.
770 771
fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroExpander)
                         -> SmallVector<P<Stmt>> {
772
    // is it a let?
773 774 775 776 777
    match node {
        StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl {
            DeclLocal(local) => {
                // take it apart:
                let rewritten_local = local.map(|Local {id, pat, ty, init, source, span}| {
778 779
                    // expand the ty since TyFixedLengthVec contains an Expr
                    // and thus may have a macro use
S
Seo Sanghyeon 已提交
780
                    let expanded_ty = ty.map(|t| fld.fold_ty(t));
781
                    // expand the pat (it might contain macro uses):
782
                    let expanded_pat = fld.fold_pat(pat);
783
                    // find the PatIdents in the pattern:
784 785 786 787
                    // 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
788
                    let idents = pattern_bindings(&*expanded_pat);
789 790
                    let mut new_pending_renames =
                        idents.iter().map(|ident| (*ident, fresh_name(ident))).collect();
791 792
                    // rewrite the pattern using the new names (the old
                    // ones have already been applied):
793
                    let rewritten_pat = {
794 795
                        // nested binding to allow borrow to expire:
                        let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
796 797 798
                        rename_fld.fold_pat(expanded_pat)
                    };
                    // add them to the existing pending renames:
799 800
                    fld.cx.syntax_env.info().pending_renames
                          .extend(new_pending_renames.into_iter());
801 802 803 804 805 806 807
                    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)),
                        source: source,
808
                        span: span
809 810 811 812 813 814 815 816 817 818
                    }
                });
                SmallVector::one(P(Spanned {
                    node: StmtDecl(P(Spanned {
                            node: DeclLocal(rewritten_local),
                            span: span
                        }),
                        node_id),
                    span: stmt_span
                }))
S
Steven Fackler 已提交
819
            }
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
            _ => {
                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)
        }
837 838 839
    }
}

J
John Clements 已提交
840
// expand the arm of a 'match', renaming for macro hygiene
841
fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
842
    // expand pats... they might contain macro uses:
843
    let expanded_pats = arm.pats.move_map(|pat| fld.fold_pat(pat));
844
    if expanded_pats.len() == 0 {
S
Steve Klabnik 已提交
845
        panic!("encountered match arm with 0 patterns");
J
John Clements 已提交
846
    }
J
John Clements 已提交
847 848
    // all of the pats must have the same set of bindings, so use the
    // first one to extract them and generate new names:
849
    let idents = pattern_bindings(&*expanded_pats[0]);
A
Aaron Turon 已提交
850
    let new_renames = idents.into_iter().map(|id| (id, fresh_name(&id))).collect();
851
    // apply the renaming, but only to the PatIdents:
J
John Clements 已提交
852
    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
853
    let rewritten_pats = expanded_pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
854
    // apply renaming and then expansion to the guard and the body:
J
John Clements 已提交
855
    let mut rename_fld = IdentRenamer{renames:&new_renames};
856 857 858
    let rewritten_guard =
        arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
    let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
J
John Clements 已提交
859
    ast::Arm {
860
        attrs: fold::fold_attrs(arm.attrs, fld),
861 862 863
        pats: rewritten_pats,
        guard: rewritten_guard,
        body: rewritten_body,
J
John Clements 已提交
864
    }
J
John Clements 已提交
865 866
}

867 868 869
/// A visitor that extracts the PatIdent (binding) paths
/// from a given thingy and puts them in a mutable
/// array
870
#[derive(Clone)]
871
struct PatIdentFinder {
872
    ident_accumulator: Vec<ast::Ident>
873 874
}

875
impl<'v> Visitor<'v> for PatIdentFinder {
876
    fn visit_pat(&mut self, pattern: &ast::Pat) {
877
        match *pattern {
878
            ast::Pat { id: _, node: ast::PatIdent(_, ref path1, ref inner), span: _ } => {
879
                self.ident_accumulator.push(path1.node);
880
                // visit optional subpattern of PatIdent:
881
                if let Some(ref subpat) = *inner {
882
                    self.visit_pat(&**subpat)
J
John Clements 已提交
883 884
                }
            }
885
            // use the default traversal for non-PatIdents
886
            _ => visit::walk_pat(self, pattern)
887 888 889 890
        }
    }
}

891
/// find the PatIdent paths in a pattern
892
fn pattern_bindings(pat: &ast::Pat) -> Vec<ast::Ident> {
893
    let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
894
    name_finder.visit_pat(pat);
895
    name_finder.ident_accumulator
896 897
}

J
John Clements 已提交
898 899 900
/// 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()};
901
    for arg in &fn_decl.inputs {
902
        pat_idents.visit_pat(&*arg.pat);
J
John Clements 已提交
903 904 905 906
    }
    pat_idents.ident_accumulator
}

J
John Clements 已提交
907
// expand a block. pushes a new exts_frame, then calls expand_block_elts
908
pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {
909
    // see note below about treatment of exts table
910
    with_exts_frame!(fld.cx.syntax_env,false,
911
                     expand_block_elts(blk, fld))
912 913
}

J
John Clements 已提交
914
// expand the elements of a block.
915
pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
916
    b.map(|Block {id, stmts, expr, rules, span}| {
A
Aaron Turon 已提交
917
        let new_stmts = stmts.into_iter().flat_map(|x| {
918
            // perform all pending renames
919
            let renamed_stmt = {
920
                let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
921
                let mut rename_fld = IdentRenamer{renames:pending_renames};
922
                rename_fld.fold_stmt(x).expect_one("rename_fold didn't return one value")
923
            };
924
            // expand macros in the statement
A
Aaron Turon 已提交
925
            fld.fold_stmt(renamed_stmt).into_iter()
926
        }).collect();
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
        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
        }
942
    })
J
John Clements 已提交
943 944
}

945 946 947 948
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 已提交
949
    }
950 951 952 953 954 955 956 957 958
    p.map(|ast::Pat {node, span, ..}| {
        let (pth, tts) = match node {
            PatMac(mac) => match mac.node {
                MacInvocTT(pth, tts, _) => {
                    (pth, tts)
                }
            },
            _ => unreachable!()
        };
959
        if pth.segments.len() > 1 {
960 961
            fld.cx.span_err(pth.span, "expected macro name without module separators");
            return DummyResult::raw_pat(span);
K
Keegan McAllister 已提交
962
        }
963
        let extname = pth.segments[0].identifier;
964 965 966 967
        let extnamestr = token::get_ident(extname);
        let marked_after = match fld.cx.syntax_env.find(&extname.name) {
            None => {
                fld.cx.span_err(pth.span,
J
Jorge Aparicio 已提交
968
                                &format!("macro undefined: '{}!'",
969
                                        extnamestr));
970 971 972
                // let compilation continue
                return DummyResult::raw_pat(span);
            }
K
Keegan McAllister 已提交
973

974
            Some(rc) => match *rc {
975
                NormalTT(ref expander, tt_span, allow_internal_unstable) => {
976 977 978
                    fld.cx.bt_push(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
979
                            name: extnamestr.to_string(),
980
                            format: MacroBang,
981 982
                            span: tt_span,
                            allow_internal_unstable: allow_internal_unstable,
983 984
                        }
                    });
K
Keegan McAllister 已提交
985

986
                    let fm = fresh_mark();
987
                    let marked_before = mark_tts(&tts[..], fm);
988
                    let mac_span = fld.cx.original_span();
989
                    let expanded = match expander.expand(fld.cx,
990
                                        mac_span,
991
                                        &marked_before[..]).make_pat() {
992 993 994 995
                        Some(e) => e,
                        None => {
                            fld.cx.span_err(
                                pth.span,
J
Jorge Aparicio 已提交
996
                                &format!(
997
                                    "non-pattern macro in pattern position: {}",
998
                                    &extnamestr
999
                                    )
1000 1001 1002 1003
                            );
                            return DummyResult::raw_pat(span);
                        }
                    };
1004

1005 1006 1007 1008 1009
                    // mark after:
                    mark_pat(expanded,fm)
                }
                _ => {
                    fld.cx.span_err(span,
J
Jorge Aparicio 已提交
1010
                                    &format!("{}! is not legal in pattern position",
1011
                                            &extnamestr));
1012 1013
                    return DummyResult::raw_pat(span);
                }
1014
            }
1015
        };
K
Keegan McAllister 已提交
1016

1017 1018 1019
        let fully_expanded =
            fld.fold_pat(marked_after).node.clone();
        fld.cx.bt_pop();
K
Keegan McAllister 已提交
1020

1021 1022 1023 1024 1025 1026
        ast::Pat {
            id: ast::DUMMY_NODE_ID,
            node: fully_expanded,
            span: span
        }
    })
K
Keegan McAllister 已提交
1027 1028
}

J
John Clements 已提交
1029 1030 1031
/// 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)
1032
pub struct IdentRenamer<'a> {
1033
    renames: &'a mtwt::RenameList,
1034 1035
}

1036
impl<'a> Folder for IdentRenamer<'a> {
1037 1038
    fn fold_ident(&mut self, id: Ident) -> Ident {
        Ident {
1039
            name: id.name,
1040
            ctxt: mtwt::apply_renames(self.renames, id.ctxt),
1041 1042
        }
    }
K
Keegan McAllister 已提交
1043 1044
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
1045
    }
1046 1047
}

J
John Clements 已提交
1048 1049 1050 1051 1052 1053 1054 1055 1056
/// 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> {
1057
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
J
John Clements 已提交
1058
        match pat.node {
1059 1060 1061 1062 1063 1064 1065 1066
            ast::PatIdent(..) => {},
            _ => return noop_fold_pat(pat, self)
        }

        pat.map(|ast::Pat {id, node, span}| match node {
            ast::PatIdent(binding_mode, Spanned{span: sp, node: ident}, sub) => {
                let new_ident = Ident{name: ident.name,
                                      ctxt: mtwt::apply_renames(self.renames, ident.ctxt)};
J
John Clements 已提交
1067 1068
                let new_node =
                    ast::PatIdent(binding_mode,
1069
                                  Spanned{span: self.new_span(sp), node: new_ident},
J
John Clements 已提交
1070
                                  sub.map(|p| self.fold_pat(p)));
1071 1072
                ast::Pat {
                    id: id,
J
John Clements 已提交
1073
                    node: new_node,
1074
                    span: self.new_span(span)
J
John Clements 已提交
1075 1076
                }
            },
1077 1078
            _ => unreachable!()
        })
1079
    }
K
Keegan McAllister 已提交
1080 1081
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
1082
    }
K
Kevin Atkinson 已提交
1083 1084
}

1085 1086 1087 1088 1089 1090 1091
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();
1092
    for attr in a.attrs() {
1093 1094
        let mname = attr.name();

1095
        match fld.cx.syntax_env.find(&intern(&mname)) {
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
            Some(rc) => match *rc {
                Decorator(ref dec) => {
                    let it = match a {
                        Annotatable::Item(ref it) => it,
                        // ItemDecorators are only implemented for Items.
                        _ => break,
                    };

                    attr::mark_used(attr);

                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
1109
                            name: mname.to_string(),
1110
                            format: MacroAttribute,
1111
                            span: Some(attr.span),
1112 1113 1114
                            // attributes can do whatever they like,
                            // for now.
                            allow_internal_unstable: true,
1115 1116 1117 1118 1119 1120 1121
                        }
                    });

                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
                    // but that double-mut-borrows fld
                    let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
                    dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
1122 1123 1124 1125
                               &mut |item| items.push(item));
                    decorator_items.extend(
                        items.into_iter()
                             .flat_map(|item| expand_item(item, fld).into_iter()));
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146

                    fld.cx.bt_pop();
                }
                _ => new_attrs.push((*attr).clone()),
            },
            _ => new_attrs.push((*attr).clone()),
        }
    }

    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);
                }
1147
                let macro_use = contains_macro_use(fld, &new_attrs[..]);
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
                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()
            }
        },
1164

1165
        Annotatable::TraitItem(it) => match it.node {
1166 1167 1168 1169 1170 1171 1172 1173 1174
            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))
                    }
1175
                    _ => unreachable!()
1176 1177 1178 1179 1180 1181
                },
                span: fld.new_span(ti.span)
            })),
            _ => fold::noop_fold_trait_item(it, fld)
        }.into_iter().map(Annotatable::TraitItem).collect(),

1182
        Annotatable::ImplItem(ii) => {
1183
            expand_impl_item(ii, fld).into_iter().map(Annotatable::ImplItem).collect()
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
        }
    };

    new_items.push_all(decorator_items.into_iter().map(|i| Annotatable::Item(i)).collect());
    new_items
}

// partition the attributes into ItemModifiers and others
fn modifiers(attrs: &Vec<ast::Attribute>,
             fld: &MacroExpander)
             -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
    attrs.iter().cloned().partition(|attr| {
1196
        match fld.cx.syntax_env.find(&intern(&attr.name())) {
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
            Some(rc) => match *rc {
                Modifier(_) => true,
                _ => false
            },
            _ => false
        }
    })
}

// partition the attributes into MultiModifiers and others
fn multi_modifiers(attrs: &[ast::Attribute],
                   fld: &MacroExpander)
                   -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
    attrs.iter().cloned().partition(|attr| {
1211
        match fld.cx.syntax_env.find(&intern(&attr.name())) {
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
            Some(rc) => match *rc {
                MultiModifier(_) => true,
                _ => false
            },
            _ => false
        }
    })
}

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
    }

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

1236
        match fld.cx.syntax_env.find(&intern(&mname)) {
1237 1238 1239 1240 1241 1242
            Some(rc) => match *rc {
                MultiModifier(ref mac) => {
                    attr::mark_used(attr);
                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
G
GuillaumeGomez 已提交
1243
                            name: mname.to_string(),
1244 1245
                            format: MacroAttribute,
                            span: None,
1246 1247 1248
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
                        }
                    });
                    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)
}

1264
fn expand_impl_item(ii: P<ast::ImplItem>, fld: &mut MacroExpander)
1265 1266
                 -> SmallVector<P<ast::ImplItem>> {
    match ii.node {
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
        ast::MethodImplItem(..) => SmallVector::one(ii.map(|ii| ast::ImplItem {
            id: ii.id,
            ident: ii.ident,
            attrs: ii.attrs,
            vis: ii.vis,
            node: match ii.node  {
                ast::MethodImplItem(sig, body) => {
                    let (sig, body) = expand_and_rename_method(sig, body, fld);
                    ast::MethodImplItem(sig, body)
                }
                _ => unreachable!()
            },
            span: fld.new_span(ii.span)
        })),
        ast::MacImplItem(_) => {
1282
            let (span, mac) = ii.and_then(|ii| match ii.node {
1283
                ast::MacImplItem(mac) => (ii.span, mac),
1284 1285
                _ => unreachable!()
            });
1286
            let maybe_new_items =
1287
                expand_mac_invoc(mac, span,
1288 1289
                                 |r| r.make_impl_items(),
                                 |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
J
John Clements 已提交
1290 1291
                                 fld);

1292 1293
            match maybe_new_items {
                Some(impl_items) => {
A
Adolfo Ochagavía 已提交
1294
                    // expand again if necessary
1295 1296 1297
                    let new_items = impl_items.into_iter().flat_map(|ii| {
                        expand_impl_item(ii, fld).into_iter()
                    }).collect();
A
Adolfo Ochagavía 已提交
1298
                    fld.cx.bt_pop();
1299
                    new_items
A
Adolfo Ochagavía 已提交
1300
                }
J
John Clements 已提交
1301
                None => SmallVector::zero()
A
Adolfo Ochagavía 已提交
1302
            }
1303
        }
1304
        _ => fold::noop_fold_impl_item(ii, fld)
1305
    }
1306 1307
}

J
John Clements 已提交
1308 1309 1310
/// 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.
1311
fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Block>,
J
John Clements 已提交
1312
                                       fld: &mut MacroExpander)
1313
                                       -> (P<ast::FnDecl>, P<ast::Block>) {
J
John Clements 已提交
1314
    let expanded_decl = fld.fold_fn_decl(fn_decl);
1315
    let idents = fn_decl_arg_bindings(&*expanded_decl);
J
John Clements 已提交
1316 1317 1318 1319
    let renames =
        idents.iter().map(|id : &ast::Ident| (*id,fresh_name(id))).collect();
    // first, a renamer for the PatIdents, for the fn_decl:
    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
1320
    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
J
John Clements 已提交
1321 1322 1323 1324 1325 1326
    // 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)
}

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
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,
        decl: rewritten_fn_decl
    }, rewritten_body)
}

J
John Clements 已提交
1341
/// A tree-folder that performs macro expansion
1342
pub struct MacroExpander<'a, 'b:'a> {
1343
    pub cx: &'a mut ExtCtxt<'b>,
N
Nick Cameron 已提交
1344 1345 1346 1347
}

impl<'a, 'b> MacroExpander<'a, 'b> {
    pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1348
        MacroExpander { cx: cx }
N
Nick Cameron 已提交
1349
    }
1350 1351
}

E
Eduard Burtescu 已提交
1352
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1353
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1354
        expand_expr(expr, self)
1355 1356
    }

1357
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
K
Keegan McAllister 已提交
1358 1359 1360
        expand_pat(pat, self)
    }

1361
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1362
        expand_item(item, self)
1363 1364
    }

1365
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
J
John Clements 已提交
1366 1367 1368
        expand_item_underscore(item, self)
    }

1369
    fn fold_stmt(&mut self, stmt: P<ast::Stmt>) -> SmallVector<P<ast::Stmt>> {
1370
        expand_stmt(stmt, self)
1371 1372
    }

S
Steven Fackler 已提交
1373
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1374
        expand_block(block, self)
1375 1376
    }

1377
    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
J
John Clements 已提交
1378 1379 1380
        expand_arm(arm, self)
    }

1381 1382 1383
    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()
1384 1385
    }

1386 1387 1388
    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()
1389 1390
    }

S
Steven Fackler 已提交
1391
    fn new_span(&mut self, span: Span) -> Span {
1392 1393
        new_span(self.cx, span)
    }
1394 1395
}

J
John Clements 已提交
1396 1397 1398 1399 1400
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,
1401
        expn_id: cx.backtrace(),
J
John Clements 已提交
1402 1403 1404
    }
}

1405
pub struct ExpansionConfig<'feat> {
1406
    pub crate_name: String,
1407
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1408
    pub recursion_limit: usize,
1409 1410
}

1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1424 1425
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1426 1427
        ExpansionConfig {
            crate_name: crate_name,
1428
            features: None,
1429
            recursion_limit: 64,
1430 1431
        }
    }
1432

1433 1434 1435 1436 1437 1438 1439
    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,
1440
        fn enable_custom_derive = allow_custom_derive,
1441
    }
1442 1443
}

1444 1445 1446 1447 1448 1449
pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
                           cfg: ExpansionConfig<'feat>,
                           // these are the macros being imported to this crate:
                           imported_macros: Vec<ast::MacroDef>,
                           user_exts: Vec<NamedSyntaxExtension>,
                           c: Crate) -> Crate {
1450
    let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
1451 1452
    cx.use_std = std_inject::use_std(&c);

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

1455
    for def in imported_macros {
1456
        expander.cx.insert_macro(def);
1457 1458
    }

1459
    for (name, extension) in user_exts {
1460
        expander.cx.syntax_env.insert(name, extension);
1461 1462
    }

1463 1464
    let mut ret = expander.fold_crate(c);
    ret.exported_macros = expander.cx.exported_macros.clone();
1465 1466
    parse_sess.span_diagnostic.handler().abort_if_errors();
    return ret;
1467
}
J
John Clements 已提交
1468

1469 1470 1471 1472 1473 1474 1475 1476
// 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 已提交
1477 1478
// A Marker adds the given mark to the syntax context
struct Marker { mark: Mrk }
1479

E
Eduard Burtescu 已提交
1480
impl Folder for Marker {
1481
    fn fold_ident(&mut self, id: Ident) -> Ident {
1482
        ast::Ident {
E
Eduard Burtescu 已提交
1483
            name: id.name,
1484
            ctxt: mtwt::apply_mark(self.mark, id.ctxt)
1485 1486
        }
    }
1487
    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1488
        Spanned {
1489 1490 1491
            node: match node {
                MacInvocTT(path, tts, ctxt) => {
                    MacInvocTT(self.fold_path(path),
1492
                               self.fold_tts(&tts[..]),
1493 1494 1495 1496
                               mtwt::apply_mark(self.mark, ctxt))
                }
            },
            span: span,
1497
        }
1498 1499 1500
    }
}

1501
// apply a given mark to the given token trees. Used prior to expansion of a macro.
1502
fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
M
Marvin Löbel 已提交
1503
    noop_fold_tts(tts, &mut Marker{mark:m})
1504 1505 1506
}

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

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

1516
// apply a given mark to the given stmt. Used following the expansion of a macro.
1517 1518
fn mark_stmt(stmt: P<ast::Stmt>, m: Mrk) -> P<ast::Stmt> {
    Marker{mark:m}.fold_stmt(stmt)
J
John Clements 已提交
1519
        .expect_one("marking a stmt didn't return exactly one stmt")
1520 1521 1522
}

// apply a given mark to the given item. Used following the expansion of a macro.
1523
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
J
John Clements 已提交
1524
    Marker{mark:m}.fold_item(expr)
J
John Clements 已提交
1525 1526 1527 1528
        .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.
1529
fn mark_impl_item(ii: P<ast::ImplItem>, m: Mrk) -> P<ast::ImplItem> {
1530
    Marker{mark:m}.fold_impl_item(ii)
1531
        .expect_one("marking an impl item didn't return exactly one impl item")
1532 1533
}

J
John Clements 已提交
1534 1535
/// Check that there are no macro invocations left in the AST:
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1536
    visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
J
John Clements 已提交
1537 1538 1539 1540 1541 1542 1543
}

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

1544
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
K
Keegan McAllister 已提交
1545 1546
    fn visit_mac(&mut self, mac: &ast::Mac) {
        self.sess.span_diagnostic.span_bug(mac.span,
J
John Clements 已提交
1547 1548 1549 1550 1551 1552
                                           "macro exterminator: expected AST \
                                           with no macro invocations");
    }
}


J
John Clements 已提交
1553 1554
#[cfg(test)]
mod test {
A
Alex Crichton 已提交
1555
    use super::{pattern_bindings, expand_crate};
1556
    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1557
    use ast;
J
Jorge Aparicio 已提交
1558
    use ast::Name;
1559
    use codemap;
1560
    use ext::mtwt;
1561
    use fold::Folder;
1562
    use parse;
1563
    use parse::token;
E
Eduard Burtescu 已提交
1564
    use util::parser_testing::{string_to_parser};
1565
    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1566
    use visit;
1567 1568 1569 1570 1571
    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)
1572
    #[derive(Clone)]
1573
    struct PathExprFinderContext {
1574
        path_accumulator: Vec<ast::Path> ,
1575 1576
    }

1577
    impl<'v> Visitor<'v> for PathExprFinderContext {
1578
        fn visit_expr(&mut self, expr: &ast::Expr) {
1579 1580
            if let ast::ExprPath(None, ref p) = expr.node {
                self.path_accumulator.push(p.clone());
1581
            }
1582
            visit::walk_expr(self, expr);
1583 1584 1585
        }
    }

1586 1587 1588
    // 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()};
1589
        visit::walk_crate(&mut path_finder, the_crate);
1590
        path_finder.path_accumulator
1591
    }
J
John Clements 已提交
1592

1593 1594
    /// A Visitor that extracts the identifiers from a thingy.
    // as a side note, I'm starting to want to abstract over these....
1595
    struct IdentFinder {
1596 1597
        ident_accumulator: Vec<ast::Ident>
    }
1598

1599
    impl<'v> Visitor<'v> for IdentFinder {
1600
        fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1601 1602 1603 1604 1605 1606 1607
            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()};
1608
        visit::walk_crate(&mut ident_finder, the_crate);
1609 1610
        ident_finder.ident_accumulator
    }
1611

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

1615
    fn test_ecfg() -> ExpansionConfig<'static> {
1616 1617 1618
        ExpansionConfig::default("test".to_string())
    }

J
John Clements 已提交
1619
    // make sure that macros can't escape fns
1620
    #[should_panic]
J
John Clements 已提交
1621
    #[test] fn macros_cant_escape_fns_test () {
1622
        let src = "fn bogus() {macro_rules! z (() => (3+4));}\
1623
                   fn inty() -> i32 { z!() }".to_string();
E
Eduard Burtescu 已提交
1624
        let sess = parse::new_parse_sess();
J
John Clements 已提交
1625
        let crate_ast = parse::parse_crate_from_source_str(
1626
            "<test>".to_string(),
1627
            src,
E
Eduard Burtescu 已提交
1628
            Vec::new(), &sess);
J
John Clements 已提交
1629
        // should fail:
1630
        expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
J
John Clements 已提交
1631 1632
    }

J
John Clements 已提交
1633
    // make sure that macros can't escape modules
1634
    #[should_panic]
J
John Clements 已提交
1635
    #[test] fn macros_cant_escape_mods_test () {
1636
        let src = "mod foo {macro_rules! z (() => (3+4));}\
1637
                   fn inty() -> i32 { z!() }".to_string();
E
Eduard Burtescu 已提交
1638
        let sess = parse::new_parse_sess();
J
John Clements 已提交
1639
        let crate_ast = parse::parse_crate_from_source_str(
1640
            "<test>".to_string(),
1641
            src,
E
Eduard Burtescu 已提交
1642
            Vec::new(), &sess);
1643
        expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
J
John Clements 已提交
1644 1645
    }

1646
    // macro_use modules should allow macros to escape
J
John Clements 已提交
1647
    #[test] fn macros_can_escape_flattened_mods_test () {
1648
        let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1649
                   fn inty() -> i32 { z!() }".to_string();
E
Eduard Burtescu 已提交
1650
        let sess = parse::new_parse_sess();
J
John Clements 已提交
1651
        let crate_ast = parse::parse_crate_from_source_str(
1652
            "<test>".to_string(),
1653
            src,
E
Eduard Burtescu 已提交
1654
            Vec::new(), &sess);
1655
        expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast);
J
John Clements 已提交
1656 1657
    }

1658
    fn expand_crate_str(crate_str: String) -> ast::Crate {
E
Eduard Burtescu 已提交
1659
        let ps = parse::new_parse_sess();
1660
        let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
1661
        // the cfg argument actually does matter, here...
1662
        expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast)
1663 1664
    }

1665 1666
    // find the pat_ident paths in a crate
    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1667
        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1668
        visit::walk_crate(&mut name_finder, the_crate);
1669 1670 1671
        name_finder.ident_accumulator
    }

1672
    #[test] fn macro_tokens_should_match(){
1673
        expand_crate_str(
1674
            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1675 1676
    }

1677 1678 1679
    // should be able to use a bound identifier as a literal in a macro definition:
    #[test] fn self_macro_parsing(){
        expand_crate_str(
1680 1681
            "macro_rules! foo ((zz) => (287;));
            fn f(zz: i32) {foo!(zz);}".to_string()
1682 1683 1684
            );
    }

1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
    // 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
    // three varrefs, the array ~[~[1,2],~[0]] would indicate that the first
    // binding should match the second two varrefs, and the second binding
    // should match the first varref.
    //
J
John Clements 已提交
1696 1697 1698 1699 1700 1701
    // 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.
    //
1702 1703
    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
    // names; differences in marks don't matter any more.
J
John Clements 已提交
1704
    //
1705
    // oog... I also want tests that check "bound-identifier-=?". That is,
J
John Clements 已提交
1706 1707 1708 1709 1710
    // 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 已提交
1711
    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1712

1713 1714
    #[test]
    fn automatic_renaming () {
1715 1716
        let tests: Vec<RenamingTest> =
            vec!(// b & c should get new names throughout, in the expr too:
1717
                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1718
                 vec!(vec!(0,1),vec!(2)), false),
J
John Clements 已提交
1719
                // both x's should be renamed (how is this causing a bug?)
1720
                ("fn main () {let x: i32 = 13;x;}",
1721
                 vec!(vec!(0)), false),
1722
                // the use of b after the + should be renamed, the other one not:
1723
                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1724
                 vec!(vec!(1)), false),
J
John Clements 已提交
1725
                // the b before the plus should not be renamed (requires marks)
1726
                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1727
                 vec!(vec!(1)), false),
1728 1729 1730
                // 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.
1731 1732
                ("macro_rules! letty(($x:ident) => (let $x = 15;));
                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
1733
                  fn main() -> i32 {user!(z)}",
1734 1735
                 vec!(vec!(0)), false)
                );
1736 1737
        for (idx,s) in tests.iter().enumerate() {
            run_renaming_test(s,idx);
1738 1739 1740
        }
    }

1741 1742 1743 1744 1745
    // 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 已提交
1746 1747
    #[test]
    fn issue_8062(){
1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
        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 已提交
1758 1759
    #[test]
    fn issue_6994(){
1760 1761
        run_renaming_test(
            &("macro_rules! g (($x:ident) =>
1762
              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1763 1764 1765
              fn a(){g!(z)}",
              vec!(vec!(0)),false),
            0)
1766 1767
    }

1768
    // match variable hygiene. Should expand into
1769
    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
R
Richo Healey 已提交
1770 1771
    #[test]
    fn issue_9384(){
1772
        run_renaming_test(
1773
            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1774
              fn z() {match 8 {x => bad_macro!(x)}}",
1775
              // NB: the third "binding" is the repeat of the second one.
1776
              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
1777 1778
              true),
            0)
1779 1780
    }

1781
    // interpolated nodes weren't getting labeled.
1782 1783
    // should expand into
    // fn main(){let g1_1 = 13; g1_1}}
R
Richo Healey 已提交
1784 1785
    #[test]
    fn pat_expand_issue_15221(){
1786
        run_renaming_test(
1787 1788
            &("macro_rules! inner ( ($e:pat ) => ($e));
              macro_rules! outer ( ($e:pat ) => (inner!($e)));
1789 1790 1791 1792 1793 1794
              fn main() { let outer!(g) = 13; g;}",
              vec!(vec!(0)),
              true),
            0)
    }

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

1799
    // method arg hygiene
1800
    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
R
Richo Healey 已提交
1801 1802
    #[test]
    fn method_arg_hygiene(){
1803
        run_renaming_test(
1804 1805
            &("macro_rules! inject_x (()=>(x));
              macro_rules! inject_self (()=>(self));
1806
              struct A;
1807
              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
1808 1809 1810 1811 1812
              vec!(vec!(0),vec!(3)),
              true),
            0)
    }

J
John Clements 已提交
1813 1814
    // ooh, got another bite?
    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
R
Richo Healey 已提交
1815 1816
    #[test]
    fn method_arg_hygiene_2(){
J
John Clements 已提交
1817 1818 1819
        run_renaming_test(
            &("struct A;
              macro_rules! add_method (($T:ty) =>
1820 1821
              (impl $T {  fn thingy(&self) {self;} }));
              add_method!(A);",
J
John Clements 已提交
1822 1823 1824 1825 1826
              vec!(vec!(0)),
              true),
            0)
    }

J
John Clements 已提交
1827
    // item fn hygiene
1828
    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
R
Richo Healey 已提交
1829 1830
    #[test]
    fn issue_9383(){
1831
        run_renaming_test(
1832 1833
            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
              fn q(x: i32) { bad_macro!(x); }",
1834
              vec!(vec!(1),vec!(0)),true),
1835
            0)
1836
    }
1837

1838
    // closure arg hygiene (ExprClosure)
1839
    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
R
Richo Healey 已提交
1840 1841
    #[test]
    fn closure_arg_hygiene(){
1842
        run_renaming_test(
1843
            &("macro_rules! inject_x (()=>(x));
1844
            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
1845 1846 1847 1848 1849
              vec!(vec!(1)),
              true),
            0)
    }

1850
    // macro_rules in method position. Sadly, unimplemented.
R
Richo Healey 已提交
1851 1852
    #[test]
    fn macro_in_method_posn(){
1853
        expand_crate_str(
1854
            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
1855
            struct A;
1856
            impl A{ my_method!(); }
1857 1858 1859
            fn f(){A.thirteen;}".to_string());
    }

1860 1861
    // another nested macro
    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
R
Richo Healey 已提交
1862 1863
    #[test]
    fn item_macro_workaround(){
1864 1865 1866 1867
        run_renaming_test(
            &("macro_rules! item { ($i:item) => {$i}}
              struct Entries;
              macro_rules! iterator_impl {
1868
              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
1869 1870 1871 1872 1873
              iterator_impl! { }",
              vec!(vec!(0)), true),
            0)
    }

J
John Clements 已提交
1874
    // run one of the renaming tests
P
Paul Collier 已提交
1875
    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
J
John Clements 已提交
1876
        let invalid_name = token::special_idents::invalid.name;
J
John Clements 已提交
1877
        let (teststr, bound_connections, bound_ident_check) = match *t {
1878
            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
1879
        };
1880
        let cr = expand_crate_str(teststr.to_string());
1881 1882
        let bindings = crate_bindings(&cr);
        let varrefs = crate_varrefs(&cr);
1883

1884 1885 1886
        // must be one check clause for each binding:
        assert_eq!(bindings.len(),bound_connections.len());
        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
1887 1888
            let binding_name = mtwt::resolve(bindings[binding_idx]);
            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
1889 1890 1891 1892
            // shouldmatch can't name varrefs that don't exist:
            assert!((shouldmatch.len() == 0) ||
                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
            for (idx,varref) in varrefs.iter().enumerate() {
1893
                let print_hygiene_debug_info = || {
J
John Clements 已提交
1894 1895 1896
                    // 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 已提交
1897
                        None => panic!("varref with 0 path segments?")
J
John Clements 已提交
1898 1899 1900 1901 1902
                    };
                    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 已提交
1903
                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
J
John Clements 已提交
1904
                    let string = token::get_ident(final_varref_ident);
1905
                    println!("varref's first segment's string: \"{}\"", &string[..]);
J
John Clements 已提交
1906
                    println!("binding #{}: {}, resolves to {}",
1907
                             binding_idx, bindings[binding_idx], binding_name);
J
John Clements 已提交
1908 1909
                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
                };
1910 1911
                if shouldmatch.contains(&idx) {
                    // it should be a path of length 1, and it should
J
John Clements 已提交
1912
                    // be free-identifier=? or bound-identifier=? to the given binding
1913
                    assert_eq!(varref.segments.len(),1);
1914 1915
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
                    let varref_marks = mtwt::marksof(varref.segments[0]
1916 1917 1918
                                                           .identifier
                                                           .ctxt,
                                                     invalid_name);
1919
                    if !(varref_name==binding_name) {
1920
                        println!("uh oh, should match but doesn't:");
J
John Clements 已提交
1921
                        print_hygiene_debug_info();
1922 1923
                    }
                    assert_eq!(varref_name,binding_name);
1924
                    if bound_ident_check {
J
John Clements 已提交
1925 1926
                        // we're checking bound-identifier=?, and the marks
                        // should be the same, too:
J
John Clements 已提交
1927 1928
                        assert_eq!(varref_marks,binding_marks.clone());
                    }
1929
                } else {
1930
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
1931
                    let fail = (varref.segments.len() == 1)
1932
                        && (varref_name == binding_name);
1933
                    // temp debugging:
1934
                    if fail {
1935 1936 1937 1938
                        println!("failure on test {}",test_idx);
                        println!("text of test case: \"{}\"", teststr);
                        println!("");
                        println!("uh oh, matches but shouldn't:");
J
John Clements 已提交
1939
                        print_hygiene_debug_info();
1940 1941 1942 1943
                    }
                    assert!(!fail);
                }
            }
1944 1945
        }
    }
1946

R
Richo Healey 已提交
1947 1948
    #[test]
    fn fmt_in_macro_used_inside_module_macro() {
1949 1950 1951
        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!();
1952
".to_string();
J
John Clements 已提交
1953 1954
        let cr = expand_crate_str(crate_str);
        // find the xx binding
1955
        let bindings = crate_bindings(&cr);
1956
        let cxbinds: Vec<&ast::Ident> =
1957 1958
            bindings.iter().filter(|b| {
                let ident = token::get_ident(**b);
1959
                let string = &ident[..];
1960 1961
                "xx" == string
            }).collect();
1962
        let cxbinds: &[&ast::Ident] = &cxbinds[..];
J
John Clements 已提交
1963 1964
        let cxbind = match cxbinds {
            [b] => b,
S
Steve Klabnik 已提交
1965
            _ => panic!("expected just one binding for ext_cx")
J
John Clements 已提交
1966
        };
1967
        let resolved_binding = mtwt::resolve(*cxbind);
1968
        let varrefs = crate_varrefs(&cr);
1969

J
John Clements 已提交
1970
        // the xx binding should bind all of the xx varrefs:
1971
        for (idx,v) in varrefs.iter().filter(|p| {
1972
            p.segments.len() == 1
M
Manish Goregaokar 已提交
1973
            && "xx" == &*token::get_ident(p.segments[0].identifier)
1974
        }).enumerate() {
1975
            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
1976
                println!("uh oh, xx binding didn't match xx varref:");
L
Luqman Aden 已提交
1977 1978 1979
                println!("this is xx varref \\# {}", idx);
                println!("binding: {}", cxbind);
                println!("resolves to: {}", resolved_binding);
1980
                println!("varref: {}", v.segments[0].identifier);
L
Luqman Aden 已提交
1981
                println!("resolves to: {}",
1982
                         mtwt::resolve(v.segments[0].identifier));
1983
                mtwt::with_sctable(|x| mtwt::display_sctable(x));
J
John Clements 已提交
1984
            }
1985
            assert_eq!(mtwt::resolve(v.segments[0].identifier),
1986
                       resolved_binding);
J
John Clements 已提交
1987 1988 1989
        };
    }

J
John Clements 已提交
1990 1991
    #[test]
    fn pat_idents(){
1992
        let pat = string_to_pat(
1993
            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
1994
        let idents = pattern_bindings(&*pat);
1995
        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
J
John Clements 已提交
1996
    }
J
John Clements 已提交
1997

1998 1999 2000
    // 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.
2001
    #[test]
2002
    fn crate_bindings_test(){
2003
        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
2004
        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
2005 2006
        let idents = crate_bindings(&the_crate);
        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
2007 2008
    }

2009 2010 2011
    // test the IdentRenamer directly
    #[test]
    fn ident_renamer_test () {
2012
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
2013 2014
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
2015
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
2016
        let renames = vec!((x_ident,Name(16)));
2017 2018 2019 2020
        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();
2021
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
2022 2023 2024 2025 2026
    }

    // test the PatIdentRenamer; only PatIdents get renamed
    #[test]
    fn pat_ident_renamer_test () {
2027
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
2028 2029
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
2030
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
2031
        let renames = vec!((x_ident,Name(16)));
2032 2033 2034 2035 2036
        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;
2037
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
2038
    }
J
John Clements 已提交
2039
}