base.rs 19.5 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, ExpnInfo};
15
use ext;
16
use ext::expand;
17
use parse;
A
Alex Crichton 已提交
18
use parse::token;
P
Patrick Walton 已提交
19
use parse::token::{InternedString, intern, str_to_ident};
S
Steven Fackler 已提交
20
use util::small_vector::SmallVector;
21

22
use collections::HashMap;
23
use std::vec_ng::Vec;
24

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

33
pub struct MacroDef {
P
Patrick Walton 已提交
34
    name: ~str,
35
    ext: SyntaxExtension
36
}
37

38
pub type ItemDecorator =
S
Steven Fackler 已提交
39
    fn(&mut ExtCtxt, Span, @ast::MetaItem, @ast::Item, |@ast::Item|);
40

41 42 43
pub type ItemModifier =
    fn(&mut ExtCtxt, Span, @ast::MetaItem, @ast::Item) -> @ast::Item;

S
Steven Fackler 已提交
44 45
pub struct BasicMacroExpander {
    expander: MacroExpanderFn,
46 47 48
    span: Option<Span>
}

S
Steven Fackler 已提交
49
pub trait MacroExpander {
50
    fn expand(&self,
S
Steven Fackler 已提交
51
              ecx: &mut ExtCtxt,
52
              span: Span,
S
Steven Fackler 已提交
53
              token_tree: &[ast::TokenTree])
54 55 56
              -> MacResult;
}

S
Steven Fackler 已提交
57
pub type MacroExpanderFn =
58
    fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
59
       -> MacResult;
60

S
Steven Fackler 已提交
61
impl MacroExpander for BasicMacroExpander {
62
    fn expand(&self,
S
Steven Fackler 已提交
63
              ecx: &mut ExtCtxt,
64
              span: Span,
S
Steven Fackler 已提交
65
              token_tree: &[ast::TokenTree])
66
              -> MacResult {
S
Steven Fackler 已提交
67
        (self.expander)(ecx, span, token_tree)
68 69
    }
}
J
John Clements 已提交
70

S
Steven Fackler 已提交
71 72
pub struct BasicIdentMacroExpander {
    expander: IdentMacroExpanderFn,
73 74 75
    span: Option<Span>
}

S
Steven Fackler 已提交
76
pub trait IdentMacroExpander {
77
    fn expand(&self,
S
Steven Fackler 已提交
78
              cx: &mut ExtCtxt,
79 80
              sp: Span,
              ident: ast::Ident,
81
              token_tree: Vec<ast::TokenTree> )
82 83 84
              -> MacResult;
}

S
Steven Fackler 已提交
85
impl IdentMacroExpander for BasicIdentMacroExpander {
86
    fn expand(&self,
S
Steven Fackler 已提交
87
              cx: &mut ExtCtxt,
88 89
              sp: Span,
              ident: ast::Ident,
90
              token_tree: Vec<ast::TokenTree> )
91
              -> MacResult {
S
Steven Fackler 已提交
92
        (self.expander)(cx, sp, ident, token_tree)
93 94 95
    }
}

S
Steven Fackler 已提交
96
pub type IdentMacroExpanderFn =
97
    fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree> ) -> MacResult;
98

99
pub type MacroCrateRegistrationFun =
S
Steven Fackler 已提交
100
    fn(|ast::Name, SyntaxExtension|);
101

102 103
pub trait AnyMacro {
    fn make_expr(&self) -> @ast::Expr;
104
    fn make_items(&self) -> SmallVector<@ast::Item>;
105 106
    fn make_stmt(&self) -> @ast::Stmt;
}
J
John Clements 已提交
107

108

109
pub enum MacResult {
110
    MRExpr(@ast::Expr),
111
    MRItem(@ast::Item),
E
Eduard Burtescu 已提交
112
    MRAny(~AnyMacro:),
113
    MRDef(MacroDef),
114
}
115 116 117 118 119
impl MacResult {
    /// Create an empty expression MacResult; useful for satisfying
    /// type signatures after emitting a non-fatal error (which stop
    /// compilation well before the validity (or otherwise)) of the
    /// expression are checked.
120 121 122
    pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr {
        @ast::Expr {
            id: ast::DUMMY_NODE_ID,
123
            node: ast::ExprTup(Vec::new()),
124 125 126 127 128
            span: sp
        }
    }
    pub fn dummy_expr(sp: codemap::Span) -> MacResult {
        MRExpr(MacResult::raw_dummy_expr(sp))
129 130
    }
}
131

