diff options
| author | John Clements <clements@racket-lang.org> | 2013-05-08 15:27:29 -0700 |
|---|---|---|
| committer | John Clements <clements@racket-lang.org> | 2013-06-05 12:01:36 -0700 |
| commit | d7638f9dba5cef5c4db7b9008196ede4450d8521 (patch) | |
| tree | ca96d50b78c7defd451ef9807a7f7554acc3436f /src/libsyntax/ext | |
| parent | 77c2c0900f975e1fa9179c3e7492d62656734295 (diff) | |
| download | rust-d7638f9dba5cef5c4db7b9008196ede4450d8521.tar.gz rust-d7638f9dba5cef5c4db7b9008196ede4450d8521.zip | |
change to newer macro escape mechanism, using uints in more places
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 125 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 128 |
2 files changed, 138 insertions, 115 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5fae6ff3c18..48cfe61309c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -11,6 +11,7 @@ use core::prelude::*; use ast; +use ast::Name; use codemap; use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom}; use codemap::CallInfo; @@ -18,6 +19,7 @@ use diagnostic::span_handler; use ext; use parse; use parse::token; +use parse::token::{intern}; use core::hashmap::HashMap; use core::vec; @@ -91,29 +93,33 @@ pub enum SyntaxExtension { IdentTT(SyntaxExpanderTTItem), } +// The SyntaxEnv is the environment that's threaded through the expansion +// of macros. It contains bindings for macros, and also a special binding +// for " block" (not a legal identifier) that maps to a BlockInfo pub type SyntaxEnv = @mut MapChain<Name, Transformer>; -// Name : the domain of SyntaxEnvs -// want to change these to uints.... -// note that we use certain strings that are not legal as identifiers -// to indicate, for instance, how blocks are supposed to behave. -type Name = @~str; - // Transformer : the codomain of SyntaxEnvs -// NB: it may seem crazy to lump both of these into one environment; -// what would it mean to bind "foo" to BlockLimit(true)? The idea -// is that this follows the lead of MTWT, and accommodates growth -// toward a more uniform syntax syntax (sorry) where blocks are just -// another kind of transformer. - pub enum Transformer { // this identifier maps to a syntax extension or macro SE(SyntaxExtension), - // should blocks occurring here limit macro scopes? - ScopeMacros(bool) + // blockinfo : this is ... well, it's simpler than threading + // another whole data stack-structured data structure through + // expansion. Basically, there's an invariant that every + // map must contain a binding for " block". + BlockInfo(BlockInfo) +} + +pub struct BlockInfo { + // should macros escape from this scope? + macros_escape : bool, + // what are the pending renames? + pending_renames : @mut RenameList } +// a list of ident->name renamings +type RenameList = ~[(ast::ident,Name)]; + // The base map of methods for expanding syntax extension // AST nodes into full ASTs pub fn syntax_expander_table() -> SyntaxEnv { @@ -127,77 +133,80 @@ pub fn syntax_expander_table() -> SyntaxEnv { } let mut syntax_expanders = HashMap::new(); // NB identifier starts with space, and can't conflict with legal idents - syntax_expanders.insert(@~" block", - @ScopeMacros(true)); - syntax_expanders.insert(@~"macro_rules", + syntax_expanders.insert(intern(&" block"), + @BlockInfo(BlockInfo{ + macros_escape : false, + pending_renames : @mut ~[] + })); + syntax_expanders.insert(intern(&"macro_rules"), builtin_item_tt( ext::tt::macro_rules::add_new_extension)); - syntax_expanders.insert(@~"fmt", + syntax_expanders.insert(intern(&"fmt"), builtin_normal_tt(ext::fmt::expand_syntax_ext)); syntax_expanders.insert( - @~"auto_encode", + intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); syntax_expanders.insert( - @~"auto_decode", + intern(&"auto_decode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_decode))); - syntax_expanders.insert(@~"env", + syntax_expanders.insert(intern(&"env"), builtin_normal_tt(ext::env::expand_syntax_ext)); - syntax_expanders.insert(@~"bytes", + syntax_expanders.insert(intern("bytes"), builtin_normal_tt(ext::bytes::expand_syntax_ext)); - syntax_expanders.insert(@~"concat_idents", + syntax_expanders.insert(intern("concat_idents"), builtin_normal_tt( ext::concat_idents::expand_syntax_ext)); - syntax_expanders.insert(@~"log_syntax", + syntax_expanders.insert(intern(&"log_syntax"), builtin_normal_tt( ext::log_syntax::expand_syntax_ext)); - syntax_expanders.insert(@~"deriving", + syntax_expanders.insert(intern(&"deriving"), @SE(ItemDecorator( ext::deriving::expand_meta_deriving))); // Quasi-quoting expanders - syntax_expanders.insert(@~"quote_tokens", + syntax_expanders.insert(intern(&"quote_tokens"), builtin_normal_tt(ext::quote::expand_quote_tokens)); - syntax_expanders.insert(@~"quote_expr", + syntax_expanders.insert(intern(&"quote_expr"), builtin_normal_tt(ext::quote::expand_quote_expr)); - syntax_expanders.insert(@~"quote_ty", + syntax_expanders.insert(intern(&"quote_ty"), builtin_normal_tt(ext::quote::expand_quote_ty)); - syntax_expanders.insert(@~"quote_item", + syntax_expanders.insert(intern(&"quote_item"), builtin_normal_tt(ext::quote::expand_quote_item)); - syntax_expanders.insert(@~"quote_pat", + syntax_expanders.insert(intern(&"quote_pat"), builtin_normal_tt(ext::quote::expand_quote_pat)); - syntax_expanders.insert(@~"quote_stmt", + syntax_expanders.insert(intern(&"quote_stmt"), builtin_normal_tt(ext::quote::expand_quote_stmt)); - syntax_expanders.insert(@~"line", + syntax_expanders.insert(intern(&"line"), builtin_normal_tt( ext::source_util::expand_line)); - syntax_expanders.insert(@~"col", + syntax_expanders.insert(intern(&"col"), builtin_normal_tt( ext::source_util::expand_col)); - syntax_expanders.insert(@~"file", + syntax_expanders.insert(intern(&"file"), builtin_normal_tt( ext::source_util::expand_file)); - syntax_expanders.insert(@~"stringify", + syntax_expanders.insert(intern(&"stringify"), builtin_normal_tt( ext::source_util::expand_stringify)); - syntax_expanders.insert(@~"include", + syntax_expanders.insert(intern(&"include"), builtin_normal_tt( ext::source_util::expand_include)); - syntax_expanders.insert(@~"include_str", + syntax_expanders.insert(intern(&"include_str"), builtin_normal_tt( ext::source_util::expand_include_str)); - syntax_expanders.insert(@~"include_bin", + syntax_expanders.insert(intern(&"include_bin"), builtin_normal_tt( ext::source_util::expand_include_bin)); - syntax_expanders.insert(@~"module_path", + syntax_expanders.insert(intern(&"module_path"), builtin_normal_tt( ext::source_util::expand_mod)); - syntax_expanders.insert(@~"proto", + syntax_expanders.insert(intern(&"proto"), builtin_item_tt(ext::pipes::expand_proto)); - syntax_expanders.insert(@~"asm", + syntax_expanders.insert(intern(&"asm"), builtin_normal_tt(ext::asm::expand_asm)); syntax_expanders.insert( - @~"trace_macros", + intern(&"trace_macros"), builtin_normal_tt(ext::trace_macros::expand_trace_macros)); MapChain::new(~syntax_expanders) } @@ -478,7 +487,39 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{ ConsMapChain (~ref mut map,_) => map.insert(key,ext) } } + // insert the binding into the topmost frame for which the binding + // associated with 'n' exists and satisfies pred + // ... there are definitely some opportunities for abstraction + // here that I'm ignoring. (e.g., manufacturing a predicate on + // the maps in the chain, and using an abstract "find". + fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) { + match *self { + BaseMapChain (~ref mut map) => { + if satisfies_pred(map,&n,pred) { + map.insert(key,ext); + } else { + fail!(~"expected map chain containing satisfying frame") + } + }, + ConsMapChain (~ref mut map, rest) => { + if satisfies_pred(map,&n,pred) { + map.insert(key,ext); + } else { + rest.insert_into_frame(key,ext,n,pred) + } + } + } + } +} +fn satisfies_pred<K : Eq + Hash + IterBytes,V>(map : &mut HashMap<K,V>, + n: &K, + pred: &fn(&V)->bool) + -> bool { + match map.find(n) { + Some(ref v) => (pred(*v)), + None => false + } } #[cfg(test)] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 6ea1160c267..c23e34e0f91 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -25,6 +25,7 @@ use ext::base::*; use fold::*; use parse; use parse::{parse_item_from_source_str}; +use parse::token::{get_ident_interner,intern}; use core::vec; @@ -48,15 +49,14 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, fmt!("expected macro name without module \ separators")); } - /* using idents and token::special_idents would make the - the macro names be hygienic */ - let extname = cx.parse_sess().interner.get(pth.idents[0]); + let extname = pth.idents[0]; + let extnamestr = get_ident_interner().get(extname); // leaving explicit deref here to highlight unbox op: - match (*extsbox).find(&extname) { + match (*extsbox).find(&extname.repr) { None => { cx.span_fatal( pth.span, - fmt!("macro undefined: '%s'", *extname)) + fmt!("macro undefined: '%s'", *extnamestr)) } Some(@SE(NormalTT(SyntaxExpanderTT{ expander: exp, @@ -65,7 +65,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, cx.bt_push(ExpandedFrom(CallInfo { call_site: s, callee: NameAndSpan { - name: copy *extname, + name: copy *extnamestr, span: exp_sp, }, })); @@ -78,7 +78,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, pth.span, fmt!( "non-expr macro in expr pos: %s", - *extname + *extnamestr ) ) } @@ -94,7 +94,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, _ => { cx.span_fatal( pth.span, - fmt!("'%s' is not a tt-style macro", *extname) + fmt!("'%s' is not a tt-style macro", *extnamestr) ) } } @@ -131,7 +131,7 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv, do vec::foldr(item.attrs, ~[*item]) |attr, items| { let mname = attr::get_attr_name(attr); - match (*extsbox).find(&mname) { + match (*extsbox).find(&intern(*mname)) { Some(@SE(ItemDecorator(dec_fn))) => { cx.bt_push(ExpandedFrom(CallInfo { call_site: attr.span, @@ -155,16 +155,20 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv, // eval $e with a new exts frame: macro_rules! with_exts_frame ( - ($extsboxexpr:expr,$e:expr) => + ($extsboxexpr:expr,$macros_escape:expr,$e:expr) => ({let extsbox = $extsboxexpr; let oldexts = *extsbox; *extsbox = oldexts.push_frame(); + extsbox.insert(intern(special_block_name), + @BlockInfo(BlockInfo{macros_escape:$macros_escape,pending_renames:@mut ~[]})); let result = $e; *extsbox = oldexts; result }) ) +static special_block_name : &'static str = " block"; + // When we enter a module, record it, for the sake of `module!` pub fn expand_item(extsbox: @mut SyntaxEnv, cx: @ExtCtxt, @@ -182,14 +186,8 @@ pub fn expand_item(extsbox: @mut SyntaxEnv, match it.node { ast::item_mod(_) | ast::item_foreign_mod(_) => { cx.mod_push(it.ident); - let result = - // don't push a macro scope for macro_escape: - if contains_macro_escape(it.attrs) { - orig(it,fld) - } else { - // otherwise, push a scope: - with_exts_frame!(extsbox,orig(it,fld)) - }; + let macro_escape = contains_macro_escape(it.attrs); + let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld)); cx.mod_pop(); result } @@ -205,31 +203,6 @@ pub fn contains_macro_escape (attrs: &[ast::attribute]) -> bool { attrs.any(|attr| "macro_escape" == *attr::get_attr_name(attr)) } -// this macro disables (one layer of) macro -// scoping, to allow a block to add macro bindings -// to its parent env -macro_rules! without_macro_scoping( - ($extsexpr:expr,$exp:expr) => - ({ - // only evaluate this once: - let exts = $extsexpr; - // capture the existing binding: - let existingBlockBinding = - match exts.find(&@~" block"){ - Some(binding) => binding, - None => cx.bug("expected to find \" block\" binding") - }; - // this prevents the block from limiting the macros' scope: - exts.insert(@~" block",@ScopeMacros(false)); - let result = $exp; - // reset the block binding. Note that since the original - // one may have been inherited, this procedure may wind - // up introducing a block binding where one didn't exist - // before. - exts.insert(@~" block",existingBlockBinding); - result - })) - // Support for item-position macro invocations, exactly the same // logic as for expression-position macro invocations. pub fn expand_item_mac(extsbox: @mut SyntaxEnv, @@ -243,22 +216,24 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, _ => cx.span_bug(it.span, "invalid item macro invocation") }; - let extname = cx.parse_sess().interner.get(pth.idents[0]); - let expanded = match (*extsbox).find(&extname) { + let extname = pth.idents[0]; + let interner = get_ident_interner(); + let extnamestr = interner.get(extname); + let expanded = match (*extsbox).find(&extname.repr) { None => cx.span_fatal(pth.span, - fmt!("macro undefined: '%s!'", *extname)), + fmt!("macro undefined: '%s!'", *extnamestr)), Some(@SE(NormalTT(ref expand))) => { if it.ident != parse::token::special_idents::invalid { cx.span_fatal(pth.span, fmt!("macro %s! expects no ident argument, \ - given '%s'", *extname, - *cx.parse_sess().interner.get(it.ident))); + given '%s'", *extnamestr, + *interner.get(it.ident))); } cx.bt_push(ExpandedFrom(CallInfo { call_site: it.span, callee: NameAndSpan { - name: copy *extname, + name: copy *extnamestr, span: expand.span } })); @@ -268,29 +243,29 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, if it.ident == parse::token::special_idents::invalid { cx.span_fatal(pth.span, fmt!("macro %s! expects an ident argument", - *extname)); + *extnamestr)); } cx.bt_push(ExpandedFrom(CallInfo { call_site: it.span, callee: NameAndSpan { - name: copy *extname, + name: copy *extnamestr, span: expand.span } })); ((*expand).expander)(cx, it.span, it.ident, tts) } _ => cx.span_fatal( - it.span, fmt!("%s! is not legal in item position", *extname)) + it.span, fmt!("%s! is not legal in item position", *extnamestr)) }; let maybe_it = match expanded { MRItem(it) => fld.fold_item(it), MRExpr(_) => cx.span_fatal(pth.span, ~"expr macro in item position: " - + *extname), + + *extnamestr), MRAny(_, item_maker, _) => item_maker().chain(|i| {fld.fold_item(i)}), MRDef(ref mdef) => { - extsbox.insert(@/*bad*/ copy mdef.name, @SE((*mdef).ext)); + insert_macro(*extsbox,intern(mdef.name), @SE((*mdef).ext)); None } }; @@ -298,6 +273,23 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, return maybe_it; } + +// insert a macro into the innermost frame that doesn't have the +// macro_escape tag. +fn insert_macro(exts: SyntaxEnv, name: ast::Name, transformer: @Transformer) { + let block_err_msg = "special identifier ' block' was bound to a non-BlockInfo"; + let is_non_escaping_block = + |t : &@Transformer| -> bool{ + match t { + &@BlockInfo(BlockInfo {macros_escape:false,_}) => true, + &@BlockInfo(BlockInfo {_}) => false, + _ => fail!(block_err_msg) + } + }; + exts.insert_into_frame(name,transformer,intern(special_block_name), + is_non_escaping_block) +} + // expand a stmt pub fn expand_stmt(extsbox: @mut SyntaxEnv, cx: @ExtCtxt, @@ -323,16 +315,17 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, fmt!("expected macro name without module \ separators")); } - let extname = cx.parse_sess().interner.get(pth.idents[0]); - let (fully_expanded, sp) = match (*extsbox).find(&extname) { + let extname = pth.idents[0]; + let extnamestr = get_ident_interner().get(extname); + let (fully_expanded, sp) = match (*extsbox).find(&extname.repr) { None => - cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", *extname)), + cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", *extnamestr)), Some(@SE(NormalTT( SyntaxExpanderTT{expander: exp, span: exp_sp}))) => { cx.bt_push(ExpandedFrom(CallInfo { call_site: sp, - callee: NameAndSpan { name: copy *extname, span: exp_sp } + callee: NameAndSpan { name: copy *extnamestr, span: exp_sp } })); let expanded = match exp(cx, mac.span, tts) { MRExpr(e) => @@ -341,7 +334,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, MRAny(_,_,stmt_mkr) => stmt_mkr(), _ => cx.span_fatal( pth.span, - fmt!("non-stmt macro in stmt pos: %s", *extname)) + fmt!("non-stmt macro in stmt pos: %s", *extnamestr)) }; //keep going, outside-in @@ -362,7 +355,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, _ => { cx.span_fatal(pth.span, - fmt!("'%s' is not a tt-style macro", *extname)) + fmt!("'%s' is not a tt-style macro", *extnamestr)) } }; @@ -382,19 +375,8 @@ pub fn expand_block(extsbox: @mut SyntaxEnv, fld: @ast_fold, orig: @fn(&blk_, span, @ast_fold) -> (blk_, span)) -> (blk_, span) { - match (*extsbox).find(&@~" block") { - // no scope limit on macros in this block, no need - // to push an exts frame: - Some(@ScopeMacros(false)) => { - orig (blk,sp,fld) - }, - // this block should limit the scope of its macros: - Some(@ScopeMacros(true)) => { - // see note below about treatment of exts table - with_exts_frame!(extsbox,orig(blk,sp,fld)) - }, - _ => cx.span_bug(sp, "expected ScopeMacros binding for \" block\"") - } + // see note below about treatment of exts table + with_exts_frame!(extsbox,false,orig(blk,sp,fld)) } // given a mutable list of renames, return a tree-folder that applies those |
