base.rs 27.2 KB
Newer Older
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;
12
use ast::Name;
13
use codemap;
14
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
15
use ext;
16
use ext::expand;
17
use parse;
18
use parse::parser;
A
Alex Crichton 已提交
19
use parse::token;
P
Patrick Walton 已提交
20
use parse::token::{InternedString, intern, str_to_ident};
21
use ptr::P;
S
Steven Fackler 已提交
22
use util::small_vector::SmallVector;
23
use ext::mtwt;
24
use fold::Folder;
25

26
use std::collections::HashMap;
27
use std::rc::Rc;
28

29 30
// new-style macro! tt code:
//
31
//    MacResult, NormalTT, IdentTT
32
//
33
// also note that ast::Mac used to have a bunch of extraneous cases and
34
// is now probably a redundant AST node, can be merged with
35
// ast::MacInvocTT.
36

37
pub struct MacroDef {
38
    pub name: String,
39
    pub ext: SyntaxExtension
40
}
41

42 43 44 45
pub trait ItemDecorator {
    fn expand(&self,
              ecx: &mut ExtCtxt,
              sp: Span,
46 47 48
              meta_item: &ast::MetaItem,
              item: &ast::Item,
              push: |P<ast::Item>|);
49 50
}

51
impl ItemDecorator for fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, |P<ast::Item>|) {
52 53 54
    fn expand(&self,
              ecx: &mut ExtCtxt,
              sp: Span,
55 56 57
              meta_item: &ast::MetaItem,
              item: &ast::Item,
              push: |P<ast::Item>|) {
58 59 60
        (*self)(ecx, sp, meta_item, item, push)
    }
}
61

62 63 64 65
pub trait ItemModifier {
    fn expand(&self,
              ecx: &mut ExtCtxt,
              span: Span,
66 67 68
              meta_item: &ast::MetaItem,
              item: P<ast::Item>)
              -> P<ast::Item>;
69 70
}

71
impl ItemModifier for fn(&mut ExtCtxt, Span, &ast::MetaItem, P<ast::Item>) -> P<ast::Item> {
72 73 74
    fn expand(&self,
              ecx: &mut ExtCtxt,
              span: Span,
75 76 77
              meta_item: &ast::MetaItem,
              item: P<ast::Item>)
              -> P<ast::Item> {
78 79 80
        (*self)(ecx, span, meta_item, item)
    }
}
81

82 83
/// Represents a thing that maps token trees to Macro Results
pub trait TTMacroExpander {
84 85 86 87 88
    fn expand<'cx>(&self,
                   ecx: &'cx mut ExtCtxt,
                   span: Span,
                   token_tree: &[ast::TokenTree])
                   -> Box<MacResult+'cx>;
89 90
}

S
Steven Fackler 已提交
91
pub type MacroExpanderFn =
92
    for<'cx> fn(&'cx mut ExtCtxt, Span, &[ast::TokenTree]) -> Box<MacResult+'cx>;
93

94
impl TTMacroExpander for MacroExpanderFn {
95 96 97 98 99
    fn expand<'cx>(&self,
                   ecx: &'cx mut ExtCtxt,
                   span: Span,
                   token_tree: &[ast::TokenTree])
                   -> Box<MacResult+'cx> {
100
        (*self)(ecx, span, token_tree)
101 102
    }
}
J
John Clements 已提交
103

S
Steven Fackler 已提交
104
pub trait IdentMacroExpander {
105 106 107 108 109 110
    fn expand<'cx>(&self,
                   cx: &'cx mut ExtCtxt,
                   sp: Span,
                   ident: ast::Ident,
                   token_tree: Vec<ast::TokenTree> )
                   -> Box<MacResult+'cx>;
111 112
}

113
pub type IdentMacroExpanderFn =
114
    for<'cx> fn(&'cx mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree>) -> Box<MacResult+'cx>;
115 116

impl IdentMacroExpander for IdentMacroExpanderFn {
117 118 119 120 121 122
    fn expand<'cx>(&self,
                   cx: &'cx mut ExtCtxt,
                   sp: Span,
                   ident: ast::Ident,
                   token_tree: Vec<ast::TokenTree> )
                   -> Box<MacResult+'cx> {
123
        (*self)(cx, sp, ident, token_tree)
124 125 126
    }
}

