1
Fork 0

librustc: Change fold to use traits instead of @fn.

This commit is contained in:
Patrick Walton 2013-08-29 12:10:02 -07:00
parent 9705399504
commit 3e5de06135
12 changed files with 1335 additions and 1258 deletions

View file

@ -11,9 +11,22 @@
use driver::session::Session; use driver::session::Session;
use syntax::ast; use syntax::ast;
use syntax::ast_util; use syntax::fold::ast_fold;
struct NodeIdAssigner {
sess: Session,
}
impl ast_fold for NodeIdAssigner {
fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
assert_eq!(old_id, ast::DUMMY_NODE_ID);
self.sess.next_node_id()
}
}
pub fn assign_node_ids(sess: Session, crate: @ast::Crate) -> @ast::Crate { pub fn assign_node_ids(sess: Session, crate: @ast::Crate) -> @ast::Crate {
let fold = ast_util::node_id_assigner(|| sess.next_node_id()); let fold = NodeIdAssigner {
sess: sess,
};
@fold.fold_crate(crate) @fold.fold_crate(crate)
} }

View file

@ -10,6 +10,7 @@
use std::option; use std::option;
use syntax::fold::ast_fold;
use syntax::{ast, fold, attr}; use syntax::{ast, fold, attr};
type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool; type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool;
@ -26,21 +27,34 @@ pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate {
} }
} }
pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) struct ItemRemover {
-> @ast::Crate { ctxt: @Context,
}
let ctxt = @Context { in_cfg: in_cfg }; impl fold::ast_fold for ItemRemover {
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
fold_mod(self.ctxt, module, self)
}
fn fold_block(&self, block: &ast::Block) -> ast::Block {
fold_block(self.ctxt, block, self)
}
fn fold_foreign_mod(&self, foreign_module: &ast::foreign_mod)
-> ast::foreign_mod {
fold_foreign_mod(self.ctxt, foreign_module, self)
}
fn fold_item_underscore(&self, item: &ast::item_) -> ast::item_ {
fold_item_underscore(self.ctxt, item, self)
}
}
let precursor = @fold::AstFoldFns { pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) -> @ast::Crate {
fold_mod: |a,b| fold_mod(ctxt, a, b), let ctxt = @Context {
fold_block: |a,b| fold_block(ctxt, a, b), in_cfg: in_cfg,
fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
fold_item_underscore: |a,b| fold_item_underscore(ctxt, a, b),
.. *fold::default_ast_fold()
}; };
let precursor = ItemRemover {
let fold = fold::make_fold(precursor); ctxt: ctxt,
@fold.fold_crate(crate) };
@precursor.fold_crate(crate)
} }
fn filter_item(cx: @Context, item: @ast::item) -> fn filter_item(cx: @Context, item: @ast::item) ->
@ -56,7 +70,7 @@ fn filter_view_item<'r>(cx: @Context, view_item: &'r ast::view_item)-> Option<&'
} }
} }
fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod { fn fold_mod(cx: @Context, m: &ast::_mod, fld: &ItemRemover) -> ast::_mod {
let filtered_items = do m.items.iter().filter_map |a| { let filtered_items = do m.items.iter().filter_map |a| {
filter_item(cx, *a).and_then(|x| fld.fold_item(x)) filter_item(cx, *a).and_then(|x| fld.fold_item(x))
}.collect(); }.collect();
@ -78,12 +92,12 @@ fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) ->
} else { option::None } } else { option::None }
} }
fn fold_foreign_mod( fn fold_foreign_mod(cx: @Context, nm: &ast::foreign_mod, fld: &ItemRemover)
cx: @Context, -> ast::foreign_mod {
nm: &ast::foreign_mod, let filtered_items = nm.items
fld: @fold::ast_fold .iter()
) -> ast::foreign_mod { .filter_map(|a| filter_foreign_item(cx, *a))
let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect(); .collect();
let filtered_view_items = do nm.view_items.iter().filter_map |a| { let filtered_view_items = do nm.view_items.iter().filter_map |a| {
do filter_view_item(cx, a).map_move |x| { do filter_view_item(cx, a).map_move |x| {
fld.fold_view_item(x) fld.fold_view_item(x)
@ -97,8 +111,8 @@ fn fold_foreign_mod(
} }
} }
fn fold_item_underscore(cx: @Context, item: &ast::item_, fn fold_item_underscore(cx: @Context, item: &ast::item_, fld: &ItemRemover)
fld: @fold::ast_fold) -> ast::item_ { -> ast::item_ {
let item = match *item { let item = match *item {
ast::item_impl(ref a, ref b, ref c, ref methods) => { ast::item_impl(ref a, ref b, ref c, ref methods) => {
let methods = methods.iter().filter(|m| method_in_cfg(cx, **m)) let methods = methods.iter().filter(|m| method_in_cfg(cx, **m))
@ -133,11 +147,7 @@ fn filter_stmt(cx: @Context, stmt: @ast::Stmt) ->
} }
} }
fn fold_block( fn fold_block(cx: @Context, b: &ast::Block, fld: &ItemRemover) -> ast::Block {
cx: @Context,
b: &ast::Block,
fld: @fold::ast_fold
) -> ast::Block {
let resulting_stmts = do b.stmts.iter().filter_map |a| { let resulting_stmts = do b.stmts.iter().filter_map |a| {
filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt)) filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
}.collect(); }.collect();

View file

@ -16,6 +16,7 @@ use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::codemap::dummy_sp; use syntax::codemap::dummy_sp;
use syntax::codemap; use syntax::codemap;
use syntax::fold::ast_fold;
use syntax::fold; use syntax::fold;
use syntax::opt_vec; use syntax::opt_vec;
@ -38,20 +39,27 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "no_implicit_prelude") attr::contains_name(attrs, "no_implicit_prelude")
} }
fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate { fn spanned<T>(x: T) -> codemap::Spanned<T> {
fn spanned<T>(x: T) -> codemap::Spanned<T> { codemap::Spanned {
codemap::Spanned { node: x, span: dummy_sp() } node: x,
span: dummy_sp(),
} }
}
let precursor = @fold::AstFoldFns { struct StandardLibraryInjector {
fold_crate: |crate, fld| { sess: Session,
let n1 = ast::DUMMY_NODE_ID; }
impl fold::ast_fold for StandardLibraryInjector {
fn fold_crate(&self, crate: &ast::Crate) -> ast::Crate {
let version = STD_VERSION.to_managed();
let vi1 = ast::view_item { let vi1 = ast::view_item {
node: ast::view_item_extern_mod( node: ast::view_item_extern_mod(self.sess.ident_of("std"),
sess.ident_of("std"), None, ~[], n1), None,
~[],
ast::DUMMY_NODE_ID),
attrs: ~[ attrs: ~[
attr::mk_attr( attr::mk_attr(attr::mk_name_value_item_str(@"vers", version))
attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
], ],
vis: ast::private, vis: ast::private,
span: dummy_sp() span: dummy_sp()
@ -66,7 +74,7 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
if !no_prelude(crate.attrs) { if !no_prelude(crate.attrs) {
// only add `use std::prelude::*;` if there wasn't a // only add `use std::prelude::*;` if there wasn't a
// `#[no_implicit_prelude];` at the crate level. // `#[no_implicit_prelude];` at the crate level.
new_module = fld.fold_mod(&new_module); new_module = self.fold_mod(&new_module);
} }
// FIXME #2543: Bad copy. // FIXME #2543: Bad copy.
@ -74,42 +82,45 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
module: new_module, module: new_module,
..(*crate).clone() ..(*crate).clone()
} }
}, }
fold_item: |item, fld| {
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
if !no_prelude(item.attrs) { if !no_prelude(item.attrs) {
// only recur if there wasn't `#[no_implicit_prelude];` // only recur if there wasn't `#[no_implicit_prelude];`
// on this item, i.e. this means that the prelude is not // on this item, i.e. this means that the prelude is not
// implicitly imported though the whole subtree // implicitly imported though the whole subtree
fold::noop_fold_item(item, fld) fold::noop_fold_item(item, self)
} else { } else {
Some(item) Some(item)
} }
}, }
fold_mod: |module, fld| {
let n2 = ast::DUMMY_NODE_ID;
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
let prelude_path = ast::Path { let prelude_path = ast::Path {
span: dummy_sp(), span: dummy_sp(),
global: false, global: false,
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: sess.ident_of("std"), identifier: self.sess.ident_of("std"),
lifetime: None, lifetime: None,
types: opt_vec::Empty, types: opt_vec::Empty,
}, },
ast::PathSegment { ast::PathSegment {
identifier: sess.ident_of("prelude"), identifier: self.sess.ident_of("prelude"),
lifetime: None, lifetime: None,
types: opt_vec::Empty, types: opt_vec::Empty,
}, },
], ],
}; };
let vp = @spanned(ast::view_path_glob(prelude_path, n2)); let vp = @spanned(ast::view_path_glob(prelude_path,
let vi2 = ast::view_item { node: ast::view_item_use(~[vp]), ast::DUMMY_NODE_ID));
let vi2 = ast::view_item {
node: ast::view_item_use(~[vp]),
attrs: ~[], attrs: ~[],
vis: ast::private, vis: ast::private,
span: dummy_sp() }; span: dummy_sp(),
};
let vis = vec::append(~[vi2], module.view_items); let vis = vec::append(~[vi2], module.view_items);
@ -118,11 +129,13 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
view_items: vis, view_items: vis,
..(*module).clone() ..(*module).clone()
}; };
fold::noop_fold_mod(&new_module, fld) fold::noop_fold_mod(&new_module, self)
}, }
..*fold::default_ast_fold() }
};
let fold = fold::make_fold(precursor); fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
let fold = StandardLibraryInjector {
sess: sess,
};
@fold.fold_crate(crate) @fold.fold_crate(crate)
} }