132
/// An enum representing the different kinds of syntax extensions.
133
pub enum SyntaxExtension {
134 135 136 137
    /// A syntax extension that is attached to an item and creates new items
    /// based upon it.
    ///
    /// `#[deriving(...)]` is an `ItemDecorator`.
138
    ItemDecorator(ItemDecorator),
139

140 141 142
    /// A syntax extension that is attached to an item and modifies it
    /// in-place.
    ItemModifier(ItemModifier),
143

144 145 146 147
    /// A normal, function-like syntax extension.
    ///
    /// `bytes!` is a `NormalTT`.
    NormalTT(~MacroExpander:'static, Option<Span>),
J
John Clements 已提交
148

149 150 151 152
    /// A function-like syntax extension that has an extra ident before
    /// the block.
    ///
    /// `macro_rules!` is an `IdentTT`.
S
Steven Fackler 已提交
153
    IdentTT(~IdentMacroExpander:'static, Option<Span>),
154
}
155

156 157
pub struct BlockInfo {
    // should macros escape from this scope?
158
    macros_escape: bool,
159
    // what are the pending renames?
160
    pending_renames: RenameList,
S
Steven Fackler 已提交
161 162 163 164 165 166
}

impl BlockInfo {
    pub fn new() -> BlockInfo {
        BlockInfo {
            macros_escape: false,
167
            pending_renames: Vec::new(),
S
Steven Fackler 已提交
168 169
        }
    }
J
John Clements 已提交
170
}
171

172
// a list of ident->name renamings
173
pub type RenameList = Vec<(ast::Ident, Name)>;
174

J
John Clements 已提交
175
// The base map of methods for expanding syntax extension
176
// AST nodes into full ASTs
J
John Clements 已提交
177
pub fn syntax_expander_table() -> SyntaxEnv {
J
John Clements 已提交
178
    // utility function to simplify creating NormalTT syntax extensions
S
Steven Fackler 已提交
179 180 181 182 183 184
    fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
        NormalTT(~BasicMacroExpander {
                expander: f,
                span: None,
            },
            None)
185
    }
K
Kiet Tran 已提交
186

187
    let mut syntax_expanders = SyntaxEnv::new();
188
    syntax_expanders.insert(intern(&"macro_rules"),
S
Steven Fackler 已提交
189 190
                            IdentTT(~BasicIdentMacroExpander {
                                expander: ext::tt::macro_rules::add_new_extension,
191
                                span: None,
192
                            },
S
Steven Fackler 已提交
193
                            None));
A
Alex Crichton 已提交
194
    syntax_expanders.insert(intern(&"fmt"),
S
Steven Fackler 已提交
195
                            builtin_normal_expander(
196
                                ext::fmt::expand_syntax_ext));
A
Alex Crichton 已提交
197
    syntax_expanders.insert(intern(&"format_args"),
S
Steven Fackler 已提交
198
                            builtin_normal_expander(
199
                                ext::format::expand_args));
200
    syntax_expanders.insert(intern(&"env"),
S
Steven Fackler 已提交
201
                            builtin_normal_expander(
202
                                    ext::env::expand_env));
S
Steven Fackler 已提交
203
    syntax_expanders.insert(intern(&"option_env"),
S
Steven Fackler 已提交
204
                            builtin_normal_expander(
205
                                    ext::env::expand_option_env));
206
    syntax_expanders.insert(intern("bytes"),
S
Steven Fackler 已提交
207
                            builtin_normal_expander(
208
                                    ext::bytes::expand_syntax_ext));
209
    syntax_expanders.insert(intern("concat_idents"),
S
Steven Fackler 已提交
210
                            builtin_normal_expander(
211
                                    ext::concat_idents::expand_syntax_ext));
212
    syntax_expanders.insert(intern("concat"),
S
Steven Fackler 已提交
213
                            builtin_normal_expander(
214
                                    ext::concat::expand_syntax_ext));
215
    syntax_expanders.insert(intern(&"log_syntax"),
S
Steven Fackler 已提交
216
                            builtin_normal_expander(
217
                                    ext::log_syntax::expand_syntax_ext));
218
    syntax_expanders.insert(intern(&"deriving"),
S
Steven Fackler 已提交
219
                            ItemDecorator(ext::deriving::expand_meta_deriving));
220 221

    // Quasi-quoting expanders
222
    syntax_expanders.insert(intern(&"quote_tokens"),
S
Steven Fackler 已提交
223
                       builtin_normal_expander(
224
                            ext::quote::expand_quote_tokens));
225
    syntax_expanders.insert(intern(&"quote_expr"),
S
Steven Fackler 已提交
226
                       builtin_normal_expander(
227
                            ext::quote::expand_quote_expr));
228
    syntax_expanders.insert(intern(&"quote_ty"),
S
Steven Fackler 已提交
229
                       builtin_normal_expander(
230
                            ext::quote::expand_quote_ty));
231
    syntax_expanders.insert(intern(&"quote_item"),
S
Steven Fackler 已提交
232
                       builtin_normal_expander(
233
                            ext::quote::expand_quote_item));
234
    syntax_expanders.insert(intern(&"quote_pat"),
S
Steven Fackler 已提交
235
                       builtin_normal_expander(
236
                            ext::quote::expand_quote_pat));
237
    syntax_expanders.insert(intern(&"quote_stmt"),
S
Steven Fackler 已提交
238
                       builtin_normal_expander(
239
                            ext::quote::expand_quote_stmt));
240

241
    syntax_expanders.insert(intern(&"line"),
S
Steven Fackler 已提交
242
                            builtin_normal_expander(
243
                                    ext::source_util::expand_line));
244
    syntax_expanders.insert(intern(&"col"),
S
Steven Fackler 已提交
245
                            builtin_normal_expander(
246
                                    ext::source_util::expand_col));
247
    syntax_expanders.insert(intern(&"file"),
S
Steven Fackler 已提交
248
                            builtin_normal_expander(
249
                                    ext::source_util::expand_file));
250
    syntax_expanders.insert(intern(&"stringify"),
S
Steven Fackler 已提交
251
                            builtin_normal_expander(
252
                                    ext::source_util::expand_stringify));
253
    syntax_expanders.insert(intern(&"include"),
S
Steven Fackler 已提交
254
                            builtin_normal_expander(
255
                                    ext::source_util::expand_include));
256
    syntax_expanders.insert(intern(&"include_str"),
S
Steven Fackler 已提交
257
                            builtin_normal_expander(
258
                                    ext::source_util::expand_include_str));
259
    syntax_expanders.insert(intern(&"include_bin"),
S
Steven Fackler 已提交
260
                            builtin_normal_expander(
261
                                    ext::source_util::expand_include_bin));
262
    syntax_expanders.insert(intern(&"module_path"),
S
Steven Fackler 已提交
263
                            builtin_normal_expander(
264
                                    ext::source_util::expand_mod));
265
    syntax_expanders.insert(intern(&"asm"),
S
Steven Fackler 已提交
266
                            builtin_normal_expander(
267
                                    ext::asm::expand_asm));
268
    syntax_expanders.insert(intern(&"cfg"),
S
Steven Fackler 已提交
269
                            builtin_normal_expander(
270 271
                                    ext::cfg::expand_cfg));
    syntax_expanders.insert(intern(&"trace_macros"),
S
Steven Fackler 已提交
272
                            builtin_normal_expander(
273
                                    ext::trace_macros::expand_trace_macros));
S
Steven Fackler 已提交
274
    syntax_expanders
275
}
276

277 278 279 280 281 282
pub struct MacroCrate {
    lib: Option<Path>,
    cnum: ast::CrateNum,
}

pub trait CrateLoader {
283
    fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate;
284
    fn get_exported_macros(&mut self, crate_num: ast::CrateNum) -> Vec<~str> ;
285 286 287
    fn get_registrar_symbol(&mut self, crate_num: ast::CrateNum) -> Option<~str>;
}

288 289 290
// 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.
291
pub struct ExtCtxt<'a> {
292
    parse_sess: @parse::ParseSess,
293
    cfg: ast::CrateConfig,
S
Steven Fackler 已提交
294
    backtrace: Option<@ExpnInfo>,
295
    ecfg: expand::ExpansionConfig<'a>,
296

297
    mod_path: Vec<ast::Ident> ,
S
Steven Fackler 已提交
298
    trace_mac: bool
299
}
N
Niko Matsakis 已提交
300