127 128 129 130
/// The result of a macro expansion. The return values of the various
/// methods are spliced into the AST at the callsite of the macro (or
/// just into the compiler's internal macro table, for `make_def`).
pub trait MacResult {
131
    /// Attempt to define a new macro.
132 133 134
    // this should go away; the idea that a macro might expand into
    // either a macro definition or an expression, depending on what
    // the context wants, is kind of silly.
135
    fn make_def(&mut self) -> Option<MacroDef> {
136 137 138
        None
    }
    /// Create an expression.
139
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
140 141 142
        None
    }
    /// Create zero or more items.
143
    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
144 145
        None
    }
146 147

    /// Create zero or more methods.
148
    fn make_methods(self: Box<Self>) -> Option<SmallVector<P<ast::Method>>> {
149 150 151
        None
    }

K
Keegan McAllister 已提交
152
    /// Create a pattern.
153
    fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
K
Keegan McAllister 已提交
154 155
        None
    }
156 157 158 159 160

    /// Create a statement.
    ///
    /// By default this attempts to create an expression statement,
    /// returning None if that fails.
161
    fn make_stmt(self: Box<Self>) -> Option<P<ast::Stmt>> {
162
        self.make_expr()
163
            .map(|e| P(codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID))))
164
    }
165
}
J
John Clements 已提交
166

167 168
/// A convenience type for macros that return a single expression.
pub struct MacExpr {
169
    e: P<ast::Expr>
170 171
}
impl MacExpr {
172
    pub fn new(e: P<ast::Expr>) -> Box<MacResult+'static> {
173
        box MacExpr { e: e } as Box<MacResult+'static>
174 175 176
    }
}
impl MacResult for MacExpr {
177
    fn make_expr(self: Box<MacExpr>) -> Option<P<ast::Expr>> {
178 179
        Some(self.e)
    }
180
    fn make_pat(self: Box<MacExpr>) -> Option<P<ast::Pat>> {
181
        match self.e.node {
182
            ast::ExprLit(_) => Some(P(ast::Pat {
183
                id: ast::DUMMY_NODE_ID,
184 185 186
                span: self.e.span,
                node: ast::PatLit(self.e)
            })),
187 188 189
            _ => None
        }
    }
190
}
K
Keegan McAllister 已提交
191 192
/// A convenience type for macros that return a single pattern.
pub struct MacPat {
193
    p: P<ast::Pat>
K
Keegan McAllister 已提交
194 195
}
impl MacPat {
196
    pub fn new(p: P<ast::Pat>) -> Box<MacResult+'static> {
197
        box MacPat { p: p } as Box<MacResult+'static>
K
Keegan McAllister 已提交
198 199 200
    }
}
impl MacResult for MacPat {
201
    fn make_pat(self: Box<MacPat>) -> Option<P<ast::Pat>> {
K
Keegan McAllister 已提交
202 203 204
        Some(self.p)
    }
}
205 206 207
/// A type for macros that return multiple items.
pub struct MacItems {
    items: SmallVector<P<ast::Item>>
208
}
209 210 211 212

impl MacItems {
    pub fn new<I: Iterator<P<ast::Item>>>(mut it: I) -> Box<MacResult+'static> {
        box MacItems { items: it.collect() } as Box<MacResult+'static>
213 214
    }
}
215 216 217 218

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(self.items)
219 220
    }
}
221

222 223 224 225 226
/// Fill-in macro expansion result, to allow compilation to continue
/// after hitting errors.
pub struct DummyResult {
    expr_only: bool,
    span: Span
227
}
228 229 230 231 232 233

impl DummyResult {
    /// Create a default MacResult that can be anything.
    ///
    /// Use this as a return value after hitting any errors and
    /// calling `span_err`.
234 235
    pub fn any(sp: Span) -> Box<MacResult+'static> {
        box DummyResult { expr_only: false, span: sp } as Box<MacResult+'static>
236 237 238 239 240
    }

    /// Create a default MacResult that can only be an expression.
    ///
    /// Use this for macros that must expand to an expression, so even
241
    /// if an error is encountered internally, the user will receive
242
    /// an error that they also used it in the wrong place.
243 244
    pub fn expr(sp: Span) -> Box<MacResult+'static> {
        box DummyResult { expr_only: true, span: sp } as Box<MacResult+'static>
245 246 247
    }

    /// A plain dummy expression.