View file

@ -21,6 +21,7 @@ use syntax::attr;
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan}; use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan};
use syntax::codemap; use syntax::codemap;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::fold::ast_fold;
use syntax::fold; use syntax::fold;
use syntax::opt_vec; use syntax::opt_vec;
use syntax::print::pprust; use syntax::print::pprust;
@ -61,50 +62,58 @@ pub fn modify_for_testing(sess: session::Session,
} }
} }
fn generate_test_harness(sess: session::Session, struct TestHarnessGenerator {
crate: @ast::Crate) cx: @mut TestCtxt,
-> @ast::Crate { }
let cx: @mut TestCtxt = @mut TestCtxt {
sess: sess, impl fold::ast_fold for TestHarnessGenerator {
crate: crate, fn fold_crate(&self, c: &ast::Crate) -> ast::Crate {
ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()), let folded = fold::noop_fold_crate(c, self);
path: ~[],
testfns: ~[] // Add a special __test module to the crate that will contain code
// generated for the test harness
ast::Crate {
module: add_test_module(self.cx, &folded.module),
.. folded
}
}
fn fold_item(&self, i: @ast::item) -> Option<@ast::item> {
self.cx.path.push(i.ident);
debug!("current path: %s",
ast_util::path_name_i(self.cx.path.clone()));
if is_test_fn(self.cx, i) || is_bench_fn(i) {
match i.node {
ast::item_fn(_, purity, _, _, _)
if purity == ast::unsafe_fn => {
let sess = self.cx.sess;
sess.span_fatal(i.span,
"unsafe functions cannot be used for \
tests");
}
_ => {
debug!("this is a test function");
let test = Test {
span: i.span,
path: self.cx.path.clone(),
bench: is_bench_fn(i),
ignore: is_ignored(self.cx, i),
should_fail: should_fail(i)
}; };
self.cx.testfns.push(test);
let ext_cx = cx.ext_cx; // debug!("have %u test/bench functions",
ext_cx.bt_push(ExpnInfo { // cx.testfns.len());
call_site: dummy_sp(), }
callee: NameAndSpan { }
name: @"test",
span: None
} }
});
let precursor = @fold::AstFoldFns { let res = fold::noop_fold_item(i, self);
fold_crate: |a,b| fold_crate(cx, a, b), self.cx.path.pop();
fold_item: |a,b| fold_item(cx, a, b),
fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
let fold = fold::make_fold(precursor);
let res = @fold.fold_crate(&*crate);
ext_cx.bt_pop();
return res; return res;
}
fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
// When not compiling with --test we should not compile the
// #[test] functions
do config::strip_items(crate) |attrs| {
!attr::contains_name(attrs, "test") &&
!attr::contains_name(attrs, "bench")
} }
}
fn fold_mod(cx: @mut TestCtxt, fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
m: &ast::_mod,
fld: @fold::ast_fold)
-> ast::_mod {
// Remove any #[main] from the AST so it doesn't clash with // Remove any #[main] from the AST so it doesn't clash with
// the one we're going to add. Only if compiling an executable. // the one we're going to add. Only if compiling an executable.
@ -127,59 +136,49 @@ fn fold_mod(cx: @mut TestCtxt,
let mod_nomain = ast::_mod { let mod_nomain = ast::_mod {
view_items: m.view_items.clone(), view_items: m.view_items.clone(),
items: m.items.iter().map(|i| nomain(cx, *i)).collect(), items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
}; };
fold::noop_fold_mod(&mod_nomain, fld) fold::noop_fold_mod(&mod_nomain, self)
}
fn fold_crate(cx: @mut TestCtxt, c: &ast::Crate, fld: @fold::ast_fold)
-> ast::Crate {
let folded = fold::noop_fold_crate(c, fld);
// Add a special __test module to the crate that will contain code
// generated for the test harness
ast::Crate {
module: add_test_module(cx, &folded.module),
.. folded
} }
} }
fn generate_test_harness(sess: session::Session, crate: @ast::Crate)
fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold) -> @ast::Crate {
-> Option<@ast::item> { let cx: @mut TestCtxt = @mut TestCtxt {
cx.path.push(i.ident); sess: sess,
debug!("current path: %s", crate: crate,
ast_util::path_name_i(cx.path.clone())); ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
path: ~[],
if is_test_fn(cx, i) || is_bench_fn(i) { testfns: ~[]
match i.node {
ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => {
let sess = cx.sess;
sess.span_fatal(
i.span,
"unsafe functions cannot be used for tests");
}
_ => {
debug!("this is a test function");
let test = Test {
span: i.span,
path: cx.path.clone(),
bench: is_bench_fn(i),
ignore: is_ignored(cx, i),
should_fail: should_fail(i)
}; };
cx.testfns.push(test);
// debug!("have %u test/bench functions", cx.testfns.len());
}
}
}
let res = fold::noop_fold_item(i, fld); let ext_cx = cx.ext_cx;
cx.path.pop(); ext_cx.bt_push(ExpnInfo {
call_site: dummy_sp(),
callee: NameAndSpan {
name: @"test",
span: None
}
});
let fold = TestHarnessGenerator {
cx: cx
};
let res = @fold.fold_crate(&*crate);
ext_cx.bt_pop();
return res; return res;
} }
fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
// When not compiling with --test we should not compile the
// #[test] functions
do config::strip_items(crate) |attrs| {
!attr::contains_name(attrs, "test") &&
!attr::contains_name(attrs, "bench")
}
}
fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool { fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
let has_test_attr = attr::contains_name(i.attrs, "test"); let has_test_attr = attr::contains_name(i.attrs, "test");

View file

@ -287,25 +287,23 @@ fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) {
ebml_w.end_tag(); ebml_w.end_tag();
} }
// Produces a simplified copy of the AST which does not include things struct NestedItemsDropper {
// that we do not need to or do not want to export. For example, we contents: (),
// do not include any nested items: if these nested items are to be }
// inlined, their AST will be exported separately (this only makes
// sense because, in Rust, nested items are independent except for impl fold::ast_fold for NestedItemsDropper {
// their visibility). fn fold_block(&self, blk: &ast::Block) -> ast::Block {
//
// As it happens, trans relies on the fact that we do not export
// nested items, as otherwise it would get confused when translating
// inlined items.
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| { let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
match stmt.node { match stmt.node {
ast::StmtExpr(_, _) | ast::StmtSemi(_, _) | ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
ast::StmtDecl(@codemap::Spanned { node: ast::DeclLocal(_), span: _}, _) ast::StmtDecl(@codemap::Spanned {
=> Some(*stmt), node: ast::DeclLocal(_),
ast::StmtDecl(@codemap::Spanned { node: ast::DeclItem(_), span: _}, _) span: _
=> None, }, _) => Some(*stmt),
ast::StmtDecl(@codemap::Spanned {
node: ast::DeclItem(_),
span: _
}, _) => None,
ast::StmtMac(*) => fail!("unexpanded macro in astencode") ast::StmtMac(*) => fail!("unexpanded macro in astencode")
} }
}.collect(); }.collect();
@ -318,13 +316,24 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
rules: blk.rules, rules: blk.rules,
span: blk.span, span: blk.span,
}; };
fold::noop_fold_block(&blk_sans_items, fld) fold::noop_fold_block(&blk_sans_items, self)
} }
}
let fld = fold::make_fold(@fold::AstFoldFns { // Produces a simplified copy of the AST which does not include things
fold_block: drop_nested_items, // that we do not need to or do not want to export. For example, we
.. *fold::default_ast_fold() // do not include any nested items: if these nested items are to be
}); // inlined, their AST will be exported separately (this only makes
// sense because, in Rust, nested items are independent except for
// their visibility).
//
// As it happens, trans relies on the fact that we do not export
// nested items, as otherwise it would get confused when translating
// inlined items.
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
let fld = NestedItemsDropper {
contents: (),
};
match *ii { match *ii {
//hack: we're not dropping items //hack: we're not dropping items
@ -341,14 +350,24 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
Decodable::decode(&mut d) Decodable::decode(&mut d)
} }
struct AstRenumberer {
xcx: @ExtendedDecodeContext,
}
impl fold::ast_fold for AstRenumberer {
fn new_id(&self, id: ast::NodeId) -> ast::NodeId {
self.xcx.tr_id(id)
}
fn new_span(&self, span: Span) -> Span {
self.xcx.tr_span(span)
}
}
fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item)
-> ast::inlined_item { -> ast::inlined_item {
let fld = fold::make_fold(@fold::AstFoldFns{ let fld = AstRenumberer {
new_id: |a| xcx.tr_id(a), xcx: xcx,
new_span: |a| xcx.tr_span(a), };
.. *fold::default_ast_fold()
});
match ii { match ii {
ast::ii_item(i) => ast::ii_item(fld.fold_item(i).unwrap()), ast::ii_item(i) => ast::ii_item(fld.fold_item(i).unwrap()),
ast::ii_method(d, is_provided, m) => ast::ii_method(d, is_provided, m) =>

View file

@ -18,6 +18,8 @@ use syntax::codemap::{dummy_sp, Spanned};
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::{ast, attr, codemap, diagnostic, fold}; use syntax::{ast, attr, codemap, diagnostic, fold};
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
use syntax::fold::ast_fold;
use rustc::back::link::output_type_exe;
use rustc::back::link; use rustc::back::link;
use rustc::driver::session::{lib_crate, bin_crate}; use rustc::driver::session::{lib_crate, bin_crate};
use context::{in_target, StopBefore, Link, Assemble, BuildContext}; use context::{in_target, StopBefore, Link, Assemble, BuildContext};
@ -70,9 +72,8 @@ struct ReadyCtx {
fns: ~[ListenerFn] fns: ~[ListenerFn]
} }
fn fold_mod(_ctx: @mut ReadyCtx, fn fold_mod(_ctx: @mut ReadyCtx, m: &ast::_mod, fold: &CrateSetup)
m: &ast::_mod, -> ast::_mod {
fold: @fold::ast_fold) -> ast::_mod {
fn strip_main(item: @ast::item) -> @ast::item { fn strip_main(item: @ast::item) -> @ast::item {
@ast::item { @ast::item {
attrs: do item.attrs.iter().filter_map |attr| { attrs: do item.attrs.iter().filter_map |attr| {
@ -94,9 +95,8 @@ fn fold_mod(_ctx: @mut ReadyCtx,
}, fold) }, fold)
} }
fn fold_item(ctx: @mut ReadyCtx, fn fold_item(ctx: @mut ReadyCtx, item: @ast::item, fold: &CrateSetup)
item: @ast::item, -> Option<@ast::item> {
fold: @fold::ast_fold) -> Option<@ast::item> {
ctx.path.push(item.ident); ctx.path.push(item.ident);
let mut cmds = ~[]; let mut cmds = ~[];
@ -134,6 +134,19 @@ fn fold_item(ctx: @mut ReadyCtx,
res res
} }
struct CrateSetup {
ctx: @mut ReadyCtx,
}
impl fold::ast_fold for CrateSetup {
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
fold_item(self.ctx, item, self)
}
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
fold_mod(self.ctx, module, self)
}
}
/// Generate/filter main function, add the list of commands, etc. /// Generate/filter main function, add the list of commands, etc.
pub fn ready_crate(sess: session::Session, pub fn ready_crate(sess: session::Session,
crate: @ast::Crate) -> @ast::Crate { crate: @ast::Crate) -> @ast::Crate {
@ -144,15 +157,9 @@ pub fn ready_crate(sess: session::Session,
path: ~[], path: ~[],
fns: ~[] fns: ~[]
}; };
let precursor = @fold::AstFoldFns { let fold = CrateSetup {
// fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)), ctx: ctx,
fold_item: |a, b| fold_item(ctx, a, b),
fold_mod: |a, b| fold_mod(ctx, a, b),
.. *fold::default_ast_fold()
}; };
let fold = fold::make_fold(precursor);
@fold.fold_crate(crate) @fold.fold_crate(crate)
} }

View file

@ -12,7 +12,6 @@ use ast::*;
use ast; use ast;
use ast_util; use ast_util;
use codemap::{Span, dummy_sp}; use codemap::{Span, dummy_sp};
use fold;
use opt_vec; use opt_vec;
use parse::token; use parse::token;
use visit::Visitor; use visit::Visitor;
@ -371,21 +370,6 @@ pub fn empty_generics() -> Generics {
ty_params: opt_vec::Empty} ty_params: opt_vec::Empty}
} }
///////////////////////////////////////////////////////////////////////////
// Assigning node ids
fn node_id_assigner(next_id: @fn() -> ast::NodeId) -> @fold::ast_fold {
let precursor = @fold::AstFoldFns {
new_id: |old_id| {
assert_eq!(old_id, ast::DUMMY_NODE_ID);
next_id()
},
..*fold::default_ast_fold()
};
fold::make_fold(precursor)
}
// ______________________________________________________________________ // ______________________________________________________________________
// Enumerating the IDs which appear in an AST // Enumerating the IDs which appear in an AST

View file

@ -15,6 +15,7 @@ use ast_util;
use codemap::{Span, respan, dummy_sp}; use codemap::{Span, respan, dummy_sp};
use ext::base::ExtCtxt; use ext::base::ExtCtxt;
use ext::quote::rt::*; use ext::quote::rt::*;
use fold;
use opt_vec; use opt_vec;
use opt_vec::OptVec; use opt_vec::OptVec;
@ -862,3 +863,32 @@ impl AstBuilder for @ExtCtxt {
ast::view_path_glob(self.path(sp, path), ast::DUMMY_NODE_ID))]) ast::view_path_glob(self.path(sp, path), ast::DUMMY_NODE_ID))])
} }
} }
struct Duplicator {
cx: @ExtCtxt,
}
impl fold::ast_fold for Duplicator {
fn new_id(&self, _: NodeId) -> NodeId {
ast::DUMMY_NODE_ID
}
}
pub trait Duplicate {
//
// Duplication functions
//
// These functions just duplicate AST nodes.
//
fn duplicate(&self, cx: @ExtCtxt) -> Self;
}
impl Duplicate for @ast::Expr {
fn duplicate(&self, cx: @ExtCtxt) -> @ast::Expr {
let folder = @Duplicator {
cx: cx,
} as @fold::ast_fold;
folder.fold_expr(*self)
}
}

