diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ac3fc717500a..24f70bfeaa8b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -33,6 +33,10 @@ pub struct MacroDef { ext: SyntaxExtension } +// No context arg for an Item Decorator macro, simply because +// adding it would require adding a ctxt field to all items. +// we could do this if it turns out to be useful. + pub type ItemDecoratorFun = @fn(@ExtCtxt, Span, @ast::MetaItem, @@ -41,15 +45,34 @@ pub type ItemDecoratorFun = @fn(@ExtCtxt, pub type SyntaxExpanderTTFun = @fn(@ExtCtxt, Span, - &[ast::token_tree]) + &[ast::token_tree], + ast::SyntaxContext) -> MacResult; pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt, + Span, + ast::Ident, + ~[ast::token_tree], + ast::SyntaxContext) + -> MacResult; + +// oog... in order to make the presentation of builtin_normal_tt_no_ctxt +// and builtin_ident_tt_no_ctxt palatable, we need one-off types for +// functions that don't consume a ctxt: + +pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt, + Span, + &[ast::token_tree]) + -> MacResult; + +pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt, Span, ast::Ident, ~[ast::token_tree]) -> MacResult; + + pub enum MacResult { MRExpr(@ast::Expr), MRItem(@ast::item), @@ -78,6 +101,7 @@ pub enum SyntaxExtension { IdentTT(SyntaxExpanderTTItemFun, Option), } + // 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 @@ -109,12 +133,16 @@ type RenameList = ~[(ast::Ident,Name)]; // AST nodes into full ASTs pub fn syntax_expander_table() -> SyntaxEnv { // utility function to simplify creating NormalTT syntax extensions - fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer { - @SE(NormalTT(f, None)) + // that ignore their contexts + fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer { + let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,d|{f(a,b,c)}; + @SE(NormalTT(wrapped_expander, None)) } // utility function to simplify creating IdentTT syntax extensions - fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer { - @SE(IdentTT(f, None)) + // that ignore their contexts + fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer { + let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,e|{f(a,b,c,d)}; + @SE(IdentTT(wrapped_expander, None)) } let mut syntax_expanders = HashMap::new(); // NB identifier starts with space, and can't conflict with legal idents @@ -124,16 +152,16 @@ pub fn syntax_expander_table() -> SyntaxEnv { pending_renames : @mut ~[] })); syntax_expanders.insert(intern(&"macro_rules"), - builtin_item_tt( + builtin_item_tt_no_ctxt( ext::tt::macro_rules::add_new_extension)); syntax_expanders.insert(intern(&"fmt"), - builtin_normal_tt(ext::fmt::expand_syntax_ext)); + builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext)); syntax_expanders.insert(intern(&"format"), - builtin_normal_tt(ext::ifmt::expand_format)); + builtin_normal_tt_no_ctxt(ext::ifmt::expand_format)); syntax_expanders.insert(intern(&"write"), - builtin_normal_tt(ext::ifmt::expand_write)); + builtin_normal_tt_no_ctxt(ext::ifmt::expand_write)); syntax_expanders.insert(intern(&"writeln"), - builtin_normal_tt(ext::ifmt::expand_writeln)); + builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); @@ -141,16 +169,16 @@ pub fn syntax_expander_table() -> SyntaxEnv { intern(&"auto_decode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_decode))); syntax_expanders.insert(intern(&"env"), - builtin_normal_tt(ext::env::expand_env)); + builtin_normal_tt_no_ctxt(ext::env::expand_env)); syntax_expanders.insert(intern(&"option_env"), - builtin_normal_tt(ext::env::expand_option_env)); + builtin_normal_tt_no_ctxt(ext::env::expand_option_env)); syntax_expanders.insert(intern("bytes"), - builtin_normal_tt(ext::bytes::expand_syntax_ext)); + builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext)); syntax_expanders.insert(intern("concat_idents"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::concat_idents::expand_syntax_ext)); syntax_expanders.insert(intern(&"log_syntax"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::log_syntax::expand_syntax_ext)); syntax_expanders.insert(intern(&"deriving"), @SE(ItemDecorator( @@ -158,49 +186,49 @@ pub fn syntax_expander_table() -> SyntaxEnv { // Quasi-quoting expanders syntax_expanders.insert(intern(&"quote_tokens"), - builtin_normal_tt(ext::quote::expand_quote_tokens)); + @SE(NormalTT(ext::quote::expand_quote_tokens, None))); syntax_expanders.insert(intern(&"quote_expr"), - builtin_normal_tt(ext::quote::expand_quote_expr)); + @SE(NormalTT(ext::quote::expand_quote_expr, None))); syntax_expanders.insert(intern(&"quote_ty"), - builtin_normal_tt(ext::quote::expand_quote_ty)); + @SE(NormalTT(ext::quote::expand_quote_ty, None))); syntax_expanders.insert(intern(&"quote_item"), - builtin_normal_tt(ext::quote::expand_quote_item)); + @SE(NormalTT(ext::quote::expand_quote_item, None))); syntax_expanders.insert(intern(&"quote_pat"), - builtin_normal_tt(ext::quote::expand_quote_pat)); + @SE(NormalTT(ext::quote::expand_quote_pat, None))); syntax_expanders.insert(intern(&"quote_stmt"), - builtin_normal_tt(ext::quote::expand_quote_stmt)); + @SE(NormalTT(ext::quote::expand_quote_stmt, None))); syntax_expanders.insert(intern(&"line"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_line)); syntax_expanders.insert(intern(&"col"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_col)); syntax_expanders.insert(intern(&"file"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_file)); syntax_expanders.insert(intern(&"stringify"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_stringify)); syntax_expanders.insert(intern(&"include"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_include)); syntax_expanders.insert(intern(&"include_str"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_include_str)); syntax_expanders.insert(intern(&"include_bin"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_include_bin)); syntax_expanders.insert(intern(&"module_path"), - builtin_normal_tt( + builtin_normal_tt_no_ctxt( ext::source_util::expand_mod)); syntax_expanders.insert(intern(&"asm"), - builtin_normal_tt(ext::asm::expand_asm)); + builtin_normal_tt_no_ctxt(ext::asm::expand_asm)); syntax_expanders.insert(intern(&"cfg"), - builtin_normal_tt(ext::cfg::expand_cfg)); + builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg)); syntax_expanders.insert( intern(&"trace_macros"), - builtin_normal_tt(ext::trace_macros::expand_trace_macros)); + builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros)); MapChain::new(~syntax_expanders) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a62b015c6cbb..91a56590435d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Block, Crate, NodeId, DeclLocal, EMPTY_CTXT, Expr_, ExprMac}; +use ast::{Block, Crate, NodeId, DeclLocal, EMPTY_CTXT, Expr_, ExprMac, SyntaxContext}; use ast::{Local, Ident, mac_invoc_tt}; use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi}; use ast::{ILLEGAL_CTXT, SCTable, token_tree}; @@ -42,6 +42,11 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, // entry-point for all syntax extensions. ExprMac(ref mac) => { match (*mac).node { + // 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: mac_invoc_tt(ref pth, ref tts, ctxt) => { if (pth.segments.len() > 1u) { @@ -70,7 +75,8 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, let fm = fresh_mark(); // mark before: let marked_before = mark_tts(*tts,fm); - let expanded = match expandfun(cx, mac.span, marked_before) { + let marked_ctxt = new_mark(fm, ctxt); + let expanded = match expandfun(cx, mac.span, marked_before, marked_ctxt) { MRExpr(e) => e, MRAny(expr_maker,_,_) => expr_maker(), _ => { @@ -367,9 +373,9 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, cx: @ExtCtxt, it: @ast::item, fld: @ast_fold) -> Option<@ast::item> { - let (pth, tts) = match it.node { + let (pth, tts, ctxt) = match it.node { item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => { - (pth, (*tts).clone()) + (pth, (*tts).clone(), ctxt) } _ => cx.span_bug(it.span, "invalid item macro invocation") }; @@ -396,10 +402,9 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, } }); // mark before expansion: - let marked_tts = mark_tts(tts,fm); - // mark after expansion: - // RIGHT HERE: can't apply mark_item to MacResult ... :( - expander(cx, it.span, marked_tts) + let marked_before = mark_tts(tts,fm); + let marked_ctxt = new_mark(fm,ctxt); + expander(cx, it.span, marked_before, marked_ctxt) } Some(@SE(IdentTT(expander, span))) => { if it.ident.name == parse::token::special_idents::invalid.name { @@ -417,7 +422,8 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, let fm = fresh_mark(); // mark before expansion: let marked_tts = mark_tts(tts,fm); - expander(cx, it.span, it.ident, marked_tts) + let marked_ctxt = new_mark(fm,ctxt); + expander(cx, it.span, it.ident, marked_tts, marked_ctxt) } _ => cx.span_fatal( it.span, fmt!("%s! is not legal in item position", extnamestr)) @@ -468,11 +474,11 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, -> (Option, Span) { // why the copying here and not in expand_expr? // looks like classic changed-in-only-one-place - let (mac, pth, tts, semi) = match *s { + let (mac, pth, tts, semi, ctxt) = match *s { StmtMac(ref mac, semi) => { match mac.node { mac_invoc_tt(ref pth, ref tts, ctxt) => { - ((*mac).clone(), pth, (*tts).clone(), semi) + ((*mac).clone(), pth, (*tts).clone(), semi, ctxt) } } } @@ -498,7 +504,8 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, let fm = fresh_mark(); // mark before expansion: let marked_tts = mark_tts(tts,fm); - let expanded = match expandfun(cx, mac.span, marked_tts) { + let marked_ctxt = new_mark(fm,ctxt); + let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) { MRExpr(e) => @codemap::Spanned { node: StmtExpr(e, cx.next_id()), span: e.span}, @@ -893,25 +900,6 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> { context as @mut Visitor<()> } -// given a mutable list of renames, return a tree-folder that applies those -// renames. -// FIXME #4536: currently pub to allow testing -pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold { - let afp = default_ast_fold(); - let f_pre = @AstFoldFns { - fold_ident: |id,_| { - // the individual elements are memoized... it would - // also be possible to memoize on the whole list at once. - let new_ctxt = renames.iter().fold(id.ctxt,|ctxt,&(from,to)| { - new_rename(from,to,ctxt) - }); - ast::Ident{name:id.name,ctxt:new_ctxt} - }, - .. *afp - }; - make_fold(f_pre) -} - // expand a block. pushes a new exts_frame, then calls expand_block_elts pub fn expand_block(extsbox: @mut SyntaxEnv, _cx: @ExtCtxt, @@ -1427,6 +1415,7 @@ pub trait CtxtFn{ fn f(&self, ast::SyntaxContext) -> ast::SyntaxContext; } +// a renamer adds a rename to the syntax context pub struct Renamer { from : ast::Ident, to : ast::Name @@ -1438,6 +1427,22 @@ impl CtxtFn for Renamer { } } +// a renamer that performs a whole bunch of renames +pub struct MultiRenamer { + renames : @mut ~[(ast::Ident,ast::Name)] +} + +impl CtxtFn for MultiRenamer { + fn f(&self, starting_ctxt : ast::SyntaxContext) -> ast::SyntaxContext { + // the individual elements are memoized... it would + // also be possible to memoize on the whole list at once. + self.renames.iter().fold(starting_ctxt,|ctxt,&(from,to)| { + new_rename(from,to,ctxt) + }) + } +} + +// a marker adds the given mark to the syntax context pub struct Marker { mark : Mrk } impl CtxtFn for Marker { @@ -1446,6 +1451,15 @@ impl CtxtFn for Marker { } } +// a repainter just replaces the given context with the one it's closed over +pub struct Repainter { ctxt : SyntaxContext } + +impl CtxtFn for Repainter { + fn f(&self, ctxt : ast::SyntaxContext) -> ast::SyntaxContext { + self.ctxt + } +} + // given a function from ctxts to ctxts, produce // an ast_fold that applies that function to all ctxts: pub fn fun_to_ctxt_folder(cf: @T) -> @AstFoldFns { @@ -1454,7 +1468,7 @@ pub fn fun_to_ctxt_folder(cf: @T) -> @AstFoldFns { |ast::Ident{name, ctxt}, _| { ast::Ident{name:name,ctxt:cf.f(ctxt)} }; - let fm : @fn(&ast::mac_, span, @ast_fold) -> (ast::mac_,span) = + let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) = |m, sp, fld| { match *m { mac_invoc_tt(ref path, ref tts, ctxt) => @@ -1472,6 +1486,15 @@ pub fn fun_to_ctxt_folder(cf: @T) -> @AstFoldFns { } } + + +// given a mutable list of renames, return a tree-folder that applies those +// renames. +// FIXME #4536: currently pub to allow testing +pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns { + fun_to_ctxt_folder(@MultiRenamer{renames : renames}) +} + // just a convenience: pub fn new_mark_folder(m : Mrk) -> @AstFoldFns { fun_to_ctxt_folder(@Marker{mark:m}) } pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns { @@ -1513,6 +1536,12 @@ fn mark_item(expr : @ast::item, m : Mrk) -> Option<@ast::item> { new_mark_folder(m).fold_item(expr) } +// replace all contexts in a given expr with the given mark. Used +// for capturing macros +pub fn replace_ctxts(expr : @ast::Expr, ctxt : SyntaxContext) -> @ast::Expr { + fun_to_ctxt_folder(@Repainter{ctxt:ctxt}).fold_expr(expr) +} + #[cfg(test)] mod test { use super::*; @@ -1522,7 +1551,7 @@ mod test { use codemap; use codemap::Spanned; use parse; - use parse::token::{gensym, intern, get_ident_interner}; + use parse::token::{gensym, intern, get_ident_interner, ident_to_str}; use print::pprust; use std; use std::vec; @@ -1656,8 +1685,9 @@ mod test { } } - fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) { - pprust::print_mod(s, &crate.module, crate.attrs); + fn fake_print_crate(crate: @ast::Crate) { + let s = pprust::rust_printer(std::io::stderr(),get_ident_interner()); + pprust::print_crate_(s, crate); } fn expand_crate_str(crate_str: @str) -> @ast::Crate { @@ -1784,6 +1814,57 @@ mod test { } } + #[test] fn quote_expr_test() { + quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_expr!(dontcare);}"); + } + #[test] fn quote_item_test() { + quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_item!(dontcare);}"); + } + #[test] fn quote_pat_test() { + quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_pat!(dontcare);}"); + } + #[test] fn quote_ty_test() { + quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_ty!(dontcare);}"); + } + #[test] fn quote_tokens_test() { + quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_tokens!(dontcare);}"); + } + + fn quote_ext_cx_test(crate_str : @str) { + let crate = expand_crate_str(crate_str); + // find the ext_cx binding + let bindings = @mut ~[]; + visit::walk_crate(&mut new_name_finder(bindings), crate, ()); + let cxbinds : ~[&ast::Ident] = bindings.iter().filter(|b|{@"ext_cx" == (ident_to_str(*b))}).collect(); + let cxbind = match cxbinds { + [b] => b, + _ => fail!("expected just one binding for ext_cx") + }; + let resolved_binding = mtwt_resolve(*cxbind); + // find all the ext_cx varrefs: + let varrefs = @mut ~[]; + visit::walk_crate(&mut new_path_finder(varrefs), crate, ()); + // the ext_cx binding should bind all of the ext_cx varrefs: + for (idx,v) in varrefs.iter().filter(|p|{ p.segments.len() == 1 + && (@"ext_cx" == (ident_to_str(&p.segments[0].identifier))) + }).enumerate() { + if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) { + std::io::println("uh oh, ext_cx binding didn't match ext_cx varref:"); + std::io::println(fmt!("this is varref # %?",idx)); + std::io::println(fmt!("binding: %?",cxbind)); + std::io::println(fmt!("resolves to: %?",resolved_binding)); + std::io::println(fmt!("varref: %?",v.segments[0])); + std::io::println(fmt!("resolves to: %?",mtwt_resolve(v.segments[0].identifier))); + let table = get_sctable(); + std::io::println("SC table:"); + for (idx,val) in table.table.iter().enumerate() { + std::io::println(fmt!("%4u : %?",idx,val)); + } + } + assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding); + }; + } + #[test] fn pat_idents(){ let pat = string_to_pat(@"(a,Foo{x:c @ (b,9),y:Bar(4,d)})"); diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 4e8b7467c5c0..d1299cf56cb0 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -12,6 +12,7 @@ use ast; use codemap::{BytePos, Pos, Span}; use ext::base::ExtCtxt; use ext::base; +use ext::expand; use ext::build::AstBuilder; use parse::token::*; use parse::token; @@ -291,47 +292,73 @@ pub mod rt { pub fn expand_quote_tokens(cx: @ExtCtxt, sp: Span, - tts: &[ast::token_tree]) -> base::MacResult { + tts: &[ast::token_tree], + ctxt: ast::SyntaxContext) -> base::MacResult { let (cx_expr, expr) = expand_tts(cx, sp, tts); - base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr)) + let expanded = expand_wrapper(cx, sp, cx_expr, expr); + // repaint the expanded code so it's as though it was the original text. + let repainted = expand::replace_ctxts(expanded,ctxt); + base::MRExpr(repainted) } pub fn expand_quote_expr(cx: @ExtCtxt, sp: Span, - tts: &[ast::token_tree]) -> base::MacResult { - base::MRExpr(expand_parse_call(cx, sp, "parse_expr", ~[], tts)) + tts: &[ast::token_tree], + ctxt: ast::SyntaxContext) -> base::MacResult { + let expanded = expand_parse_call(cx, sp, "parse_expr", ~[], tts); + // repaint the expanded code so it's as though it was the original text. + let repainted = expand::replace_ctxts(expanded,ctxt); + base::MRExpr(repainted) } +// these probably need to be capturing, too... + pub fn expand_quote_item(cx: @ExtCtxt, sp: Span, - tts: &[ast::token_tree]) -> base::MacResult { + tts: &[ast::token_tree], + ctxt: ast::SyntaxContext) -> base::MacResult { let e_attrs = cx.expr_vec_uniq(sp, ~[]); - base::MRExpr(expand_parse_call(cx, sp, "parse_item", - ~[e_attrs], tts)) + let expanded = expand_parse_call(cx, sp, "parse_item", + ~[e_attrs], tts); + // repaint the expanded code so it's as though it was the original text. + let repainted = expand::replace_ctxts(expanded,ctxt); + base::MRExpr(repainted) } pub fn expand_quote_pat(cx: @ExtCtxt, sp: Span, - tts: &[ast::token_tree]) -> base::MacResult { + tts: &[ast::token_tree], + ctxt: ast::SyntaxContext) -> base::MacResult { let e_refutable = cx.expr_lit(sp, ast::lit_bool(true)); - base::MRExpr(expand_parse_call(cx, sp, "parse_pat", - ~[e_refutable], tts)) + let expanded = expand_parse_call(cx, sp, "parse_pat", + ~[e_refutable], tts); + // repaint the expanded code so it's as though it was the original text. + let repainted = expand::replace_ctxts(expanded,ctxt); + base::MRExpr(repainted) } pub fn expand_quote_ty(cx: @ExtCtxt, sp: Span, - tts: &[ast::token_tree]) -> base::MacResult { + tts: &[ast::token_tree], + ctxt: ast::SyntaxContext) -> base::MacResult { let e_param_colons = cx.expr_lit(sp, ast::lit_bool(false)); - base::MRExpr(expand_parse_call(cx, sp, "parse_ty", - ~[e_param_colons], tts)) + let expanded = expand_parse_call(cx, sp, "parse_ty", + ~[e_param_colons], tts); + // repaint the expanded code so it's as though it was the original text. + let repainted = expand::replace_ctxts(expanded,ctxt); + base::MRExpr(repainted) } pub fn expand_quote_stmt(cx: @ExtCtxt, sp: Span, - tts: &[ast::token_tree]) -> base::MacResult { + tts: &[ast::token_tree], + ctxt: ast::SyntaxContext) -> base::MacResult { let e_attrs = cx.expr_vec_uniq(sp, ~[]); - base::MRExpr(expand_parse_call(cx, sp, "parse_stmt", - ~[e_attrs], tts)) + let expanded = expand_parse_call(cx, sp, "parse_stmt", + ~[e_attrs], tts); + // repaint the expanded code so it's as though it was the original text. + let repainted = expand::replace_ctxts(expanded,ctxt); + base::MRExpr(repainted) } fn ids_ext(strs: ~[~str]) -> ~[ast::Ident] { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 2145e4297e79..074ec3cd195e 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -150,8 +150,8 @@ pub fn add_new_extension(cx: @ExtCtxt, cx.span_fatal(best_fail_spot, best_fail_msg); } - let exp: @fn(@ExtCtxt, Span, &[ast::token_tree]) -> MacResult = - |cx, sp, arg| generic_extension(cx, sp, name, arg, *lhses, *rhses); + let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult = + |cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses); return MRDef(MacroDef{ name: ident_to_str(&name), diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 823e018a7187..b805d55830f1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -209,6 +209,7 @@ pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate { } fn noop_fold_view_item(vi: &view_item_, _fld: @ast_fold) -> view_item_ { + // FIXME #7654: doesn't iterate over idents in a view_item_use return /* FIXME (#2543) */ (*vi).clone(); }