248 249
    pub fn raw_expr(sp: Span) -> P<ast::Expr> {
        P(ast::Expr {
250
            id: ast::DUMMY_NODE_ID,
251
            node: ast::ExprLit(P(codemap::respan(sp, ast::LitNil))),
252
            span: sp,
253
        })
254
    }
K
Keegan McAllister 已提交
255 256

    /// A plain dummy pattern.
257 258
    pub fn raw_pat(sp: Span) -> ast::Pat {
        ast::Pat {
K
Keegan McAllister 已提交
259
            id: ast::DUMMY_NODE_ID,
260
            node: ast::PatWild(ast::PatWildSingle),
K
Keegan McAllister 已提交
261 262 263
            span: sp,
        }
    }
264

265
}
266 267

impl MacResult for DummyResult {
268
    fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> {
269
        Some(DummyResult::raw_expr(self.span))
270
    }
271 272
    fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> {
        Some(P(DummyResult::raw_pat(self.span)))
K
Keegan McAllister 已提交
273
    }
274
    fn make_items(self: Box<DummyResult>) -> Option<SmallVector<P<ast::Item>>> {
275 276 277 278 279 280 281
        // this code needs a comment... why not always just return the Some() ?
        if self.expr_only {
            None
        } else {
            Some(SmallVector::zero())
        }
    }
282
    fn make_methods(self: Box<DummyResult>) -> Option<SmallVector<P<ast::Method>>> {
283 284 285 286 287
        if self.expr_only {
            None
        } else {
            Some(SmallVector::zero())
        }
288
    }
289 290 291 292
    fn make_stmt(self: Box<DummyResult>) -> Option<P<ast::Stmt>> {
        Some(P(codemap::respan(self.span,
                               ast::StmtExpr(DummyResult::raw_expr(self.span),
                                             ast::DUMMY_NODE_ID))))
293
    }
294
}
295