View file

@ -10,7 +10,7 @@
use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext}; use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
use ast::{Local, Ident, mac_invoc_tt}; use ast::{Local, Ident, mac_invoc_tt};
use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi}; use ast::{item_mac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::{token_tree}; use ast::{token_tree};
use ast; use ast;
use ast_util::{mtwt_outer_mark, new_rename, new_mark}; use ast_util::{mtwt_outer_mark, new_rename, new_mark};
@ -21,6 +21,7 @@ use codemap;
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan}; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
use ext::base::*; use ext::base::*;
use fold::*; use fold::*;
use opt_vec;
use parse; use parse;
use parse::{parse_item_from_source_str}; use parse::{parse_item_from_source_str};
use parse::token; use parse::token;
@ -32,12 +33,10 @@ use std::vec;
pub fn expand_expr(extsbox: @mut SyntaxEnv, pub fn expand_expr(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt, cx: @ExtCtxt,
e: &Expr_, e: @ast::Expr,
span: Span, fld: &MacroExpander)
fld: @ast_fold, -> @ast::Expr {
orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span)) match e.node {
-> (Expr_, Span) {
match *e {
// expr_mac should really be expr_ext or something; it's the // expr_mac should really be expr_ext or something; it's the
// entry-point for all syntax extensions. // entry-point for all syntax extensions.
ExprMac(ref mac) => { ExprMac(ref mac) => {
@ -66,7 +65,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
} }
Some(@SE(NormalTT(expandfun, exp_span))) => { Some(@SE(NormalTT(expandfun, exp_span))) => {
cx.bt_push(ExpnInfo { cx.bt_push(ExpnInfo {
call_site: span, call_site: e.span,
callee: NameAndSpan { callee: NameAndSpan {
name: extnamestr, name: extnamestr,
span: exp_span, span: exp_span,
@ -101,12 +100,19 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
// mark after: // mark after:
let marked_after = mark_expr(expanded,fm); let marked_after = mark_expr(expanded,fm);
//keep going, outside-in // Keep going, outside-in.
//
// XXX(pcwalton): Is it necessary to clone the
// node here?
let fully_expanded = let fully_expanded =
fld.fold_expr(marked_after).node.clone(); fld.fold_expr(marked_after).node.clone();
cx.bt_pop(); cx.bt_pop();
(fully_expanded, span) @ast::Expr {
id: ast::DUMMY_NODE_ID,
node: fully_expanded,
span: e.span,
}
} }
_ => { _ => {
cx.span_fatal( cx.span_fatal(
@ -125,8 +131,48 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => { ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
// Expand any interior macros etc. // Expand any interior macros etc.
// NB: we don't fold pats yet. Curious. // NB: we don't fold pats yet. Curious.
let src_expr = fld.fold_expr(src_expr); let src_expr = fld.fold_expr(src_expr).clone();
let src_loop_block = fld.fold_block(src_loop_block); let src_loop_block = fld.fold_block(src_loop_block).clone();
let span = e.span;
pub fn mk_expr(_: @ExtCtxt, span: Span, node: Expr_)
-> @ast::Expr {
@ast::Expr {
id: ast::DUMMY_NODE_ID,
node: node,
span: span,
}
}
fn mk_block(_: @ExtCtxt,
stmts: &[@ast::Stmt],
expr: Option<@ast::Expr>,
span: Span)
-> ast::Block {
ast::Block {
view_items: ~[],
stmts: stmts.to_owned(),
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: ast::DefaultBlock,
span: span,
}
}
fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path {
ast::Path {
span: span,
global: false,
segments: ~[
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
// to: // to:
// //
@ -182,10 +228,14 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
~[iter_decl_stmt], ~[iter_decl_stmt],
Some(loop_expr)); Some(loop_expr));
(ast::ExprBlock(block), span) @ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprBlock(block),
span: span,
}
} }
_ => orig(e, span, fld) _ => noop_fold_expr(e, fld)
} }
} }
@ -201,12 +251,10 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
pub fn expand_mod_items(extsbox: @mut SyntaxEnv, pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt, cx: @ExtCtxt,
module_: &ast::_mod, module_: &ast::_mod,
fld: @ast_fold, fld: &MacroExpander)
orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod)
-> ast::_mod { -> ast::_mod {
// Fold the contents first: // Fold the contents first:
let module_ = orig(module_, fld); let module_ = noop_fold_mod(module_, fld);
// For each item, look through the attributes. If any of them are // For each item, look through the attributes. If any of them are
// decorated with "item decorators", then use that function to transform // decorated with "item decorators", then use that function to transform
@ -233,7 +281,10 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
} }
}; };
ast::_mod { items: new_items, ..module_ } ast::_mod {
items: new_items,
..module_
}
} }
// eval $e with a new exts frame: // eval $e with a new exts frame:
@ -256,19 +307,20 @@ static special_block_name : &'static str = " block";
pub fn expand_item(extsbox: @mut SyntaxEnv, pub fn expand_item(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt, cx: @ExtCtxt,
it: @ast::item, it: @ast::item,
fld: @ast_fold, fld: &MacroExpander)
orig: @fn(@ast::item, @ast_fold) -> Option<@ast::item>)
-> Option<@ast::item> { -> Option<@ast::item> {
match it.node { match it.node {
ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld), ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
ast::item_mod(_) | ast::item_foreign_mod(_) => { ast::item_mod(_) | ast::item_foreign_mod(_) => {
cx.mod_push(it.ident); cx.mod_push(it.ident);
let macro_escape = contains_macro_escape(it.attrs); let macro_escape = contains_macro_escape(it.attrs);
let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld)); let result = with_exts_frame!(extsbox,
macro_escape,
noop_fold_item(it, fld));
cx.mod_pop(); cx.mod_pop();
result result
}, },
_ => orig(it,fld) _ => noop_fold_item(it, fld)
} }
} }
@ -280,11 +332,15 @@ pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
// Support for item-position macro invocations, exactly the same // Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations. // logic as for expression-position macro invocations.
pub fn expand_item_mac(extsbox: @mut SyntaxEnv, pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt, it: @ast::item, cx: @ExtCtxt,
fld: @ast_fold) it: @ast::item,
fld: &MacroExpander)
-> Option<@ast::item> { -> Option<@ast::item> {
let (pth, tts, ctxt) = match it.node { let (pth, tts, ctxt) = match it.node {
item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => { item_mac(codemap::Spanned {
node: mac_invoc_tt(ref pth, ref tts, ctxt),
_
}) => {
(pth, (*tts).clone(), ctxt) (pth, (*tts).clone(), ctxt)
} }
_ => cx.span_bug(it.span, "invalid item macro invocation") _ => cx.span_bug(it.span, "invalid item macro invocation")
@ -382,15 +438,12 @@ fn insert_macro(exts: SyntaxEnv, name: ast::Name, transformer: @Transformer) {
// expand a stmt // expand a stmt
pub fn expand_stmt(extsbox: @mut SyntaxEnv, pub fn expand_stmt(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt, cx: @ExtCtxt,
s: &Stmt_, s: &Stmt,
sp: Span, fld: &MacroExpander)
fld: @ast_fold, -> Option<@Stmt> {
orig: @fn(&Stmt_, Span, @ast_fold)
-> (Option<Stmt_>, Span))
-> (Option<Stmt_>, Span) {
// why the copying here and not in expand_expr? // why the copying here and not in expand_expr?
// looks like classic changed-in-only-one-place // looks like classic changed-in-only-one-place
let (pth, tts, semi, ctxt) = match *s { let (pth, tts, semi, ctxt) = match s.node {
StmtMac(ref mac, semi) => { StmtMac(ref mac, semi) => {
match mac.node { match mac.node {
mac_invoc_tt(ref pth, ref tts, ctxt) => { mac_invoc_tt(ref pth, ref tts, ctxt) => {
@ -398,24 +451,26 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
} }
} }
} }
_ => return expand_non_macro_stmt(*extsbox,s,sp,fld,orig) _ => return expand_non_macro_stmt(*extsbox, s, fld)
}; };
if (pth.segments.len() > 1u) { if (pth.segments.len() > 1u) {
cx.span_fatal( cx.span_fatal(pth.span,
pth.span, "expected macro name without module separators");
fmt!("expected macro name without module \
separators"));
} }
let extname = &pth.segments[0].identifier; let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname); let extnamestr = ident_to_str(extname);
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) { let fully_expanded: @ast::Stmt = match (*extsbox).find(&extname.name) {
None => None => {
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr)), cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr))
}
Some(@SE(NormalTT(expandfun, exp_span))) => { Some(@SE(NormalTT(expandfun, exp_span))) => {
cx.bt_push(ExpnInfo { cx.bt_push(ExpnInfo {
call_site: sp, call_site: s.span,
callee: NameAndSpan { name: extnamestr, span: exp_span } callee: NameAndSpan {
name: extnamestr,
span: exp_span,
}
}); });
let fm = fresh_mark(); let fm = fresh_mark();
// mark before expansion: // mark before expansion:
@ -426,11 +481,16 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
// not the current mac.span. // not the current mac.span.
let mac_span = original_span(cx); let mac_span = original_span(cx);
let expanded = match expandfun(cx, mac_span.call_site, let expanded = match expandfun(cx,
marked_tts, marked_ctxt) { mac_span.call_site,
MRExpr(e) => marked_tts,
@codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID), marked_ctxt) {
span: e.span}, MRExpr(e) => {
@codemap::Spanned {
node: StmtExpr(e, ast::DUMMY_NODE_ID),
span: e.span,
}
}
MRAny(_,_,stmt_mkr) => stmt_mkr(), MRAny(_,_,stmt_mkr) => stmt_mkr(),
_ => cx.span_fatal( _ => cx.span_fatal(
pth.span, pth.span,
@ -438,12 +498,15 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}; };
let marked_after = mark_stmt(expanded,fm); let marked_after = mark_stmt(expanded,fm);
//keep going, outside-in // Keep going, outside-in.
let fully_expanded = match fld.fold_stmt(marked_after) { let fully_expanded = match fld.fold_stmt(marked_after) {
Some(stmt) => { Some(stmt) => {
let fully_expanded = &stmt.node; let fully_expanded = &stmt.node;
cx.bt_pop(); cx.bt_pop();
(*fully_expanded).clone() @Spanned {
span: stmt.span,
node: (*fully_expanded).clone(),
}
} }
None => { None => {
cx.span_fatal(pth.span, cx.span_fatal(pth.span,
@ -451,7 +514,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
} }
}; };
(fully_expanded, sp) fully_expanded
} }
_ => { _ => {
@ -460,24 +523,28 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
} }
}; };
(match fully_expanded { match fully_expanded.node {
StmtExpr(e, stmt_id) if semi => Some(StmtSemi(e, stmt_id)), StmtExpr(e, stmt_id) if semi => {
_ => { Some(fully_expanded) } /* might already have a semi */ Some(@Spanned {
}, sp) span: fully_expanded.span,
node: StmtSemi(e, stmt_id),
})
}
_ => Some(fully_expanded), /* might already have a semi */
}
} }
// expand a non-macro stmt. this is essentially the fallthrough for // expand a non-macro stmt. this is essentially the fallthrough for
// expand_stmt, above. // expand_stmt, above.
fn expand_non_macro_stmt (exts: SyntaxEnv, fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
s: &Stmt_, -> Option<@Stmt> {
sp: Span,
fld: @ast_fold,
orig: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span))
-> (Option<Stmt_>,Span) {
// is it a let? // is it a let?
match *s { match s.node {
StmtDecl(@Spanned{node: DeclLocal(ref local), span: stmt_span}, node_id) => { StmtDecl(@Spanned {
node: DeclLocal(ref local),
span: stmt_span
},
node_id) => {
let block_info = get_block_info(exts); let block_info = get_block_info(exts);
let pending_renames = block_info.pending_renames; let pending_renames = block_info.pending_renames;
@ -515,19 +582,24 @@ fn expand_non_macro_stmt (exts: SyntaxEnv,
// also, don't forget to expand the init: // also, don't forget to expand the init:
let new_init_opt = init.map(|e| fld.fold_expr(*e)); let new_init_opt = init.map(|e| fld.fold_expr(*e));
let rewritten_local = let rewritten_local =
@Local{is_mutbl:is_mutbl, @Local {
ty:ty, is_mutbl: is_mutbl,
pat:rewritten_pat, ty: ty,
init:new_init_opt, pat: rewritten_pat,
id:id, init: new_init_opt,
span:span}; id: id,
(Some(StmtDecl(@Spanned{node:DeclLocal(rewritten_local), span: span,
span: stmt_span},node_id)), };
sp) Some(@Spanned {
node: StmtDecl(@Spanned {
node: DeclLocal(rewritten_local),
span: stmt_span
}, },
_ => { node_id),
orig(s, sp, fld) span: span
} })
},
_ => noop_fold_stmt(s, fld),
} }
} }
@ -628,10 +700,9 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
// expand a block. pushes a new exts_frame, then calls expand_block_elts // expand a block. pushes a new exts_frame, then calls expand_block_elts
pub fn expand_block(extsbox: @mut SyntaxEnv, pub fn expand_block(extsbox: @mut SyntaxEnv,
_cx: @ExtCtxt, _: @ExtCtxt,
blk: &Block, blk: &Block,
fld: @ast_fold, fld: &MacroExpander)
_orig: @fn(&Block, @ast_fold) -> Block)
-> Block { -> Block {
// see note below about treatment of exts table // see note below about treatment of exts table
with_exts_frame!(extsbox,false, with_exts_frame!(extsbox,false,
@ -639,7 +710,8 @@ pub fn expand_block(extsbox: @mut SyntaxEnv,
} }
// expand the elements of a block. // expand the elements of a block.
pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: @ast_fold) -> Block { pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: &MacroExpander)
-> Block {
let block_info = get_block_info(exts); let block_info = get_block_info(exts);
let pending_renames = block_info.pending_renames; let pending_renames = block_info.pending_renames;
let rename_fld = renames_to_fold(pending_renames); let rename_fld = renames_to_fold(pending_renames);
@ -680,9 +752,47 @@ fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
} }
} }
struct IdentRenamer {
renames: @mut ~[(ast::Ident,ast::Name)],
}
impl ast_fold for IdentRenamer {
fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| {
new_rename(from, to, ctxt)
});
ast::Ident {
name: id.name,
ctxt: new_ctxt,
}
}
}
// given a mutable list of renames, return a tree-folder that applies those
// renames.
fn renames_to_fold(renames: @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
@IdentRenamer {
renames: renames,
} as @ast_fold
}
// perform a bunch of renames
fn apply_pending_renames(folder : @ast_fold, stmt : ast::Stmt) -> @ast::Stmt {
match folder.fold_stmt(&stmt) {
Some(s) => s,
None => fail!(fmt!("renaming of stmt produced None"))
}
}
pub fn new_span(cx: @ExtCtxt, sp: Span) -> Span { pub fn new_span(cx: @ExtCtxt, sp: Span) -> Span {
/* this discards information in the case of macro-defining macros */ /* this discards information in the case of macro-defining macros */
return Span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()}; Span {
lo: sp.lo,
hi: sp.hi,
expn_info: cx.backtrace(),
}
} }
// FIXME (#2247): this is a moderately bad kludge to inject some macros into // FIXME (#2247): this is a moderately bad kludge to inject some macros into
@ -1025,10 +1135,28 @@ pub fn std_macros() -> @str {
}"; }";
} }
struct Injector {
sm: @ast::item,
}
impl ast_fold for Injector {
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
// Just inject the standard macros at the start of the first module
// in the crate: that is, at the start of the crate file itself.
let items = vec::append(~[ self.sm ], module.items);
ast::_mod {
items: items,
..(*module).clone() // FIXME #2543: Bad copy.
}
}
}
// add a bunch of macros as though they were placed at the head of the // add a bunch of macros as though they were placed at the head of the
// program (ick). This should run before cfg stripping. // program (ick). This should run before cfg stripping.
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess, pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
cfg: ast::CrateConfig, c: &Crate) -> @Crate { cfg: ast::CrateConfig,
c: @Crate)
-> @Crate {
let sm = match parse_item_from_source_str(@"<std-macros>", let sm = match parse_item_from_source_str(@"<std-macros>",
std_macros(), std_macros(),
cfg.clone(), cfg.clone(),
@ -1038,48 +1166,80 @@ pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
None => fail!("expected core macros to parse correctly") None => fail!("expected core macros to parse correctly")
}; };
let injecter = @AstFoldFns { let injector = @Injector {
fold_mod: |modd, _| { sm: sm,
// just inject the std macros at the start of the first } as @ast_fold;
// module in the crate (i.e the crate file itself.) @injector.fold_crate(c)
let items = vec::append(~[sm], modd.items); }
ast::_mod {
items: items, struct NoOpFolder {
// FIXME #2543: Bad copy. contents: (),
.. (*modd).clone() }
impl ast_fold for NoOpFolder {}
struct MacroExpander {
extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
}
impl ast_fold for MacroExpander {
fn fold_expr(&self, expr: @ast::Expr) -> @ast::Expr {
expand_expr(self.extsbox,
self.cx,
expr,
self)
}
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
expand_mod_items(self.extsbox,
self.cx,
module,
self)
}
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
expand_item(self.extsbox,
self.cx,
item,
self)
}
fn fold_stmt(&self, stmt: &ast::Stmt) -> Option<@ast::Stmt> {
expand_stmt(self.extsbox,
self.cx,
stmt,
self)
}
fn fold_block(&self, block: &ast::Block) -> ast::Block {
expand_block(self.extsbox,
self.cx,
block,
self)
}
fn new_span(&self, span: Span) -> Span {
new_span(self.cx, span)
} }
},
.. *default_ast_fold()
};
@make_fold(injecter).fold_crate(c)
} }
pub fn expand_crate(parse_sess: @mut parse::ParseSess, pub fn expand_crate(parse_sess: @mut parse::ParseSess,
cfg: ast::CrateConfig, c: &Crate) -> @Crate { cfg: ast::CrateConfig,
c: &Crate) -> @Crate {
// adding *another* layer of indirection here so that the block // adding *another* layer of indirection here so that the block
// visitor can swap out one exts table for another for the duration // visitor can swap out one exts table for another for the duration
// of the block. The cleaner alternative would be to thread the // of the block. The cleaner alternative would be to thread the
// exts table through the fold, but that would require updating // exts table through the fold, but that would require updating
// every method/element of AstFoldFns in fold.rs. // every method/element of AstFoldFns in fold.rs.
let extsbox = @mut syntax_expander_table(); let extsbox = syntax_expander_table();
let afp = default_ast_fold();
let cx = ExtCtxt::new(parse_sess, cfg.clone()); let cx = ExtCtxt::new(parse_sess, cfg.clone());
let f_pre = @AstFoldFns { let expander = @MacroExpander {
fold_expr: |expr,span,recur| extsbox: @mut extsbox,
expand_expr(extsbox, cx, expr, span, recur, afp.fold_expr), cx: cx,
fold_mod: |modd,recur| } as @ast_fold;
expand_mod_items(extsbox, cx, modd, recur, afp.fold_mod),
fold_item: |item,recur|
expand_item(extsbox, cx, item, recur, afp.fold_item),
fold_stmt: |stmt,span,recur|
expand_stmt(extsbox, cx, stmt, span, recur, afp.fold_stmt),
fold_block: |blk,recur|
expand_block(extsbox, cx, blk, recur, afp.fold_block),
new_span: |a| new_span(cx, a),
.. *afp};
let f = make_fold(f_pre);
let ret = @f.fold_crate(c); let ret = @expander.fold_crate(c);
parse_sess.span_diagnostic.handler().abort_if_errors(); parse_sess.span_diagnostic.handler().abort_if_errors();
return ret; return ret;
} }
@ -1145,53 +1305,56 @@ impl CtxtFn for Repainter {
} }
} }
// given a function from ctxts to ctxts, produce pub struct ContextWrapper {
// an ast_fold that applies that function to all ctxts: context_function: @CtxtFn,
pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns { }
let afp = default_ast_fold();
let fi : @fn(ast::Ident, @ast_fold) -> ast::Ident =
|ast::Ident{name, ctxt}, _| {
ast::Ident{name:name,ctxt:cf.f(ctxt)}
};
let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
|m, sp, fld| {
match *m {
mac_invoc_tt(ref path, ref tts, ctxt) =>
(mac_invoc_tt(fld.fold_path(path),
fold_tts(*tts,fld),
cf.f(ctxt)),
sp)
}
impl ast_fold for ContextWrapper {
fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
let ast::Ident {
name,
ctxt
} = id;
ast::Ident {
name: name,
ctxt: self.context_function.f(ctxt),
}
}
fn fold_mac(&self, m: &ast::mac) -> ast::mac {
let macro = match m.node {
mac_invoc_tt(ref path, ref tts, ctxt) => {
mac_invoc_tt(self.fold_path(path),
fold_tts(*tts, self),
self.context_function.f(ctxt))
}
}; };
@AstFoldFns{ Spanned {
fold_ident : fi, node: macro,
fold_mac : fm, span: m.span,
.. *afp }
} }
} }
// given a function from ctxts to ctxts, produce
// an ast_fold that applies that function to all ctxts:
// given a mutable list of renames, return a tree-folder that applies those pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @ContextWrapper {
// renames. @ContextWrapper {
// FIXME #4536: currently pub to allow testing context_function: cf as @CtxtFn,
pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns { }
fun_to_ctxt_folder(@MultiRenamer{renames : renames})
} }
// just a convenience: // just a convenience:
pub fn new_mark_folder(m : Mrk) -> @AstFoldFns { pub fn new_mark_folder(m: Mrk) -> @ContextWrapper {
fun_to_ctxt_folder(@Marker{mark:m}) fun_to_ctxt_folder(@Marker{mark:m})
} }
pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns { pub fn new_rename_folder(from: ast::Ident, to: ast::Name) -> @ContextWrapper {
fun_to_ctxt_folder(@Renamer{from:from,to:to}) fun_to_ctxt_folder(@Renamer{from:from,to:to})
} }
// apply a given mark to the given token trees. Used prior to expansion of a macro. // apply a given mark to the given token trees. Used prior to expansion of a macro.
fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] { fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] {
fold_tts(tts,new_mark_folder(m) as @ast_fold) fold_tts(tts,new_mark_folder(m))
} }
// apply a given mark to the given expr. Used following the expansion of a macro. // apply a given mark to the given expr. Used following the expansion of a macro.

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,8 @@
// xfail-test
// xfail'd because the lint pass doesn't know to ignore standard library
// stuff.
// -*- rust -*- // -*- rust -*-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at

View file

@ -1,3 +1,7 @@
// xfail-test
// xfail'd because the lint pass doesn't know to ignore standard library
// stuff.
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.