301 302
impl<'a> ExtCtxt<'a> {
    pub fn new<'a>(parse_sess: @parse::ParseSess, cfg: ast::CrateConfig,
303
                   ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> {
S
Steven Fackler 已提交
304
        ExtCtxt {
305 306
            parse_sess: parse_sess,
            cfg: cfg,
S
Steven Fackler 已提交
307
            backtrace: None,
308
            mod_path: Vec::new(),
309
            ecfg: ecfg,
S
Steven Fackler 已提交
310
            trace_mac: false
311 312 313
        }
    }

S
Steven Fackler 已提交
314
    pub fn expand_expr(&mut self, mut e: @ast::Expr) -> @ast::Expr {
315 316
        loop {
            match e.node {
A
Alex Crichton 已提交
317
                ast::ExprMac(..) => {
S
Steven Fackler 已提交
318
                    let mut expander = expand::MacroExpander {
S
Steven Fackler 已提交
319
                        extsbox: syntax_expander_table(),
320 321
                        cx: self,
                    };
S
Steven Fackler 已提交
322
                    e = expand::expand_expr(e, &mut expander);
323 324 325 326 327 328
                }
                _ => return e
            }
        }
    }

329
    pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
330
    pub fn parse_sess(&self) -> @parse::ParseSess { self.parse_sess }
331
    pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
332
    pub fn call_site(&self) -> Span {
S
Steven Fackler 已提交
333
        match self.backtrace {
334
            Some(expn_info) => expn_info.call_site,
335
            None => self.bug("missing top span")
336
        }
337
    }
338
    pub fn print_backtrace(&self) { }
S
Steven Fackler 已提交
339 340
    pub fn backtrace(&self) -> Option<@ExpnInfo> { self.backtrace }
    pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
341
    pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
342 343 344 345 346 347
    pub fn mod_path(&self) -> Vec<ast::Ident> {
        let mut v = Vec::new();
        v.push(token::str_to_ident(self.ecfg.crate_id.name));
        v.extend(&mut self.mod_path.iter().map(|a| *a));
        return v;
    }
S
Steven Fackler 已提交
348
    pub fn bt_push(&mut self, ei: codemap::ExpnInfo) {
349
        match ei {
350
            ExpnInfo {call_site: cs, callee: ref callee} => {
S
Steven Fackler 已提交
351
                self.backtrace =
352
                    Some(@ExpnInfo {
353
                        call_site: Span {lo: cs.lo, hi: cs.hi,
S
Steven Fackler 已提交
354
                                         expn_info: self.backtrace},
355 356
                        callee: (*callee).clone()
                    });
K
Kevin Atkinson 已提交
357
            }
358
        }
359
    }
S
Steven Fackler 已提交
360 361
    pub fn bt_pop(&mut self) {
        match self.backtrace {
362
            Some(expn_info) => self.backtrace = expn_info.call_site.expn_info,
363
            _ => self.bug("tried to pop without a push")
364 365
        }
    }
366 367 368 369 370 371 372 373 374 375 376
    /// Emit `msg` attached to `sp`, and stop compilation immediately.
    ///
    /// `span_err` should be strongly prefered where-ever possible:
    /// 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)
377
    pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
378 379 380
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_fatal(sp, msg);
    }
