librustc: Change fold to use traits instead of @fn
.
This commit is contained in:
parent
9705399504
commit
3e5de06135
@ -11,9 +11,22 @@
|
||||
use driver::session::Session;
|
||||
|
||||
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 {
|
||||
let fold = ast_util::node_id_assigner(|| sess.next_node_id());
|
||||
let fold = NodeIdAssigner {
|
||||
sess: sess,
|
||||
};
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
use std::option;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::{ast, fold, attr};
|
||||
|
||||
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)
|
||||
-> @ast::Crate {
|
||||
struct ItemRemover {
|
||||
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 {
|
||||
fold_mod: |a,b| fold_mod(ctxt, a, b),
|
||||
fold_block: |a,b| fold_block(ctxt, a, b),
|
||||
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()
|
||||
pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) -> @ast::Crate {
|
||||
let ctxt = @Context {
|
||||
in_cfg: in_cfg,
|
||||
};
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
@fold.fold_crate(crate)
|
||||
let precursor = ItemRemover {
|
||||
ctxt: ctxt,
|
||||
};
|
||||
@precursor.fold_crate(crate)
|
||||
}
|
||||
|
||||
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| {
|
||||
filter_item(cx, *a).and_then(|x| fld.fold_item(x))
|
||||
}.collect();
|
||||
@ -78,12 +92,12 @@ fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) ->
|
||||
} else { option::None }
|
||||
}
|
||||
|
||||
fn fold_foreign_mod(
|
||||
cx: @Context,
|
||||
nm: &ast::foreign_mod,
|
||||
fld: @fold::ast_fold
|
||||
) -> ast::foreign_mod {
|
||||
let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect();
|
||||
fn fold_foreign_mod(cx: @Context, nm: &ast::foreign_mod, fld: &ItemRemover)
|
||||
-> ast::foreign_mod {
|
||||
let filtered_items = nm.items
|
||||
.iter()
|
||||
.filter_map(|a| filter_foreign_item(cx, *a))
|
||||
.collect();
|
||||
let filtered_view_items = do nm.view_items.iter().filter_map |a| {
|
||||
do filter_view_item(cx, a).map_move |x| {
|
||||
fld.fold_view_item(x)
|
||||
@ -97,8 +111,8 @@ fn fold_foreign_mod(
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_item_underscore(cx: @Context, item: &ast::item_,
|
||||
fld: @fold::ast_fold) -> ast::item_ {
|
||||
fn fold_item_underscore(cx: @Context, item: &ast::item_, fld: &ItemRemover)
|
||||
-> ast::item_ {
|
||||
let item = match *item {
|
||||
ast::item_impl(ref a, ref b, ref c, ref methods) => {
|
||||
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(
|
||||
cx: @Context,
|
||||
b: &ast::Block,
|
||||
fld: @fold::ast_fold
|
||||
) -> ast::Block {
|
||||
fn fold_block(cx: @Context, b: &ast::Block, fld: &ItemRemover) -> ast::Block {
|
||||
let resulting_stmts = do b.stmts.iter().filter_map |a| {
|
||||
filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
|
||||
}.collect();
|
||||
|
@ -16,6 +16,7 @@ use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::codemap::dummy_sp;
|
||||
use syntax::codemap;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::fold;
|
||||
use syntax::opt_vec;
|
||||
|
||||
@ -38,91 +39,103 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
|
||||
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> {
|
||||
codemap::Spanned { node: x, span: dummy_sp() }
|
||||
fn spanned<T>(x: T) -> codemap::Spanned<T> {
|
||||
codemap::Spanned {
|
||||
node: x,
|
||||
span: dummy_sp(),
|
||||
}
|
||||
}
|
||||
|
||||
struct StandardLibraryInjector {
|
||||
sess: Session,
|
||||
}
|
||||
|
||||
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 {
|
||||
node: ast::view_item_extern_mod(self.sess.ident_of("std"),
|
||||
None,
|
||||
~[],
|
||||
ast::DUMMY_NODE_ID),
|
||||
attrs: ~[
|
||||
attr::mk_attr(attr::mk_name_value_item_str(@"vers", version))
|
||||
],
|
||||
vis: ast::private,
|
||||
span: dummy_sp()
|
||||
};
|
||||
|
||||
let vis = vec::append(~[vi1], crate.module.view_items);
|
||||
let mut new_module = ast::_mod {
|
||||
view_items: vis,
|
||||
..crate.module.clone()
|
||||
};
|
||||
|
||||
if !no_prelude(crate.attrs) {
|
||||
// only add `use std::prelude::*;` if there wasn't a
|
||||
// `#[no_implicit_prelude];` at the crate level.
|
||||
new_module = self.fold_mod(&new_module);
|
||||
}
|
||||
|
||||
// FIXME #2543: Bad copy.
|
||||
ast::Crate {
|
||||
module: new_module,
|
||||
..(*crate).clone()
|
||||
}
|
||||
}
|
||||
|
||||
let precursor = @fold::AstFoldFns {
|
||||
fold_crate: |crate, fld| {
|
||||
let n1 = ast::DUMMY_NODE_ID;
|
||||
let vi1 = ast::view_item {
|
||||
node: ast::view_item_extern_mod(
|
||||
sess.ident_of("std"), None, ~[], n1),
|
||||
attrs: ~[
|
||||
attr::mk_attr(
|
||||
attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
|
||||
],
|
||||
vis: ast::private,
|
||||
span: dummy_sp()
|
||||
};
|
||||
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
|
||||
if !no_prelude(item.attrs) {
|
||||
// only recur if there wasn't `#[no_implicit_prelude];`
|
||||
// on this item, i.e. this means that the prelude is not
|
||||
// implicitly imported though the whole subtree
|
||||
fold::noop_fold_item(item, self)
|
||||
} else {
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
let vis = vec::append(~[vi1], crate.module.view_items);
|
||||
let mut new_module = ast::_mod {
|
||||
view_items: vis,
|
||||
..crate.module.clone()
|
||||
};
|
||||
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
|
||||
let prelude_path = ast::Path {
|
||||
span: dummy_sp(),
|
||||
global: false,
|
||||
segments: ~[
|
||||
ast::PathSegment {
|
||||
identifier: self.sess.ident_of("std"),
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
ast::PathSegment {
|
||||
identifier: self.sess.ident_of("prelude"),
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if !no_prelude(crate.attrs) {
|
||||
// only add `use std::prelude::*;` if there wasn't a
|
||||
// `#[no_implicit_prelude];` at the crate level.
|
||||
new_module = fld.fold_mod(&new_module);
|
||||
}
|
||||
let vp = @spanned(ast::view_path_glob(prelude_path,
|
||||
ast::DUMMY_NODE_ID));
|
||||
let vi2 = ast::view_item {
|
||||
node: ast::view_item_use(~[vp]),
|
||||
attrs: ~[],
|
||||
vis: ast::private,
|
||||
span: dummy_sp(),
|
||||
};
|
||||
|
||||
// FIXME #2543: Bad copy.
|
||||
ast::Crate {
|
||||
module: new_module,
|
||||
..(*crate).clone()
|
||||
}
|
||||
},
|
||||
fold_item: |item, fld| {
|
||||
if !no_prelude(item.attrs) {
|
||||
// only recur if there wasn't `#[no_implicit_prelude];`
|
||||
// on this item, i.e. this means that the prelude is not
|
||||
// implicitly imported though the whole subtree
|
||||
fold::noop_fold_item(item, fld)
|
||||
} else {
|
||||
Some(item)
|
||||
}
|
||||
},
|
||||
fold_mod: |module, fld| {
|
||||
let n2 = ast::DUMMY_NODE_ID;
|
||||
let vis = vec::append(~[vi2], module.view_items);
|
||||
|
||||
let prelude_path = ast::Path {
|
||||
span: dummy_sp(),
|
||||
global: false,
|
||||
segments: ~[
|
||||
ast::PathSegment {
|
||||
identifier: sess.ident_of("std"),
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
ast::PathSegment {
|
||||
identifier: sess.ident_of("prelude"),
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
],
|
||||
};
|
||||
// FIXME #2543: Bad copy.
|
||||
let new_module = ast::_mod {
|
||||
view_items: vis,
|
||||
..(*module).clone()
|
||||
};
|
||||
fold::noop_fold_mod(&new_module, self)
|
||||
}
|
||||
}
|
||||
|
||||
let vp = @spanned(ast::view_path_glob(prelude_path, n2));
|
||||
let vi2 = ast::view_item { node: ast::view_item_use(~[vp]),
|
||||
attrs: ~[],
|
||||
vis: ast::private,
|
||||
span: dummy_sp() };
|
||||
|
||||
let vis = vec::append(~[vi2], module.view_items);
|
||||
|
||||
// FIXME #2543: Bad copy.
|
||||
let new_module = ast::_mod {
|
||||
view_items: vis,
|
||||
..(*module).clone()
|
||||
};
|
||||
fold::noop_fold_mod(&new_module, fld)
|
||||
},
|
||||
..*fold::default_ast_fold()
|
||||
fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
||||
let fold = StandardLibraryInjector {
|
||||
sess: sess,
|
||||
};
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use syntax::attr;
|
||||
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan};
|
||||
use syntax::codemap;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::fold;
|
||||
use syntax::opt_vec;
|
||||
use syntax::print::pprust;
|
||||
@ -61,9 +62,89 @@ pub fn modify_for_testing(sess: session::Session,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_test_harness(sess: session::Session,
|
||||
crate: @ast::Crate)
|
||||
-> @ast::Crate {
|
||||
struct TestHarnessGenerator {
|
||||
cx: @mut TestCtxt,
|
||||
}
|
||||
|
||||
impl fold::ast_fold for TestHarnessGenerator {
|
||||
fn fold_crate(&self, c: &ast::Crate) -> ast::Crate {
|
||||
let folded = fold::noop_fold_crate(c, self);
|
||||
|
||||
// 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);
|
||||
// debug!("have %u test/bench functions",
|
||||
// cx.testfns.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let res = fold::noop_fold_item(i, self);
|
||||
self.cx.path.pop();
|
||||
return res;
|
||||
}
|
||||
|
||||
fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
|
||||
// Remove any #[main] from the AST so it doesn't clash with
|
||||
// the one we're going to add. Only if compiling an executable.
|
||||
|
||||
fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
|
||||
if !*cx.sess.building_library {
|
||||
@ast::item {
|
||||
attrs: do item.attrs.iter().filter_map |attr| {
|
||||
if "main" != attr.name() {
|
||||
Some(*attr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}.collect(),
|
||||
.. (*item).clone()
|
||||
}
|
||||
} else {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
let mod_nomain = ast::_mod {
|
||||
view_items: m.view_items.clone(),
|
||||
items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
|
||||
};
|
||||
|
||||
fold::noop_fold_mod(&mod_nomain, self)
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_test_harness(sess: session::Session, crate: @ast::Crate)
|
||||
-> @ast::Crate {
|
||||
let cx: @mut TestCtxt = @mut TestCtxt {
|
||||
sess: sess,
|
||||
crate: crate,
|
||||
@ -81,12 +162,9 @@ fn generate_test_harness(sess: session::Session,
|
||||
}
|
||||
});
|
||||
|
||||
let precursor = @fold::AstFoldFns {
|
||||
fold_crate: |a,b| fold_crate(cx, a, b),
|
||||
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 fold = TestHarnessGenerator {
|
||||
cx: cx
|
||||
};
|
||||
let res = @fold.fold_crate(&*crate);
|
||||
ext_cx.bt_pop();
|
||||
return res;
|
||||
@ -101,85 +179,6 @@ fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_mod(cx: @mut TestCtxt,
|
||||
m: &ast::_mod,
|
||||
fld: @fold::ast_fold)
|
||||
-> ast::_mod {
|
||||
// Remove any #[main] from the AST so it doesn't clash with
|
||||
// the one we're going to add. Only if compiling an executable.
|
||||
|
||||
fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
|
||||
if !*cx.sess.building_library {
|
||||
@ast::item {
|
||||
attrs: do item.attrs.iter().filter_map |attr| {
|
||||
if "main" != attr.name() {
|
||||
Some(*attr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}.collect(),
|
||||
.. (*item).clone()
|
||||
}
|
||||
} else {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
let mod_nomain = ast::_mod {
|
||||
view_items: m.view_items.clone(),
|
||||
items: m.items.iter().map(|i| nomain(cx, *i)).collect(),
|
||||
};
|
||||
|
||||
fold::noop_fold_mod(&mod_nomain, fld)
|
||||
}
|
||||
|
||||
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 fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold)
|
||||
-> Option<@ast::item> {
|
||||
cx.path.push(i.ident);
|
||||
debug!("current path: %s",
|
||||
ast_util::path_name_i(cx.path.clone()));
|
||||
|
||||
if is_test_fn(cx, i) || is_bench_fn(i) {
|
||||
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);
|
||||
cx.path.pop();
|
||||
return res;
|
||||
}
|
||||
|
||||
fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
|
||||
let has_test_attr = attr::contains_name(i.attrs, "test");
|
||||
|
||||
|
@ -287,26 +287,24 @@ fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) {
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
// Produces a simplified copy of the AST which does not include things
|
||||
// that we do not need to or do not want to export. For example, we
|
||||
// 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 {
|
||||
fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
|
||||
struct NestedItemsDropper {
|
||||
contents: (),
|
||||
}
|
||||
|
||||
impl fold::ast_fold for NestedItemsDropper {
|
||||
fn fold_block(&self, blk: &ast::Block) -> ast::Block {
|
||||
let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
|
||||
match stmt.node {
|
||||
ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
|
||||
ast::StmtDecl(@codemap::Spanned { node: ast::DeclLocal(_), span: _}, _)
|
||||
=> Some(*stmt),
|
||||
ast::StmtDecl(@codemap::Spanned { node: ast::DeclItem(_), span: _}, _)
|
||||
=> None,
|
||||
ast::StmtMac(*) => fail!("unexpanded macro in astencode")
|
||||
ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
|
||||
ast::StmtDecl(@codemap::Spanned {
|
||||
node: ast::DeclLocal(_),
|
||||
span: _
|
||||
}, _) => Some(*stmt),
|
||||
ast::StmtDecl(@codemap::Spanned {
|
||||
node: ast::DeclItem(_),
|
||||
span: _
|
||||
}, _) => None,
|
||||
ast::StmtMac(*) => fail!("unexpanded macro in astencode")
|
||||
}
|
||||
}.collect();
|
||||
let blk_sans_items = ast::Block {
|
||||
@ -318,13 +316,24 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
|
||||
rules: blk.rules,
|
||||
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 {
|
||||
fold_block: drop_nested_items,
|
||||
.. *fold::default_ast_fold()
|
||||
});
|
||||
// Produces a simplified copy of the AST which does not include things
|
||||
// that we do not need to or do not want to export. For example, we
|
||||
// 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 {
|
||||
//hack: we're not dropping items
|
||||
@ -341,14 +350,24 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
|
||||
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)
|
||||
-> ast::inlined_item {
|
||||
let fld = fold::make_fold(@fold::AstFoldFns{
|
||||
new_id: |a| xcx.tr_id(a),
|
||||
new_span: |a| xcx.tr_span(a),
|
||||
.. *fold::default_ast_fold()
|
||||
});
|
||||
|
||||
let fld = AstRenumberer {
|
||||
xcx: xcx,
|
||||
};
|
||||
match ii {
|
||||
ast::ii_item(i) => ast::ii_item(fld.fold_item(i).unwrap()),
|
||||
ast::ii_method(d, is_provided, m) =>
|
||||
|
@ -18,6 +18,8 @@ use syntax::codemap::{dummy_sp, Spanned};
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::{ast, attr, codemap, diagnostic, fold};
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::fold::ast_fold;
|
||||
use rustc::back::link::output_type_exe;
|
||||
use rustc::back::link;
|
||||
use rustc::driver::session::{lib_crate, bin_crate};
|
||||
use context::{in_target, StopBefore, Link, Assemble, BuildContext};
|
||||
@ -70,9 +72,8 @@ struct ReadyCtx {
|
||||
fns: ~[ListenerFn]
|
||||
}
|
||||
|
||||
fn fold_mod(_ctx: @mut ReadyCtx,
|
||||
m: &ast::_mod,
|
||||
fold: @fold::ast_fold) -> ast::_mod {
|
||||
fn fold_mod(_ctx: @mut ReadyCtx, m: &ast::_mod, fold: &CrateSetup)
|
||||
-> ast::_mod {
|
||||
fn strip_main(item: @ast::item) -> @ast::item {
|
||||
@ast::item {
|
||||
attrs: do item.attrs.iter().filter_map |attr| {
|
||||
@ -94,9 +95,8 @@ fn fold_mod(_ctx: @mut ReadyCtx,
|
||||
}, fold)
|
||||
}
|
||||
|
||||
fn fold_item(ctx: @mut ReadyCtx,
|
||||
item: @ast::item,
|
||||
fold: @fold::ast_fold) -> Option<@ast::item> {
|
||||
fn fold_item(ctx: @mut ReadyCtx, item: @ast::item, fold: &CrateSetup)
|
||||
-> Option<@ast::item> {
|
||||
ctx.path.push(item.ident);
|
||||
|
||||
let mut cmds = ~[];
|
||||
@ -134,6 +134,19 @@ fn fold_item(ctx: @mut ReadyCtx,
|
||||
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.
|
||||
pub fn ready_crate(sess: session::Session,
|
||||
crate: @ast::Crate) -> @ast::Crate {
|
||||
@ -144,15 +157,9 @@ pub fn ready_crate(sess: session::Session,
|
||||
path: ~[],
|
||||
fns: ~[]
|
||||
};
|
||||
let precursor = @fold::AstFoldFns {
|
||||
// fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)),
|
||||
fold_item: |a, b| fold_item(ctx, a, b),
|
||||
fold_mod: |a, b| fold_mod(ctx, a, b),
|
||||
.. *fold::default_ast_fold()
|
||||
let fold = CrateSetup {
|
||||
ctx: ctx,
|
||||
};
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ use ast::*;
|
||||
use ast;
|
||||
use ast_util;
|
||||
use codemap::{Span, dummy_sp};
|
||||
use fold;
|
||||
use opt_vec;
|
||||
use parse::token;
|
||||
use visit::Visitor;
|
||||
@ -371,21 +370,6 @@ pub fn empty_generics() -> Generics {
|
||||
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
|
||||
|
||||
|
@ -15,6 +15,7 @@ use ast_util;
|
||||
use codemap::{Span, respan, dummy_sp};
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::quote::rt::*;
|
||||
use fold;
|
||||
use opt_vec;
|
||||
use opt_vec::OptVec;
|
||||
|
||||
@ -862,3 +863,32 @@ impl AstBuilder for @ExtCtxt {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
|
||||
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;
|
||||
use ast_util::{mtwt_outer_mark, new_rename, new_mark};
|
||||
@ -21,6 +21,7 @@ use codemap;
|
||||
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
|
||||
use ext::base::*;
|
||||
use fold::*;
|
||||
use opt_vec;
|
||||
use parse;
|
||||
use parse::{parse_item_from_source_str};
|
||||
use parse::token;
|
||||
@ -32,12 +33,10 @@ use std::vec;
|
||||
|
||||
pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
e: &Expr_,
|
||||
span: Span,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
|
||||
-> (Expr_, Span) {
|
||||
match *e {
|
||||
e: @ast::Expr,
|
||||
fld: &MacroExpander)
|
||||
-> @ast::Expr {
|
||||
match e.node {
|
||||
// expr_mac should really be expr_ext or something; it's the
|
||||
// entry-point for all syntax extensions.
|
||||
ExprMac(ref mac) => {
|
||||
@ -66,7 +65,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
||||
}
|
||||
Some(@SE(NormalTT(expandfun, exp_span))) => {
|
||||
cx.bt_push(ExpnInfo {
|
||||
call_site: span,
|
||||
call_site: e.span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr,
|
||||
span: exp_span,
|
||||
@ -101,12 +100,19 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
||||
// mark after:
|
||||
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 =
|
||||
fld.fold_expr(marked_after).node.clone();
|
||||
cx.bt_pop();
|
||||
|
||||
(fully_expanded, span)
|
||||
@ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: fully_expanded,
|
||||
span: e.span,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
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) => {
|
||||
// Expand any interior macros etc.
|
||||
// NB: we don't fold pats yet. Curious.
|
||||
let src_expr = fld.fold_expr(src_expr);
|
||||
let src_loop_block = fld.fold_block(src_loop_block);
|
||||
let src_expr = fld.fold_expr(src_expr).clone();
|
||||
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:
|
||||
//
|
||||
@ -182,10 +228,14 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
||||
~[iter_decl_stmt],
|
||||
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,
|
||||
cx: @ExtCtxt,
|
||||
module_: &ast::_mod,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod)
|
||||
-> ast::_mod {
|
||||
|
||||
fld: &MacroExpander)
|
||||
-> ast::_mod {
|
||||
// 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
|
||||
// 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:
|
||||
@ -256,19 +307,20 @@ static special_block_name : &'static str = " block";
|
||||
pub fn expand_item(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
it: @ast::item,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(@ast::item, @ast_fold) -> Option<@ast::item>)
|
||||
-> Option<@ast::item> {
|
||||
fld: &MacroExpander)
|
||||
-> Option<@ast::item> {
|
||||
match it.node {
|
||||
ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
|
||||
ast::item_mod(_) | ast::item_foreign_mod(_) => {
|
||||
cx.mod_push(it.ident);
|
||||
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();
|
||||
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
|
||||
// logic as for expression-position macro invocations.
|
||||
pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt, it: @ast::item,
|
||||
fld: @ast_fold)
|
||||
-> Option<@ast::item> {
|
||||
cx: @ExtCtxt,
|
||||
it: @ast::item,
|
||||
fld: &MacroExpander)
|
||||
-> Option<@ast::item> {
|
||||
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)
|
||||
}
|
||||
_ => 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
|
||||
pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
s: &Stmt_,
|
||||
sp: Span,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&Stmt_, Span, @ast_fold)
|
||||
-> (Option<Stmt_>, Span))
|
||||
-> (Option<Stmt_>, Span) {
|
||||
s: &Stmt,
|
||||
fld: &MacroExpander)
|
||||
-> Option<@Stmt> {
|
||||
// why the copying here and not in expand_expr?
|
||||
// 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) => {
|
||||
match mac.node {
|
||||
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) {
|
||||
cx.span_fatal(
|
||||
pth.span,
|
||||
fmt!("expected macro name without module \
|
||||
separators"));
|
||||
cx.span_fatal(pth.span,
|
||||
"expected macro name without module separators");
|
||||
}
|
||||
let extname = &pth.segments[0].identifier;
|
||||
let extnamestr = ident_to_str(extname);
|
||||
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
|
||||
None =>
|
||||
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr)),
|
||||
let fully_expanded: @ast::Stmt = match (*extsbox).find(&extname.name) {
|
||||
None => {
|
||||
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr))
|
||||
}
|
||||
|
||||
Some(@SE(NormalTT(expandfun, exp_span))) => {
|
||||
cx.bt_push(ExpnInfo {
|
||||
call_site: sp,
|
||||
callee: NameAndSpan { name: extnamestr, span: exp_span }
|
||||
call_site: s.span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr,
|
||||
span: exp_span,
|
||||
}
|
||||
});
|
||||
let fm = fresh_mark();
|
||||
// mark before expansion:
|
||||
@ -426,11 +481,16 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
||||
// not the current mac.span.
|
||||
let mac_span = original_span(cx);
|
||||
|
||||
let expanded = match expandfun(cx, mac_span.call_site,
|
||||
marked_tts, marked_ctxt) {
|
||||
MRExpr(e) =>
|
||||
@codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
|
||||
span: e.span},
|
||||
let expanded = match expandfun(cx,
|
||||
mac_span.call_site,
|
||||
marked_tts,
|
||||
marked_ctxt) {
|
||||
MRExpr(e) => {
|
||||
@codemap::Spanned {
|
||||
node: StmtExpr(e, ast::DUMMY_NODE_ID),
|
||||
span: e.span,
|
||||
}
|
||||
}
|
||||
MRAny(_,_,stmt_mkr) => stmt_mkr(),
|
||||
_ => cx.span_fatal(
|
||||
pth.span,
|
||||
@ -438,12 +498,15 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
||||
};
|
||||
let marked_after = mark_stmt(expanded,fm);
|
||||
|
||||
//keep going, outside-in
|
||||
// Keep going, outside-in.
|
||||
let fully_expanded = match fld.fold_stmt(marked_after) {
|
||||
Some(stmt) => {
|
||||
let fully_expanded = &stmt.node;
|
||||
cx.bt_pop();
|
||||
(*fully_expanded).clone()
|
||||
@Spanned {
|
||||
span: stmt.span,
|
||||
node: (*fully_expanded).clone(),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
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 {
|
||||
StmtExpr(e, stmt_id) if semi => Some(StmtSemi(e, stmt_id)),
|
||||
_ => { Some(fully_expanded) } /* might already have a semi */
|
||||
}, sp)
|
||||
|
||||
match fully_expanded.node {
|
||||
StmtExpr(e, stmt_id) if semi => {
|
||||
Some(@Spanned {
|
||||
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_stmt, above.
|
||||
fn expand_non_macro_stmt (exts: SyntaxEnv,
|
||||
s: &Stmt_,
|
||||
sp: Span,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span))
|
||||
-> (Option<Stmt_>,Span) {
|
||||
fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
|
||||
-> Option<@Stmt> {
|
||||
// is it a let?
|
||||
match *s {
|
||||
StmtDecl(@Spanned{node: DeclLocal(ref local), span: stmt_span}, node_id) => {
|
||||
match s.node {
|
||||
StmtDecl(@Spanned {
|
||||
node: DeclLocal(ref local),
|
||||
span: stmt_span
|
||||
},
|
||||
node_id) => {
|
||||
let block_info = get_block_info(exts);
|
||||
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:
|
||||
let new_init_opt = init.map(|e| fld.fold_expr(*e));
|
||||
let rewritten_local =
|
||||
@Local{is_mutbl:is_mutbl,
|
||||
ty:ty,
|
||||
pat:rewritten_pat,
|
||||
init:new_init_opt,
|
||||
id:id,
|
||||
span:span};
|
||||
(Some(StmtDecl(@Spanned{node:DeclLocal(rewritten_local),
|
||||
span: stmt_span},node_id)),
|
||||
sp)
|
||||
@Local {
|
||||
is_mutbl: is_mutbl,
|
||||
ty: ty,
|
||||
pat: rewritten_pat,
|
||||
init: new_init_opt,
|
||||
id: id,
|
||||
span: span,
|
||||
};
|
||||
Some(@Spanned {
|
||||
node: StmtDecl(@Spanned {
|
||||
node: DeclLocal(rewritten_local),
|
||||
span: stmt_span
|
||||
},
|
||||
node_id),
|
||||
span: span
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
orig(s, sp, fld)
|
||||
}
|
||||
_ => noop_fold_stmt(s, fld),
|
||||
}
|
||||
}
|
||||
|
||||
@ -628,18 +700,18 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
|
||||
|
||||
// expand a block. pushes a new exts_frame, then calls expand_block_elts
|
||||
pub fn expand_block(extsbox: @mut SyntaxEnv,
|
||||
_cx: @ExtCtxt,
|
||||
_: @ExtCtxt,
|
||||
blk: &Block,
|
||||
fld: @ast_fold,
|
||||
_orig: @fn(&Block, @ast_fold) -> Block)
|
||||
-> Block {
|
||||
fld: &MacroExpander)
|
||||
-> Block {
|
||||
// see note below about treatment of exts table
|
||||
with_exts_frame!(extsbox,false,
|
||||
expand_block_elts(*extsbox, blk, fld))
|
||||
}
|
||||
|
||||
// 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 pending_renames = block_info.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 {
|
||||
/* 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
|
||||
@ -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
|
||||
// program (ick). This should run before cfg stripping.
|
||||
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>",
|
||||
std_macros(),
|
||||
cfg.clone(),
|
||||
@ -1038,48 +1166,80 @@ pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
|
||||
None => fail!("expected core macros to parse correctly")
|
||||
};
|
||||
|
||||
let injecter = @AstFoldFns {
|
||||
fold_mod: |modd, _| {
|
||||
// just inject the std macros at the start of the first
|
||||
// module in the crate (i.e the crate file itself.)
|
||||
let items = vec::append(~[sm], modd.items);
|
||||
ast::_mod {
|
||||
items: items,
|
||||
// FIXME #2543: Bad copy.
|
||||
.. (*modd).clone()
|
||||
}
|
||||
},
|
||||
.. *default_ast_fold()
|
||||
};
|
||||
@make_fold(injecter).fold_crate(c)
|
||||
let injector = @Injector {
|
||||
sm: sm,
|
||||
} as @ast_fold;
|
||||
@injector.fold_crate(c)
|
||||
}
|
||||
|
||||
struct NoOpFolder {
|
||||
contents: (),
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// visitor can swap out one exts table for another for the duration
|
||||
// of the block. The cleaner alternative would be to thread the
|
||||
// exts table through the fold, but that would require updating
|
||||
// every method/element of AstFoldFns in fold.rs.
|
||||
let extsbox = @mut syntax_expander_table();
|
||||
let afp = default_ast_fold();
|
||||
let extsbox = syntax_expander_table();
|
||||
let cx = ExtCtxt::new(parse_sess, cfg.clone());
|
||||
let f_pre = @AstFoldFns {
|
||||
fold_expr: |expr,span,recur|
|
||||
expand_expr(extsbox, cx, expr, span, recur, afp.fold_expr),
|
||||
fold_mod: |modd,recur|
|
||||
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 expander = @MacroExpander {
|
||||
extsbox: @mut extsbox,
|
||||
cx: cx,
|
||||
} as @ast_fold;
|
||||
|
||||
let ret = @f.fold_crate(c);
|
||||
let ret = @expander.fold_crate(c);
|
||||
parse_sess.span_diagnostic.handler().abort_if_errors();
|
||||
return ret;
|
||||
}
|
||||
@ -1145,53 +1305,56 @@ impl CtxtFn for Repainter {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
pub struct ContextWrapper {
|
||||
context_function: @CtxtFn,
|
||||
}
|
||||
|
||||
};
|
||||
@AstFoldFns{
|
||||
fold_ident : fi,
|
||||
fold_mac : fm,
|
||||
.. *afp
|
||||
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))
|
||||
}
|
||||
};
|
||||
Spanned {
|
||||
node: macro,
|
||||
span: m.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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})
|
||||
// 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) -> @ContextWrapper {
|
||||
@ContextWrapper {
|
||||
context_function: cf as @CtxtFn,
|
||||
}
|
||||
}
|
||||
|
||||
// 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})
|
||||
}
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
// 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] {
|
||||
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.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,8 @@
|
||||
// xfail-test
|
||||
|
||||
// xfail'd because the lint pass doesn't know to ignore standard library
|
||||
// stuff.
|
||||
|
||||
// -*- rust -*-
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
|
@ -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
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
Loading…
x
Reference in New Issue
Block a user