296
/// An enum representing the different kinds of syntax extensions.
297
pub enum SyntaxExtension {
298 299 300 301
    /// A syntax extension that is attached to an item and creates new items
    /// based upon it.
    ///
    /// `#[deriving(...)]` is an `ItemDecorator`.
302
    Decorator(Box<ItemDecorator + 'static>),
303

304 305
    /// A syntax extension that is attached to an item and modifies it
    /// in-place.
306
    Modifier(Box<ItemModifier + 'static>),
307

308 309 310
    /// A normal, function-like syntax extension.
    ///
    /// `bytes!` is a `NormalTT`.
311
    NormalTT(Box<TTMacroExpander + 'static>, Option<Span>),
J
John Clements 已提交
312

313 314 315
    /// A function-like syntax extension that has an extra ident before
    /// the block.
    ///
A
Alex Crichton 已提交
316
    IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
J
John Clements 已提交
317 318 319 320 321 322 323 324

    /// An ident macro that has two properties:
    /// - it adds a macro definition to the environment, and
    /// - the definition it adds doesn't introduce any new
    ///   identifiers.
    ///
    /// `macro_rules!` is a LetSyntaxTT
    LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
325
}
326

327 328
pub type NamedSyntaxExtension = (Name, SyntaxExtension);

329
pub struct BlockInfo {
330
    /// Should macros escape from this scope?
331
    pub macros_escape: bool,
332
    /// What are the pending renames?
333
    pub pending_renames: mtwt::RenameList,
S
Steven Fackler 已提交
334 335 336 337 338 339
}

impl BlockInfo {
    pub fn new() -> BlockInfo {
        BlockInfo {
            macros_escape: false,
340
            pending_renames: Vec::new(),
S
Steven Fackler 已提交
341 342
        }
    }
J
John Clements 已提交
343
}
344

345 346
/// The base map of methods for expanding syntax extension
/// AST nodes into full ASTs
347
fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
J
John Clements 已提交
348
    // utility function to simplify creating NormalTT syntax extensions
S
Steven Fackler 已提交
349
    fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
350
        NormalTT(box f, None)
351
    }
K
Kiet Tran 已提交
352

353
    let mut syntax_expanders = SyntaxEnv::new();
354
    syntax_expanders.insert(intern("macro_rules"),
355
                            LetSyntaxTT(box ext::tt::macro_rules::add_new_extension, None));
356
    syntax_expanders.insert(intern("fmt"),
S
Steven Fackler 已提交
357
                            builtin_normal_expander(
358
                                ext::fmt::expand_syntax_ext));
359
    syntax_expanders.insert(intern("format_args"),
S
Steven Fackler 已提交
360
                            builtin_normal_expander(
361 362 363 364
                                ext::format::expand_format_args));
    syntax_expanders.insert(intern("format_args_method"),
                            builtin_normal_expander(
                                ext::format::expand_format_args_method));
365
    syntax_expanders.insert(intern("env"),
S
Steven Fackler 已提交
366
                            builtin_normal_expander(
367
                                    ext::env::expand_env));
368
    syntax_expanders.insert(intern("option_env"),
S
Steven Fackler 已提交
369
                            builtin_normal_expander(
370
                                    ext::env::expand_option_env));
371
    syntax_expanders.insert(intern("bytes"),
S
Steven Fackler 已提交
372
                            builtin_normal_expander(
373
                                    ext::bytes::expand_syntax_ext));
374
    syntax_expanders.insert(intern("concat_idents"),
S
Steven Fackler 已提交
375
                            builtin_normal_expander(
376
                                    ext::concat_idents::expand_syntax_ext));
377
    syntax_expanders.insert(intern("concat"),
S
Steven Fackler 已提交
378
                            builtin_normal_expander(
379
                                    ext::concat::expand_syntax_ext));
380
    syntax_expanders.insert(intern("log_syntax"),
S
Steven Fackler 已提交
381
                            builtin_normal_expander(
382
                                    ext::log_syntax::expand_syntax_ext));
383
    syntax_expanders.insert(intern("deriving"),
384
                            Decorator(box ext::deriving::expand_meta_deriving));
385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    if ecfg.enable_quotes {
        // Quasi-quoting expanders
        syntax_expanders.insert(intern("quote_tokens"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_tokens));
        syntax_expanders.insert(intern("quote_expr"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_expr));
        syntax_expanders.insert(intern("quote_ty"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_ty));
        syntax_expanders.insert(intern("quote_method"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_method));
        syntax_expanders.insert(intern("quote_item"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_item));
        syntax_expanders.insert(intern("quote_pat"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_pat));
        syntax_expanders.insert(intern("quote_arm"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_arm));
        syntax_expanders.insert(intern("quote_stmt"),
                           builtin_normal_expander(
                                ext::quote::expand_quote_stmt));
    }
413

414
    syntax_expanders.insert(intern("line"),
S
Steven Fackler 已提交
415
                            builtin_normal_expander(
416
                                    ext::source_util::expand_line));
417
    syntax_expanders.insert(intern("col"),
S
Steven Fackler 已提交
418
                            builtin_normal_expander(
419
                                    ext::source_util::expand_col));
420
    syntax_expanders.insert(intern("file"),
S
Steven Fackler 已提交
421
                            builtin_normal_expander(
422
                                    ext::source_util::expand_file));
423
    syntax_expanders.insert(intern("stringify"),
S
Steven Fackler 已提交
424
                            builtin_normal_expander(
425
                                    ext::source_util::expand_stringify));
426
    syntax_expanders.insert(intern("include"),
S
Steven Fackler 已提交
427
                            builtin_normal_expander(
428
                                    ext::source_util::expand_include));
429
    syntax_expanders.insert(intern("include_str"),
S
Steven Fackler 已提交
430
                            builtin_normal_expander(
431
                                    ext::source_util::expand_include_str));
432
    syntax_expanders.insert(intern("include_bin"),
S
Steven Fackler 已提交
433
                            builtin_normal_expander(
434
                                    ext::source_util::expand_include_bin));
435
    syntax_expanders.insert(intern("module_path"),
S
Steven Fackler 已提交
436
                            builtin_normal_expander(
437
                                    ext::source_util::expand_mod));
438
    syntax_expanders.insert(intern("asm"),
S
Steven Fackler 已提交
439
                            builtin_normal_expander(
440
                                    ext::asm::expand_asm));
441
    syntax_expanders.insert(intern("cfg"),
S
Steven Fackler 已提交
442
                            builtin_normal_expander(
443
                                    ext::cfg::expand_cfg));
S
Steven Fackler 已提交
444
    syntax_expanders.insert(intern("cfg_attr"),
S
Steven Fackler 已提交
445
                            Modifier(box ext::cfg_attr::expand));
446
    syntax_expanders.insert(intern("trace_macros"),
S
Steven Fackler 已提交
447
                            builtin_normal_expander(
448
                                    ext::trace_macros::expand_trace_macros));
S
Steven Fackler 已提交
449
    syntax_expanders
450
}
451

452 453 454
/// One of these is made during expansion and incrementally updated as we go;
/// when a macro expansion occurs, the resulting nodes have the backtrace()
/// -> expn_info of their expansion context stored into their span.
455
pub struct ExtCtxt<'a> {
456 457
    pub parse_sess: &'a parse::ParseSess,
    pub cfg: ast::CrateConfig,
458
    pub backtrace: ExpnId,
459
    pub ecfg: expand::ExpansionConfig,
460

461 462
    pub mod_path: Vec<ast::Ident> ,
    pub trace_mac: bool,
463
    pub exported_macros: Vec<P<ast::Item>>,
464

465
    pub syntax_env: SyntaxEnv,
466
    pub recursion_count: uint,
467
}
N
Niko Matsakis 已提交
468

