capturing macros now implemented

This commit is contained in:
John Clements 2013-07-08 15:55:14 -07:00
parent 2c51e262f3
commit b9bb4abcb6
5 changed files with 222 additions and 85 deletions

View file

@ -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<Span>),
}
// 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)
}

View file

@ -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<Stmt_>, 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<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
@ -1454,7 +1468,7 @@ pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(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<T : 'static + CtxtFn>(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)})");

View file

@ -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] {

View file

@ -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),

View file

@ -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();
}