381 382 383 384 385 386

    /// 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).
387
    pub fn span_err(&self, sp: Span, msg: &str) {
388 389 390
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_err(sp, msg);
    }
391
    pub fn span_warn(&self, sp: Span, msg: &str) {
392 393 394
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_warn(sp, msg);
    }
395
    pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
396 397 398
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
    }
399
    pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
400 401 402
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_bug(sp, msg);
    }
S
Steven Fackler 已提交
403 404 405 406
    pub fn span_note(&self, sp: Span, msg: &str) {
        self.print_backtrace();
        self.parse_sess.span_diagnostic.span_note(sp, msg);
    }
407
    pub fn bug(&self, msg: &str) -> ! {
408 409 410
        self.print_backtrace();
        self.parse_sess.span_diagnostic.handler().bug(msg);
    }
411
    pub fn trace_macros(&self) -> bool {
S
Steven Fackler 已提交
412
        self.trace_mac
413
    }
S
Steven Fackler 已提交
414 415
    pub fn set_trace_macros(&mut self, x: bool) {
        self.trace_mac = x
416
    }
417
    pub fn ident_of(&self, st: &str) -> ast::Ident {
418
        str_to_ident(st)
419 420 421
    }
}

422 423 424 425
/// 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.
pub fn expr_to_str(cx: &mut ExtCtxt, expr: @ast::Expr, err_msg: &str)
426
                   -> Option<(InternedString, ast::StrStyle)> {
427 428
    // we want to be able to handle e.g. concat("foo", "bar")
    let expr = cx.expand_expr(expr);
429
    match expr.node {
430
        ast::ExprLit(l) => match l.node {
P
Patrick Walton 已提交
431
            ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
432
            _ => cx.span_err(l.span, err_msg)
433
        },
434
        _ => cx.span_err(expr.span, err_msg)
435
    }
436
    None
437 438
}

439 440 441 442 443
/// 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).
444 445 446
pub fn check_zero_tts(cx: &ExtCtxt,
                      sp: Span,
                      tts: &[ast::TokenTree],
447
                      name: &str) {
448
    if tts.len() != 0 {
449
        cx.span_err(sp, format!("{} takes no arguments", name));
450
    }
451 452
}