469
impl<'a> ExtCtxt<'a> {
E
Eduard Burtescu 已提交
470
    pub fn new<'a>(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
471
                   ecfg: expand::ExpansionConfig) -> ExtCtxt<'a> {
472
        let env = initial_syntax_expander_table(&ecfg);
S
Steven Fackler 已提交
473
        ExtCtxt {
474 475
            parse_sess: parse_sess,
            cfg: cfg,
476
            backtrace: NO_EXPANSION,
477
            mod_path: Vec::new(),
478
            ecfg: ecfg,
479 480
            trace_mac: false,
            exported_macros: Vec::new(),
481
            syntax_env: env,
482
            recursion_count: 0,
483 484 485
        }
    }

486
    #[deprecated = "Replaced with `expander().fold_expr()`"]
487
    pub fn expand_expr(&mut self, e: P<ast::Expr>) -> P<ast::Expr> {
488 489 490 491 492 493
        self.expander().fold_expr(e)
    }

    /// Returns a `Folder` for deeply expanding all macros in a AST node.
    pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
        expand::MacroExpander { cx: self }
494 495
    }

496 497
    pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
        -> parser::Parser<'a> {
498
        parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
499 500
    }

E
Eduard Burtescu 已提交
501
    pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
E
Eduard Burtescu 已提交
502
    pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
503
    pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
504
    pub fn call_site(&self) -> Span {
505
        self.codemap().with_expn_info(self.backtrace, |ei| match ei {
506
            Some(expn_info) => expn_info.call_site,
507
            None => self.bug("missing top span")
508
        })
509
    }
510
    pub fn print_backtrace(&self) { }
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
    pub fn backtrace(&self) -> ExpnId { self.backtrace }
    pub fn original_span(&self) -> Span {
        let mut expn_id = self.backtrace;
        let mut call_site = None;
        loop {
            match self.codemap().with_expn_info(expn_id, |ei| ei.map(|ei| ei.call_site)) {
                None => break,
                Some(cs) => {
                    call_site = Some(cs);
                    expn_id = cs.expn_id;
                }
            }
        }
        call_site.expect("missing expansion backtrace")
    }
    pub fn original_span_in_file(&self) -> Span {
        let mut expn_id = self.backtrace;
        let mut call_site = None;
        loop {
            let expn_info = self.codemap().with_expn_info(expn_id, |ei| {
                ei.map(|ei| (ei.call_site, ei.callee.name.as_slice() == "include"))
            });
            match expn_info {
                None => break,
                Some((cs, is_include)) => {
                    if is_include {
                        // Don't recurse into file using "include!".
                        break;
                    }
                    call_site = Some(cs);
                    expn_id = cs.expn_id;
                }
            }
        }
        call_site.expect("missing expansion backtrace")
    }

S
Steven Fackler 已提交
548
    pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
549
    pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
550 551
    pub fn mod_path(&self) -> Vec<ast::Ident> {
        let mut v = Vec::new();
552
        v.push(token::str_to_ident(self.ecfg.crate_name.as_slice()));
553
        v.extend(self.mod_path.iter().map(|a| *a));
554 555
        return v;
    }
556
    pub fn bt_push(&mut self, ei: ExpnInfo) {
557 558 559
        self.recursion_count += 1;
        if self.recursion_count > self.ecfg.recursion_limit {
            self.span_fatal(ei.call_site,
J
Jakub Wieczorek 已提交
560
                            format!("recursion limit reached while expanding the macro `{}`",
561 562 563
                                    ei.callee.name).as_slice());
        }

564 565 566 567 568 569
        let mut call_site = ei.call_site;
        call_site.expn_id = self.backtrace;
        self.backtrace = self.codemap().record_expansion(ExpnInfo {
            call_site: call_site,
            callee: ei.callee
        });
570
    }
S
Steven Fackler 已提交
571 572
    pub fn bt_pop(&mut self) {
        match self.backtrace {
573 574
            NO_EXPANSION => self.bug("tried to pop without a push"),
            expn_id => {
575
                self.recursion_count -= 1;
576 577 578 579
                self.backtrace = self.codemap().with_expn_info(expn_id, |expn_info| {
                    expn_info.map_or(NO_EXPANSION, |ei| ei.call_site.expn_id)
                });
            }
580 581
        }
    }
582 583
    /// Emit `msg` attached to `sp`, and stop compilation immediately.
    ///
J
Joseph Crail 已提交
584
    /// `span_err` should be strongly preferred where-ever possible:
585 586 587 588 589 590 591 592
    /// this should *only* be used when
    /// - continuing has a high risk of flow-on errors (e.g. errors in
    ///   declaring a macro would cause all uses of that macro to
    ///   complain about "undefined macro"), or
    /// - there is literally nothing else that can be done (however,
    ///   in most cases one can construct a dummy expression/item to
    ///   substitute; we never hit resolve/type-checking so the dummy
    ///   value doesn't have to match anything)
593
    pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
594 595 596
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_fatal(sp, msg);
    }
597 598 599 600 601 602

    /// Emit `msg` attached to `sp`, without immediately stopping
    /// compilation.
    ///
    /// Compilation will be stopped in the near future (at the end of
    /// the macro expansion phase).
603
    pub fn span_err(&self, sp: Span, msg: &str) {
604 605 606
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_err(sp, msg);
    }
607
    pub fn span_warn(&self, sp: Span, msg: &str) {
608 609 610
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_warn(sp, msg);
    }
611
    pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
612 613 614
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
    }
615
    pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
616 617 618
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_bug(sp, msg);
    }
S
Steven Fackler 已提交
619 620 621 622
    pub fn span_note(&self, sp: Span, msg: &str) {
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_note(sp, msg);
    }
P
P1start 已提交
623 624 625 626
    pub fn span_help(&self, sp: Span, msg: &str) {
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_help(sp, msg);
    }
627
    pub fn bug(&self, msg: &str) -> ! {
628 629 630
        self.print_backtrace();
        self.parse_sess.span_diagnostic.handler().bug(msg);
    }
631
    pub fn trace_macros(&self) -> bool {
S
Steven Fackler 已提交
632
        self.trace_mac
633
    }
S
Steven Fackler 已提交
634 635
    pub fn set_trace_macros(&mut self, x: bool) {
        self.trace_mac = x
636
    }
637
    pub fn ident_of(&self, st: &str) -> ast::Ident {
638
        str_to_ident(st)
639
    }
C
Corey Richardson 已提交
640 641 642
    pub fn name_of(&self, st: &str) -> ast::Name {
        token::intern(st)
    }
643 644
}

645 646 647
/// Extract a string literal from the macro expanded version of `expr`,
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
/// compilation on error, merely emits a non-fatal error and returns None.
648 649
pub fn expr_to_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str)
                      -> Option<(InternedString, ast::StrStyle)> {
650
    // we want to be able to handle e.g. concat("foo", "bar")
651
    let expr = cx.expander().fold_expr(expr);
652
    match expr.node {
653
        ast::ExprLit(ref l) => match l.node {
P
Patrick Walton 已提交
654
            ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
655
            _ => cx.span_err(l.span, err_msg)
656
        },
657
        _ => cx.span_err(expr.span, err_msg)
658
    }
659
    None
660 661
}

662 663 664 665 666
/// Non-fatally assert that `tts` is empty. Note that this function
/// returns even when `tts` is non-empty, macros that *need* to stop
/// compilation should call
/// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
/// done as rarely as possible).
667 668 669
pub fn check_zero_tts(cx: &ExtCtxt,
                      sp: Span,
                      tts: &[ast::TokenTree],
670
                      name: &str) {
671
    if tts.len() != 0 {
672
        cx.span_err(sp, format!("{} takes no arguments", name).as_slice());
673
    }
674 675
}

676 677
/// Extract the string literal from the first token of `tts`. If this
/// is not a string literal, emit an error and return None.
678
pub fn get_single_str_from_tts(cx: &mut ExtCtxt,
679
                               sp: Span,
680
                               tts: &[ast::TokenTree],
681
                               name: &str)