453 454
/// Extract the string literal from the first token of `tts`. If this
/// is not a string literal, emit an error and return None.
S
Steven Fackler 已提交
455
pub fn get_single_str_from_tts(cx: &ExtCtxt,
456
                               sp: Span,
457
                               tts: &[ast::TokenTree],
458
                               name: &str)
459
                               -> Option<~str> {
460
    if tts.len() != 1 {
461 462 463 464
        cx.span_err(sp, format!("{} takes 1 argument.", name));
    } else {
        match tts[0] {
            ast::TTTok(_, token::LIT_STR(ident))
465
            | ast::TTTok(_, token::LIT_STR_RAW(ident, _)) => {
466
                return Some(token::get_ident(ident).get().to_str())
467
            }
468 469
            _ => cx.span_err(sp, format!("{} requires a string.", name)),
        }
470
    }
471
    None
472
}
473

474 475
/// Extract comma-separated expressions from `tts`. If there is a
/// parsing error, emit a non-fatal error and return None.
476
pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
477
                          sp: Span,
478
                          tts: &[ast::TokenTree]) -> Option<Vec<@ast::Expr> > {
479 480
    let mut p = parse::new_parser_from_tts(cx.parse_sess(),
                                           cx.cfg(),
481 482 483
                                           tts.iter()
                                              .map(|x| (*x).clone())
                                              .collect());
484
    let mut es = Vec::new();
485
    while p.token != token::EOF {
486
        if es.len() != 0 && !p.eat(&token::COMMA) {
487 488
            cx.span_err(sp, "expected token: `,`");
            return None;
489
        }
490
        es.push(cx.expand_expr(p.parse_expr()));
491
    }
492
    Some(es)
493 494
}

J
John Clements 已提交
495 496 497 498
// in order to have some notion of scoping for macros,
// we want to implement the notion of a transformation
// environment.

S
Steven Fackler 已提交
499
// This environment maps Names to SyntaxExtensions.
J
John Clements 已提交
500 501 502 503 504 505 506 507 508 509 510

//impl question: how to implement it? Initially, the
// 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.

511
struct MapChainFrame {
S
Steven Fackler 已提交
512
    info: BlockInfo,
513 514 515
    map: HashMap<Name, SyntaxExtension>,
}

S
Steven Fackler 已提交
516
// Only generic to make it easy to test
517
pub struct SyntaxEnv {
518
    priv chain: Vec<MapChainFrame> ,
S
Steven Fackler 已提交
519
}
J
John Clements 已提交
520

521 522
impl SyntaxEnv {
    pub fn new() -> SyntaxEnv {
523
        let mut map = SyntaxEnv { chain: Vec::new() };
S
Steven Fackler 已提交
524 525
        map.push_frame();
        map
J
John Clements 已提交
526 527
    }

S
Steven Fackler 已提交
528 529 530 531 532
    pub fn push_frame(&mut self) {
        self.chain.push(MapChainFrame {
            info: BlockInfo::new(),
            map: HashMap::new(),
        });
J
John Clements 已提交
533 534
    }

S
Steven Fackler 已提交
535 536 537
    pub fn pop_frame(&mut self) {
        assert!(self.chain.len() > 1, "too many pops on MapChain!");
        self.chain.pop();
538 539
    }

540
    fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame {
S
Sean Chalmers 已提交
541
        for (i, frame) in self.chain.mut_iter().enumerate().rev() {
S
Steven Fackler 已提交
542 543 544
            if !frame.info.macros_escape || i == 0 {
                return frame
            }
J
John Clements 已提交
545
        }
S
Steven Fackler 已提交
546
        unreachable!()
J
John Clements 已提交
547 548
    }

549
    pub fn find<'a>(&'a self, k: &Name) -> Option<&'a SyntaxExtension> {
S
Sean Chalmers 已提交
550
        for frame in self.chain.iter().rev() {
S
Steven Fackler 已提交
551 552 553
            match frame.map.find(k) {
                Some(v) => return Some(v),
                None => {}
J
John Clements 已提交
554 555
            }
        }
S
Steven Fackler 已提交
556
        None
J
John Clements 已提交
557 558
    }

559
    pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
S
Steven Fackler 已提交
560
        self.find_escape_frame().map.insert(k, v);
J
John Clements 已提交
561 562
    }

563
    pub fn info<'a>(&'a mut self) -> &'a mut BlockInfo {
564 565
        let last_chain_index = self.chain.len() - 1;
        &mut self.chain.get_mut(last_chain_index).info
J
John Clements 已提交
566 567
    }
}