682
                               -> Option<String> {
683
    let mut p = cx.new_parser_from_tts(tts);
A
Alex Crichton 已提交
684 685 686 687
    if p.token == token::Eof {
        cx.span_err(sp, format!("{} takes 1 argument", name).as_slice());
        return None
    }
688 689 690
    let ret = cx.expander().fold_expr(p.parse_expr());
    if p.token != token::Eof {
        cx.span_err(sp, format!("{} takes 1 argument", name).as_slice());
691
    }
692 693 694
    expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| {
        s.get().to_string()
    })
695
}
696

697 698
/// Extract comma-separated expressions from `tts`. If there is a
/// parsing error, emit a non-fatal error and return None.
699
pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
700
                          sp: Span,
701
                          tts: &[ast::TokenTree]) -> Option<Vec<P<ast::Expr>>> {
702
    let mut p = cx.new_parser_from_tts(tts);
703
    let mut es = Vec::new();
704
    while p.token != token::Eof {
705
        es.push(cx.expander().fold_expr(p.parse_expr()));
706
        if p.eat(&token::Comma) {
707 708
            continue;
        }
709
        if p.token != token::Eof {
710 711
            cx.span_err(sp, "expected token: `,`");
            return None;
712
        }
713
    }
714
    Some(es)
715 716
}

717 718 719
/// In order to have some notion of scoping for macros,
/// we want to implement the notion of a transformation
/// environment.
720
///
721
/// This environment maps Names to SyntaxExtensions.
722 723 724
pub struct SyntaxEnv {
    chain: Vec<MapChainFrame> ,
}
J
John Clements 已提交
725

726
// impl question: how to implement it? Initially, the
J
John Clements 已提交
727 728 729 730 731 732 733 734 735
// env will contain only macros, so it might be painful
// to add an empty frame for every context. Let's just
// get it working, first....

// NB! the mutability of the underlying maps means that
// if expansion is out-of-order, a deeper scope may be
// able to refer to a macro that was added to an enclosing
// scope lexically later than the deeper scope.

736
struct MapChainFrame {
S
Steven Fackler 已提交
737
    info: BlockInfo,
738
    map: HashMap<Name, Rc<SyntaxExtension>>,
S
Steven Fackler 已提交
739
}
J
John Clements 已提交
740

741
impl SyntaxEnv {
742
    fn new() -> SyntaxEnv {
743
        let mut map = SyntaxEnv { chain: Vec::new() };
S
Steven Fackler 已提交
744 745
        map.push_frame();
        map
J
John Clements 已提交
746 747
    }

S
Steven Fackler 已提交
748 749 750 751 752
    pub fn push_frame(&mut self) {
        self.chain.push(MapChainFrame {
            info: BlockInfo::new(),
            map: HashMap::new(),
        });
J
John Clements 已提交
753 754
    }

S
Steven Fackler 已提交
755 756 757
    pub fn pop_frame(&mut self) {
        assert!(self.chain.len() > 1, "too many pops on MapChain!");
        self.chain.pop();
758 759
    }

760
    fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame {
A
Aaron Turon 已提交
761
        for (i, frame) in self.chain.iter_mut().enumerate().rev() {
S
Steven Fackler 已提交
762 763 764
            if !frame.info.macros_escape || i == 0 {
                return frame
            }
J
John Clements 已提交
765
        }
S
Steven Fackler 已提交
766
        unreachable!()
J
John Clements 已提交
767 768
    }

769
    pub fn find(&self, k: &Name) -> Option<Rc<SyntaxExtension>> {
S
Sean Chalmers 已提交
770
        for frame in self.chain.iter().rev() {
771
            match frame.map.get(k) {
772
                Some(v) => return Some(v.clone()),
S
Steven Fackler 已提交
773
                None => {}
J
John Clements 已提交
774 775
            }
        }
S
Steven Fackler 已提交
776
        None
J
John Clements 已提交
777 778
    }

779
    pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
780
        self.find_escape_frame().map.insert(k, Rc::new(v));
J
John Clements 已提交
781 782
    }

783
    pub fn info<'a>(&'a mut self) -> &'a mut BlockInfo {
784
        let last_chain_index = self.chain.len() - 1;
785
        &mut self.chain[last_chain_index].info
J
John Clements 已提交
786 787
    }
}