From 3e5de06135fa9a857931191101d61a4abe149c96 Mon Sep 17 00:00:00 2001 From: Patrick Walton <pcwalton@mimiga.net> Date: Thu, 29 Aug 2013 12:10:02 -0700 Subject: [PATCH] librustc: Change fold to use traits instead of `@fn`. --- src/librustc/front/assign_node_ids.rs | 17 +- src/librustc/front/config.rs | 62 +- src/librustc/front/std_inject.rs | 169 +-- src/librustc/front/test.rs | 175 ++- src/librustc/middle/astencode.rs | 77 +- src/librustpkg/util.rs | 35 +- src/libsyntax/ast_util.rs | 16 - src/libsyntax/ext/build.rs | 30 + src/libsyntax/ext/expand.rs | 463 ++++--- src/libsyntax/fold.rs | 1540 +++++++++++------------- src/test/compile-fail/dead-code-ret.rs | 5 + src/test/compile-fail/issue-897-2.rs | 4 + 12 files changed, 1335 insertions(+), 1258 deletions(-) diff --git a/src/librustc/front/assign_node_ids.rs b/src/librustc/front/assign_node_ids.rs index 446db5c35e9..fc1b034de97 100644 --- a/src/librustc/front/assign_node_ids.rs +++ b/src/librustc/front/assign_node_ids.rs @@ -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) } diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 2c0068729a7..fc1794fb935 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -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(); diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 79e554090f3..ab407806bcc 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -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) } diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index f0d7f6c892b..d2baee6c961 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -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"); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index bcc333afeec..6521b4bb3cc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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) => diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 906bed2f234..02524b65020 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -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) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index f0f86911f50..2e47050ad6a 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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 diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 889c2a5976e..aa4238ae908 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -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) + } +} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 82d452bc734..0aefbe31338 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 5472c61a155..18ddee34171 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -14,227 +14,434 @@ use codemap::{Span, Spanned}; use parse::token; use opt_vec::OptVec; -// this file defines an ast_fold trait for objects that can perform -// a "fold" on Rust ASTs. It also contains a structure that implements -// that trait, and a "default_fold" whose fields contain closures -// that perform "default traversals", visiting all of the sub-elements -// and re-assembling the result. The "fun_to_ident_folder" in the -// test module provides a simple example of creating a very simple -// fold that only looks at identifiers. - +// We may eventually want to be able to fold over type parameters, too. pub trait ast_fold { - fn fold_crate(@self, &Crate) -> Crate; - fn fold_view_item(@self, &view_item) -> view_item; - fn fold_foreign_item(@self, @foreign_item) -> @foreign_item; - fn fold_item(@self, @item) -> Option<@item>; - fn fold_struct_field(@self, @struct_field) -> @struct_field; - fn fold_item_underscore(@self, &item_) -> item_; - fn fold_type_method(@self, m: &TypeMethod) -> TypeMethod; - fn fold_method(@self, @method) -> @method; - fn fold_block(@self, &Block) -> Block; - fn fold_stmt(@self, &Stmt) -> Option<@Stmt>; - fn fold_arm(@self, &Arm) -> Arm; - fn fold_pat(@self, @Pat) -> @Pat; - fn fold_decl(@self, @Decl) -> Option<@Decl>; - fn fold_expr(@self, @Expr) -> @Expr; - fn fold_ty(@self, &Ty) -> Ty; - fn fold_mod(@self, &_mod) -> _mod; - fn fold_foreign_mod(@self, &foreign_mod) -> foreign_mod; - fn fold_variant(@self, &variant) -> variant; - fn fold_ident(@self, Ident) -> Ident; - fn fold_path(@self, &Path) -> Path; - fn fold_local(@self, @Local) -> @Local; - fn fold_mac(@self, &mac) -> mac; - fn map_exprs(@self, @fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr]; - fn new_id(@self, NodeId) -> NodeId; - fn new_span(@self, Span) -> Span; + fn fold_crate(&self, c: &Crate) -> Crate { + noop_fold_crate(c, self) + } - // New style, using default methods: + fn fold_meta_items(&self, meta_items: &[@MetaItem]) -> ~[@MetaItem] { + meta_items.map(|x| fold_meta_item_(*x, self)) + } - fn fold_variant_arg(@self, va: &variant_arg) -> variant_arg { - variant_arg { - ty: self.fold_ty(&va.ty), - id: self.new_id(va.id) + fn fold_view_paths(&self, view_paths: &[@view_path]) -> ~[@view_path] { + view_paths.map(|view_path| { + let inner_view_path = match view_path.node { + view_path_simple(ref ident, ref path, node_id) => { + view_path_simple(ident.clone(), + self.fold_path(path), + self.new_id(node_id)) + } + view_path_glob(ref path, node_id) => { + view_path_glob(self.fold_path(path), self.new_id(node_id)) + } + view_path_list(ref path, ref path_list_idents, node_id) => { + view_path_list(self.fold_path(path), + path_list_idents.map(|path_list_ident| { + let id = self.new_id(path_list_ident.node + .id); + Spanned { + node: path_list_ident_ { + name: path_list_ident.node + .name + .clone(), + id: id, + }, + span: self.new_span( + path_list_ident.span) + } + }), + self.new_id(node_id)) + } + }; + @Spanned { + node: inner_view_path, + span: self.new_span(view_path.span), + } + }) + } + + fn fold_view_item(&self, vi: &view_item) -> view_item { + let inner_view_item = match vi.node { + view_item_extern_mod(ref ident, + string, + ref meta_items, + node_id) => { + view_item_extern_mod(ident.clone(), + string, + self.fold_meta_items(*meta_items), + self.new_id(node_id)) + } + view_item_use(ref view_paths) => { + view_item_use(self.fold_view_paths(*view_paths)) + } + }; + view_item { + node: inner_view_item, + attrs: vi.attrs.map(|a| fold_attribute_(*a, self)), + vis: vi.vis, + span: self.new_span(vi.span), } } - fn fold_spanned<T>(@self, s: &Spanned<T>, f: &fn(&T) -> T) -> Spanned<T> { + fn fold_foreign_item(&self, ni: @foreign_item) -> @foreign_item { + let fold_attribute = |x| fold_attribute_(x, self); + + @ast::foreign_item { + ident: self.fold_ident(ni.ident), + attrs: ni.attrs.map(|x| fold_attribute(*x)), + node: + match ni.node { + foreign_item_fn(ref fdec, ref generics) => { + foreign_item_fn( + ast::fn_decl { + inputs: fdec.inputs.map(|a| fold_arg_(a, + self)), + output: self.fold_ty(&fdec.output), + cf: fdec.cf, + }, + fold_generics(generics, self)) + } + foreign_item_static(ref t, m) => { + foreign_item_static(self.fold_ty(t), m) + } + }, + id: self.new_id(ni.id), + span: self.new_span(ni.span), + vis: ni.vis, + } + } + + fn fold_item(&self, i: @item) -> Option<@item> { + noop_fold_item(i, self) + } + + fn fold_struct_field(&self, sf: @struct_field) -> @struct_field { + let fold_attribute = |x| fold_attribute_(x, self); + + @Spanned { + node: ast::struct_field_ { + kind: sf.node.kind, + id: self.new_id(sf.node.id), + ty: self.fold_ty(&sf.node.ty), + attrs: sf.node.attrs.map(|e| fold_attribute(*e)) + }, + span: self.new_span(sf.span) + } + } + + fn fold_item_underscore(&self, i: &item_) -> item_ { + noop_fold_item_underscore(i, self) + } + + fn fold_type_method(&self, m: &TypeMethod) -> TypeMethod { + noop_fold_type_method(m, self) + } + + fn fold_method(&self, m: @method) -> @method { + @ast::method { + ident: self.fold_ident(m.ident), + attrs: m.attrs.map(|a| fold_attribute_(*a, self)), + generics: fold_generics(&m.generics, self), + explicit_self: m.explicit_self, + purity: m.purity, + decl: fold_fn_decl(&m.decl, self), + body: self.fold_block(&m.body), + id: self.new_id(m.id), + span: self.new_span(m.span), + self_id: self.new_id(m.self_id), + vis: m.vis, + } + } + + fn fold_block(&self, b: &Block) -> Block { + noop_fold_block(b, self) + } + + fn fold_stmt(&self, s: &Stmt) -> Option<@Stmt> { + noop_fold_stmt(s, self) + } + + fn fold_arm(&self, a: &Arm) -> Arm { + Arm { + pats: a.pats.map(|x| self.fold_pat(*x)), + guard: a.guard.map_move(|x| self.fold_expr(x)), + body: self.fold_block(&a.body), + } + } + + fn fold_pat(&self, p: @Pat) -> @Pat { + let node = match p.node { + PatWild => PatWild, + PatIdent(binding_mode, ref pth, ref sub) => { + PatIdent(binding_mode, + self.fold_path(pth), + sub.map_move(|x| self.fold_pat(x))) + } + PatLit(e) => PatLit(self.fold_expr(e)), + PatEnum(ref pth, ref pats) => { + PatEnum(self.fold_path(pth), + pats.map(|pats| pats.map(|x| self.fold_pat(*x)))) + } + PatStruct(ref pth, ref fields, etc) => { + let pth_ = self.fold_path(pth); + let fs = do fields.map |f| { + ast::FieldPat { + ident: f.ident, + pat: self.fold_pat(f.pat) + } + }; + PatStruct(pth_, fs, etc) + } + PatTup(ref elts) => PatTup(elts.map(|x| self.fold_pat(*x))), + PatBox(inner) => PatBox(self.fold_pat(inner)), + PatUniq(inner) => PatUniq(self.fold_pat(inner)), + PatRegion(inner) => PatRegion(self.fold_pat(inner)), + PatRange(e1, e2) => { + PatRange(self.fold_expr(e1), self.fold_expr(e2)) + }, + PatVec(ref before, ref slice, ref after) => { + PatVec(before.map(|x| self.fold_pat(*x)), + slice.map_move(|x| self.fold_pat(x)), + after.map(|x| self.fold_pat(*x))) + } + }; + + @Pat { + id: self.new_id(p.id), + span: self.new_span(p.span), + node: node, + } + } + + fn fold_decl(&self, d: @Decl) -> Option<@Decl> { + let node = match d.node { + DeclLocal(ref l) => Some(DeclLocal(self.fold_local(*l))), + DeclItem(it) => { + match self.fold_item(it) { + Some(it_folded) => Some(DeclItem(it_folded)), + None => None, + } + } + }; + + node.map_move(|node| { + @Spanned { + node: node, + span: d.span, + } + }) + } + + fn fold_expr(&self, e: @Expr) -> @Expr { + noop_fold_expr(e, self) + } + + fn fold_ty(&self, t: &Ty) -> Ty { + let node = match t.node { + ty_nil | ty_bot | ty_infer => t.node.clone(), + ty_box(ref mt) => ty_box(fold_mt(mt, self)), + ty_uniq(ref mt) => ty_uniq(fold_mt(mt, self)), + ty_vec(ref mt) => ty_vec(fold_mt(mt, self)), + ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)), + ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, self)), + ty_closure(ref f) => { + ty_closure(@TyClosure { + sigil: f.sigil, + purity: f.purity, + region: f.region, + onceness: f.onceness, + bounds: fold_opt_bounds(&f.bounds, self), + decl: fold_fn_decl(&f.decl, self), + lifetimes: f.lifetimes.map(|l| fold_lifetime(l, self)), + }) + } + ty_bare_fn(ref f) => { + ty_bare_fn(@TyBareFn { + lifetimes: f.lifetimes.map(|l| fold_lifetime(l, self)), + purity: f.purity, + abis: f.abis, + decl: fold_fn_decl(&f.decl, self) + }) + } + ty_tup(ref tys) => ty_tup(tys.map(|ty| self.fold_ty(ty))), + ty_path(ref path, ref bounds, id) => { + ty_path(self.fold_path(path), + fold_opt_bounds(bounds, self), + self.new_id(id)) + } + ty_fixed_length_vec(ref mt, e) => { + ty_fixed_length_vec(fold_mt(mt, self), self.fold_expr(e)) + } + ty_mac(ref mac) => ty_mac(self.fold_mac(mac)), + ty_typeof(expr) => ty_typeof(self.fold_expr(expr)), + }; + Ty { + id: self.new_id(t.id), + span: self.new_span(t.span), + node: node, + } + } + + fn fold_mod(&self, m: &_mod) -> _mod { + noop_fold_mod(m, self) + } + + fn fold_foreign_mod(&self, nm: &foreign_mod) -> foreign_mod { + ast::foreign_mod { + sort: nm.sort, + abis: nm.abis, + view_items: nm.view_items + .iter() + .map(|x| self.fold_view_item(x)) + .collect(), + items: nm.items + .iter() + .map(|x| self.fold_foreign_item(*x)) + .collect(), + } + } + + fn fold_variant(&self, v: &variant) -> variant { + let kind; + match v.node.kind { + tuple_variant_kind(ref variant_args) => { + kind = tuple_variant_kind(variant_args.map(|x| + fold_variant_arg_(x, self))) + } + struct_variant_kind(ref struct_def) => { + kind = struct_variant_kind(@ast::struct_def { + fields: struct_def.fields.iter() + .map(|f| self.fold_struct_field(*f)).collect(), + ctor_id: struct_def.ctor_id.map(|c| self.new_id(*c)) + }) + } + } + + let fold_attribute = |x| fold_attribute_(x, self); + let attrs = v.node.attrs.map(|x| fold_attribute(*x)); + + let de = match v.node.disr_expr { + Some(e) => Some(self.fold_expr(e)), + None => None + }; + let node = ast::variant_ { + name: v.node.name, + attrs: attrs, + kind: kind, + id: self.new_id(v.node.id), + disr_expr: de, + vis: v.node.vis, + }; Spanned { - node: f(&s.node), - span: self.new_span(s.span) + node: node, + span: self.new_span(v.span), } } - fn fold_view_path(@self, vp: &view_path) -> view_path { - self.fold_spanned(vp, |v| self.fold_view_path_(v)) + fn fold_ident(&self, i: Ident) -> Ident { + i } - fn fold_view_paths(@self, vps: &[@view_path]) -> ~[@view_path] { - vps.map(|vp| @self.fold_view_path(*vp)) - } - - fn fold_view_path_(@self, vp: &view_path_) -> view_path_ { - match *vp { - view_path_simple(ident, ref path, node_id) => { - view_path_simple(self.fold_ident(ident), - self.fold_path(path), - self.new_id(node_id)) - } - view_path_glob(ref path, node_id) => { - view_path_glob(self.fold_path(path), - self.new_id(node_id)) - } - view_path_list(ref path, ref idents, node_id) => { - view_path_list(self.fold_path(path), - self.fold_path_list_idents(*idents), - self.new_id(node_id)) - } + fn fold_path(&self, p: &Path) -> Path { + ast::Path { + span: self.new_span(p.span), + global: p.global, + segments: p.segments.map(|segment| ast::PathSegment { + identifier: self.fold_ident(segment.identifier), + lifetime: segment.lifetime, + types: segment.types.map(|typ| self.fold_ty(typ)), + }) } } - fn fold_path_list_idents(@self, idents: &[path_list_ident]) -> ~[path_list_ident] { - idents.map(|i| self.fold_path_list_ident(i)) - } - - fn fold_path_list_ident(@self, ident: &path_list_ident) -> path_list_ident { - self.fold_spanned(ident, |i| self.fold_path_list_ident_(i)) - } - - fn fold_path_list_ident_(@self, ident: &path_list_ident_) -> path_list_ident_ { - path_list_ident_ { - name: self.fold_ident(ident.name), - id: self.new_id(ident.id) - } - } - - fn fold_arg(@self, a: &arg) -> arg { - arg { - is_mutbl: a.is_mutbl, - ty: self.fold_ty(&a.ty), - pat: self.fold_pat(a.pat), - id: self.new_id(a.id), - } - } - - fn fold_trait_ref(@self, p: &trait_ref) -> trait_ref { - trait_ref { - path: self.fold_path(&p.path), - ref_id: self.new_id(p.ref_id), - } - } - - fn fold_ty_param_bound(@self, tpb: &TyParamBound) -> TyParamBound { - match *tpb { - TraitTyParamBound(ref ty) => { - TraitTyParamBound(self.fold_trait_ref(ty)) - } - RegionTyParamBound => { - RegionTyParamBound - } - } - } - - fn fold_ty_param(@self, tp: &TyParam) -> TyParam { - TyParam { - ident: self.fold_ident(tp.ident), - id: self.new_id(tp.id), - bounds: tp.bounds.map(|x| self.fold_ty_param_bound(x)) - } - } - - fn fold_ty_params(@self, tps: &OptVec<TyParam>) -> OptVec<TyParam> { - tps.map(|tp| self.fold_ty_param(tp)) - } - - fn fold_lifetime(@self, l: &Lifetime) -> Lifetime { - Lifetime { + fn fold_local(&self, l: @Local) -> @Local { + @Local { + is_mutbl: l.is_mutbl, + ty: self.fold_ty(&l.ty), + pat: self.fold_pat(l.pat), + init: l.init.map_move(|e| self.fold_expr(e)), id: self.new_id(l.id), span: self.new_span(l.span), - ident: l.ident, // Folding this ident causes hygiene errors - ndm } } - fn fold_lifetimes(@self, lts: &OptVec<Lifetime>) -> OptVec<Lifetime> { - lts.map(|l| self.fold_lifetime(l)) - } - - - fn fold_meta_item(@self, mi: &MetaItem) -> @MetaItem { - @self.fold_spanned(mi, |n| match *n { - MetaWord(id) => { - MetaWord(id) - } - MetaList(id, ref mis) => { - MetaList(id, self.fold_meta_items(*mis)) - } - MetaNameValue(id, s) => { - MetaNameValue(id, s) - } - }) - } - - fn fold_meta_items(@self, mis: &[@MetaItem]) -> ~[@MetaItem] { - mis.map(|&mi| self.fold_meta_item(mi)) - } - - fn fold_attribute(@self, at: &Attribute) -> Attribute { + fn fold_mac(&self, macro: &mac) -> mac { Spanned { - span: self.new_span(at.span), - node: Attribute_ { - style: at.node.style, - value: self.fold_meta_item(at.node.value), - is_sugared_doc: at.node.is_sugared_doc - } + node: match macro.node { + mac_invoc_tt(ref p, ref tts, ctxt) => { + mac_invoc_tt(self.fold_path(p), + fold_tts(*tts, self), + ctxt) + } + }, + span: self.new_span(macro.span) } } - fn fold_attributes(@self, attrs: &[Attribute]) -> ~[Attribute] { - attrs.map(|x| self.fold_attribute(x)) + fn map_exprs(&self, f: &fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] { + es.map(|x| f(*x)) + } + + fn new_id(&self, i: NodeId) -> NodeId { + i + } + + fn new_span(&self, sp: Span) -> Span { + sp } } -// We may eventually want to be able to fold over type parameters, too - -pub struct AstFoldFns { - //unlike the others, item_ is non-trivial - fold_crate: @fn(&Crate, @ast_fold) -> Crate, - fold_view_item: @fn(&view_item_, @ast_fold) -> view_item_, - fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item, - fold_item: @fn(@item, @ast_fold) -> Option<@item>, - fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field, - fold_item_underscore: @fn(&item_, @ast_fold) -> item_, - fold_type_method: @fn(&TypeMethod, @ast_fold) -> TypeMethod, - fold_method: @fn(@method, @ast_fold) -> @method, - fold_block: @fn(&Block, @ast_fold) -> Block, - fold_stmt: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span), - fold_arm: @fn(&Arm, @ast_fold) -> Arm, - fold_pat: @fn(&Pat_, Span, @ast_fold) -> (Pat_, Span), - fold_decl: @fn(&Decl_, Span, @ast_fold) -> (Option<Decl_>, Span), - fold_expr: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span), - fold_ty: @fn(&ty_, Span, @ast_fold) -> (ty_, Span), - fold_mod: @fn(&_mod, @ast_fold) -> _mod, - fold_foreign_mod: @fn(&foreign_mod, @ast_fold) -> foreign_mod, - fold_variant: @fn(&variant_, Span, @ast_fold) -> (variant_, Span), - fold_ident: @fn(Ident, @ast_fold) -> Ident, - fold_path: @fn(&Path, @ast_fold) -> Path, - fold_local: @fn(@Local, @ast_fold) -> @Local, - fold_mac: @fn(&mac_, Span, @ast_fold) -> (mac_, Span), - map_exprs: @fn(@fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr], - new_id: @fn(NodeId) -> NodeId, - new_span: @fn(Span) -> Span -} - -pub type ast_fold_fns = @AstFoldFns; - /* some little folds that probably aren't useful to have in ast_fold itself*/ -pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] { +//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive +fn fold_meta_item_<T:ast_fold>(mi: @MetaItem, fld: &T) -> @MetaItem { + @Spanned { + node: + match mi.node { + MetaWord(id) => MetaWord(id), + MetaList(id, ref mis) => { + let fold_meta_item = |x| fold_meta_item_(x, fld); + MetaList( + id, + mis.map(|e| fold_meta_item(*e)) + ) + } + MetaNameValue(id, s) => MetaNameValue(id, s) + }, + span: fld.new_span(mi.span) } +} + +//used in noop_fold_item and noop_fold_crate +fn fold_attribute_<T:ast_fold>(at: Attribute, fld: &T) -> Attribute { + Spanned { + span: fld.new_span(at.span), + node: ast::Attribute_ { + style: at.node.style, + value: fold_meta_item_(at.node.value, fld), + is_sugared_doc: at.node.is_sugared_doc + } + } +} + +//used in noop_fold_foreign_item and noop_fold_fn_decl +fn fold_arg_<T:ast_fold>(a: &arg, fld: &T) -> arg { + ast::arg { + is_mutbl: a.is_mutbl, + ty: fld.fold_ty(&a.ty), + pat: fld.fold_pat(a.pat), + id: fld.new_id(a.id), + } +} + +// build a new vector of tts by appling the ast_fold's fold_ident to +// all of the identifiers in the token trees. +pub fn fold_tts<T:ast_fold>(tts: &[token_tree], fld: &T) -> ~[token_tree] { do tts.map |tt| { match *tt { tt_tok(span, ref tok) => tt_tok(span,maybe_fold_ident(tok,fld)), - tt_delim(ref tts) => - tt_delim(@mut fold_tts(**tts, fld)), + tt_delim(ref tts) => tt_delim(@mut fold_tts(**tts, fld)), tt_seq(span, ref pattern, ref sep, is_optional) => tt_seq(span, @mut fold_tts(**pattern, fld), @@ -247,33 +454,68 @@ pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] { } // apply ident folder if it's an ident, otherwise leave it alone -fn maybe_fold_ident(t : &token::Token, f: @ast_fold) -> token::Token { +fn maybe_fold_ident<T:ast_fold>(t: &token::Token, fld: &T) -> token::Token { match *t { - token::IDENT(id,followed_by_colons) => - token::IDENT(f.fold_ident(id),followed_by_colons), + token::IDENT(id, followed_by_colons) => { + token::IDENT(fld.fold_ident(id), followed_by_colons) + } _ => (*t).clone() } } -pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl { +pub fn fold_fn_decl<T:ast_fold>(decl: &ast::fn_decl, fld: &T) + -> ast::fn_decl { ast::fn_decl { - inputs: decl.inputs.map(|x| fld.fold_arg(x)), + inputs: decl.inputs.map(|x| fold_arg_(x, fld)), // bad copy output: fld.fold_ty(&decl.output), cf: decl.cf, } } -pub fn fold_generics(generics: &Generics, fld: @ast_fold) -> Generics { - Generics {ty_params: fld.fold_ty_params(&generics.ty_params), - lifetimes: fld.fold_lifetimes(&generics.lifetimes)} +fn fold_ty_param_bound<T:ast_fold>(tpb: &TyParamBound, fld: &T) + -> TyParamBound { + match *tpb { + TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)), + RegionTyParamBound => RegionTyParamBound + } } -pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate { - Crate { - module: fld.fold_mod(&c.module), - attrs: fld.fold_attributes(c.attrs), - config: fld.fold_meta_items(c.config), - span: fld.new_span(c.span), +pub fn fold_ty_param<T:ast_fold>(tp: &TyParam, fld: &T) -> TyParam { + TyParam { + ident: tp.ident, + id: fld.new_id(tp.id), + bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)), + } +} + +pub fn fold_ty_params<T:ast_fold>(tps: &OptVec<TyParam>, fld: &T) + -> OptVec<TyParam> { + tps.map(|tp| fold_ty_param(tp, fld)) +} + +pub fn fold_lifetime<T:ast_fold>(l: &Lifetime, fld: &T) -> Lifetime { + Lifetime { + id: fld.new_id(l.id), + span: fld.new_span(l.span), + ident: l.ident + } +} + +pub fn fold_lifetimes<T:ast_fold>(lts: &OptVec<Lifetime>, fld: &T) + -> OptVec<Lifetime> { + lts.map(|l| fold_lifetime(l, fld)) +} + +pub fn fold_generics<T:ast_fold>(generics: &Generics, fld: &T) -> Generics { + Generics {ty_params: fold_ty_params(&generics.ty_params, fld), + lifetimes: fold_lifetimes(&generics.lifetimes, fld)} +} + +fn fold_struct_def<T:ast_fold>(struct_def: @ast::struct_def, fld: &T) + -> @ast::struct_def { + @ast::struct_def { + fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)), + ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)), } } @@ -291,172 +533,70 @@ fn noop_fold_view_item(vi: &view_item_, fld: @ast_fold) -> view_item_ { } } -fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold) - -> @foreign_item { - @ast::foreign_item { - ident: fld.fold_ident(ni.ident), - attrs: fld.fold_attributes(ni.attrs), - node: - match ni.node { - foreign_item_fn(ref fdec, ref generics) => { - foreign_item_fn( - ast::fn_decl { - inputs: fdec.inputs.map(|a| fld.fold_arg(a)), - output: fld.fold_ty(&fdec.output), - cf: fdec.cf, - }, - fold_generics(generics, fld)) - } - foreign_item_static(ref t, m) => { - foreign_item_static(fld.fold_ty(t), m) - } - }, - id: fld.new_id(ni.id), - span: fld.new_span(ni.span), - vis: ni.vis, +fn fold_trait_ref<T:ast_fold>(p: &trait_ref, fld: &T) -> trait_ref { + ast::trait_ref { + path: fld.fold_path(&p.path), + ref_id: fld.new_id(p.ref_id), } } -pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> { - Some(@ast::item { ident: fld.fold_ident(i.ident), - attrs: fld.fold_attributes(i.attrs), - id: fld.new_id(i.id), - node: fld.fold_item_underscore(&i.node), - vis: i.vis, - span: fld.new_span(i.span) }) -} - -fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold) - -> @struct_field { - @Spanned { - node: ast::struct_field_ { - kind: sf.node.kind, - id: fld.new_id(sf.node.id), - ty: fld.fold_ty(&sf.node.ty), - attrs: fld.fold_attributes(sf.node.attrs), - }, - span: sf.span - } -} - -pub fn noop_fold_type_method(m: &TypeMethod, fld: @ast_fold) -> TypeMethod { - TypeMethod { - ident: fld.fold_ident(m.ident), - attrs: fld.fold_attributes(m.attrs), - purity: m.purity, - decl: fold_fn_decl(&m.decl, fld), - generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, - id: fld.new_id(m.id), - span: fld.new_span(m.span), - } -} - -pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ { - match *i { - item_static(ref t, m, e) => { - item_static(fld.fold_ty(t), m, fld.fold_expr(e)) - } - item_fn(ref decl, purity, abi, ref generics, ref body) => { - item_fn( - fold_fn_decl(decl, fld), - purity, - abi, - fold_generics(generics, fld), - fld.fold_block(body) - ) - } - item_mod(ref m) => { - item_mod(fld.fold_mod(m)) - } - item_foreign_mod(ref nm) => { - item_foreign_mod(fld.fold_foreign_mod(nm)) - } - item_ty(ref t, ref generics) => { - item_ty(fld.fold_ty(t), fold_generics(generics, fld)) - } - item_enum(ref enum_definition, ref generics) => { - item_enum( - ast::enum_def { - variants: do enum_definition.variants.map |x| { - fld.fold_variant(x) - }, - }, - fold_generics(generics, fld)) - } - item_struct(ref struct_def, ref generics) => { - let struct_def = fold_struct_def(*struct_def, fld); - item_struct(struct_def, fold_generics(generics, fld)) - } - item_impl(ref generics, ref ifce, ref ty, ref methods) => { - item_impl( - fold_generics(generics, fld), - ifce.map(|p| fld.fold_trait_ref(p)), - fld.fold_ty(ty), - methods.map(|x| fld.fold_method(*x)) - ) - } - item_trait(ref generics, ref traits, ref methods) => { - let methods = do methods.map |method| { - match *method { - required(ref m) => required(fld.fold_type_method(m)), - provided(method) => provided(fld.fold_method(method)) - } - }; - item_trait( - fold_generics(generics, fld), - traits.map(|p| fld.fold_trait_ref(p)), - methods - ) - } - item_mac(ref m) => { - item_mac(fld.fold_mac(m)) - } - } -} - -fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold) - -> @ast::struct_def { - @ast::struct_def { - fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)), - ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)), - } -} - -fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field { +fn fold_struct_field<T:ast_fold>(f: @struct_field, fld: &T) -> @struct_field { @Spanned { node: ast::struct_field_ { kind: f.node.kind, id: fld.new_id(f.node.id), ty: fld.fold_ty(&f.node.ty), - attrs: fld.fold_attributes(f.node.attrs), + attrs: f.node.attrs.map(|a| fold_attribute_(*a, fld)), }, span: fld.new_span(f.span), } } -fn noop_fold_method(m: @method, fld: @ast_fold) -> @method { - @ast::method { - ident: fld.fold_ident(m.ident), - attrs: fld.fold_attributes(m.attrs), - generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, - purity: m.purity, - decl: fold_fn_decl(&m.decl, fld), - body: fld.fold_block(&m.body), - id: fld.new_id(m.id), - span: fld.new_span(m.span), - self_id: fld.new_id(m.self_id), - vis: m.vis, +fn fold_field_<T:ast_fold>(field: Field, folder: &T) -> Field { + ast::Field { + ident: folder.fold_ident(field.ident), + expr: folder.fold_expr(field.expr), + span: folder.new_span(field.span), } } +fn fold_mt<T:ast_fold>(mt: &mt, folder: &T) -> mt { + mt { + ty: ~folder.fold_ty(mt.ty), + mutbl: mt.mutbl, + } +} -pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block { - let view_items = b.view_items.map(|x| fld.fold_view_item(x)); +fn fold_field<T:ast_fold>(f: TypeField, folder: &T) -> TypeField { + ast::TypeField { + ident: folder.fold_ident(f.ident), + mt: fold_mt(&f.mt, folder), + span: folder.new_span(f.span), + } +} + +fn fold_opt_bounds<T:ast_fold>(b: &Option<OptVec<TyParamBound>>, folder: &T) + -> Option<OptVec<TyParamBound>> { + do b.map |bounds| { + do bounds.map |bound| { + fold_ty_param_bound(bound, folder) + } + } +} + +fn fold_variant_arg_<T:ast_fold>(va: &variant_arg, folder: &T) + -> variant_arg { + ast::variant_arg { + ty: folder.fold_ty(&va.ty), + id: folder.new_id(va.id) + } +} + +pub fn noop_fold_block<T:ast_fold>(b: &Block, folder: &T) -> Block { + let view_items = b.view_items.map(|x| folder.fold_view_item(x)); let mut stmts = ~[]; for stmt in b.stmts.iter() { - match fld.fold_stmt(*stmt) { + match folder.fold_stmt(*stmt) { None => {} Some(stmt) => stmts.push(stmt) } @@ -464,580 +604,262 @@ pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block { ast::Block { view_items: view_items, stmts: stmts, - expr: b.expr.map(|x| fld.fold_expr(*x)), - id: fld.new_id(b.id), + expr: b.expr.map(|x| folder.fold_expr(*x)), + id: folder.new_id(b.id), rules: b.rules, - span: b.span, + span: folder.new_span(b.span), } } -fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option<Stmt_> { - match *s { - StmtDecl(d, nid) => { - match fld.fold_decl(d) { - Some(d) => Some(StmtDecl(d, fld.new_id(nid))), - None => None, - } +pub fn noop_fold_item_underscore<T:ast_fold>(i: &item_, folder: &T) -> item_ { + match *i { + item_static(ref t, m, e) => { + item_static(folder.fold_ty(t), m, folder.fold_expr(e)) } - StmtExpr(e, nid) => { - Some(StmtExpr(fld.fold_expr(e), fld.new_id(nid))) - } - StmtSemi(e, nid) => { - Some(StmtSemi(fld.fold_expr(e), fld.new_id(nid))) - } - StmtMac(ref mac, semi) => Some(StmtMac(fld.fold_mac(mac), semi)) - } -} - -fn noop_fold_arm(a: &Arm, fld: @ast_fold) -> Arm { - Arm { - pats: a.pats.map(|x| fld.fold_pat(*x)), - guard: a.guard.map_move(|x| fld.fold_expr(x)), - body: fld.fold_block(&a.body), - } -} - -pub fn noop_fold_pat(p: &Pat_, fld: @ast_fold) -> Pat_ { - match *p { - PatWild => PatWild, - PatIdent(binding_mode, ref pth, ref sub) => { - PatIdent( - binding_mode, - fld.fold_path(pth), - sub.map_move(|x| fld.fold_pat(x)) + item_fn(ref decl, purity, abi, ref generics, ref body) => { + item_fn( + fold_fn_decl(decl, folder), + purity, + abi, + fold_generics(generics, folder), + folder.fold_block(body) ) } - PatLit(e) => PatLit(fld.fold_expr(e)), - PatEnum(ref pth, ref pats) => { - PatEnum( - fld.fold_path(pth), - pats.map(|pats| pats.map(|x| fld.fold_pat(*x))) + item_mod(ref m) => item_mod(folder.fold_mod(m)), + item_foreign_mod(ref nm) => { + item_foreign_mod(folder.fold_foreign_mod(nm)) + } + item_ty(ref t, ref generics) => { + item_ty(folder.fold_ty(t), + fold_generics(generics, folder)) + } + item_enum(ref enum_definition, ref generics) => { + item_enum( + ast::enum_def { + variants: do enum_definition.variants.map |x| { + folder.fold_variant(x) + }, + }, + fold_generics(generics, folder)) + } + item_struct(ref struct_def, ref generics) => { + let struct_def = fold_struct_def(*struct_def, folder); + item_struct(struct_def, fold_generics(generics, folder)) + } + item_impl(ref generics, ref ifce, ref ty, ref methods) => { + item_impl(fold_generics(generics, folder), + ifce.map(|p| fold_trait_ref(p, folder)), + folder.fold_ty(ty), + methods.map(|x| folder.fold_method(*x)) ) } - PatStruct(ref pth, ref fields, etc) => { - let pth_ = fld.fold_path(pth); - let fs = do fields.map |f| { - ast::FieldPat { - ident: f.ident, - pat: fld.fold_pat(f.pat) + item_trait(ref generics, ref traits, ref methods) => { + let methods = do methods.map |method| { + match *method { + required(ref m) => required(folder.fold_type_method(m)), + provided(method) => provided(folder.fold_method(method)) } }; - PatStruct(pth_, fs, etc) - } - PatTup(ref elts) => PatTup(elts.map(|x| fld.fold_pat(*x))), - PatBox(inner) => PatBox(fld.fold_pat(inner)), - PatUniq(inner) => PatUniq(fld.fold_pat(inner)), - PatRegion(inner) => PatRegion(fld.fold_pat(inner)), - PatRange(e1, e2) => { - PatRange(fld.fold_expr(e1), fld.fold_expr(e2)) - }, - PatVec(ref before, ref slice, ref after) => { - PatVec( - before.map(|x| fld.fold_pat(*x)), - slice.map_move(|x| fld.fold_pat(x)), - after.map(|x| fld.fold_pat(*x)) - ) + item_trait(fold_generics(generics, folder), + traits.map(|p| fold_trait_ref(p, folder)), + methods) } + item_mac(ref m) => item_mac(folder.fold_mac(m)), } } -fn noop_fold_decl(d: &Decl_, fld: @ast_fold) -> Option<Decl_> { - match *d { - DeclLocal(ref l) => Some(DeclLocal(fld.fold_local(*l))), - DeclItem(it) => { - match fld.fold_item(it) { - Some(it_folded) => Some(DeclItem(it_folded)), - None => None, - } - } +pub fn noop_fold_type_method<T:ast_fold>(m: &TypeMethod, fld: &T) + -> TypeMethod { + TypeMethod { + ident: fld.fold_ident(m.ident), + attrs: m.attrs.map(|a| fold_attribute_(*a, fld)), + purity: m.purity, + decl: fold_fn_decl(&m.decl, fld), + generics: fold_generics(&m.generics, fld), + explicit_self: m.explicit_self, + id: fld.new_id(m.id), + span: fld.new_span(m.span), } } -// lift a function in ast-thingy X fold -> ast-thingy to a function -// in (ast-thingy X span X fold) -> (ast-thingy X span). Basically, -// carries the span around. -// It seems strange to me that the call to new_fold doesn't happen -// here but instead in the impl down below.... probably just an -// accident? -pub fn wrap<T>(f: @fn(&T, @ast_fold) -> T) - -> @fn(&T, Span, @ast_fold) -> (T, Span) { - let result: @fn(&T, Span, @ast_fold) -> (T, Span) = |x, s, fld| { - (f(x, fld), s) - }; - result +pub fn noop_fold_mod<T:ast_fold>(m: &_mod, folder: &T) -> _mod { + ast::_mod { + view_items: m.view_items + .iter() + .map(|x| folder.fold_view_item(x)).collect(), + items: m.items.iter().filter_map(|x| folder.fold_item(*x)).collect(), + } } -pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ { - fn fold_field_(field: Field, fld: @ast_fold) -> Field { - ast::Field { - ident: fld.fold_ident(field.ident), - expr: fld.fold_expr(field.expr), - span: fld.new_span(field.span), - } - } - let fold_field = |x| fold_field_(x, fld); +pub fn noop_fold_crate<T:ast_fold>(c: &Crate, folder: &T) -> Crate { + let fold_meta_item = |x| fold_meta_item_(x, folder); + let fold_attribute = |x| fold_attribute_(x, folder); - match *e { + Crate { + module: folder.fold_mod(&c.module), + attrs: c.attrs.map(|x| fold_attribute(*x)), + config: c.config.map(|x| fold_meta_item(*x)), + span: folder.new_span(c.span), + } +} + +pub fn noop_fold_item<T:ast_fold>(i: @ast::item, folder: &T) + -> Option<@ast::item> { + let fold_attribute = |x| fold_attribute_(x, folder); + + Some(@ast::item { + ident: folder.fold_ident(i.ident), + attrs: i.attrs.map(|e| fold_attribute(*e)), + id: folder.new_id(i.id), + node: folder.fold_item_underscore(&i.node), + vis: i.vis, + span: folder.new_span(i.span) + }) +} + +pub fn noop_fold_expr<T:ast_fold>(e: @ast::Expr, folder: &T) -> @ast::Expr { + let fold_field = |x| fold_field_(x, folder); + + let node = match e.node { ExprVstore(e, v) => { - ExprVstore(fld.fold_expr(e), v) + ExprVstore(folder.fold_expr(e), v) } ExprVec(ref exprs, mutt) => { - ExprVec(fld.map_exprs(|x| fld.fold_expr(x), *exprs), mutt) + ExprVec(folder.map_exprs(|x| folder.fold_expr(x), *exprs), mutt) } ExprRepeat(expr, count, mutt) => { - ExprRepeat(fld.fold_expr(expr), fld.fold_expr(count), mutt) + ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count), mutt) } - ExprTup(ref elts) => ExprTup(elts.map(|x| fld.fold_expr(*x))), + ExprTup(ref elts) => ExprTup(elts.map(|x| folder.fold_expr(*x))), ExprCall(f, ref args, blk) => { - ExprCall( - fld.fold_expr(f), - fld.map_exprs(|x| fld.fold_expr(x), *args), - blk - ) + ExprCall(folder.fold_expr(f), + folder.map_exprs(|x| folder.fold_expr(x), *args), + blk) } ExprMethodCall(callee_id, f, i, ref tps, ref args, blk) => { ExprMethodCall( - fld.new_id(callee_id), - fld.fold_expr(f), - fld.fold_ident(i), - tps.map(|x| fld.fold_ty(x)), - fld.map_exprs(|x| fld.fold_expr(x), *args), + folder.new_id(callee_id), + folder.fold_expr(f), + folder.fold_ident(i), + tps.map(|x| folder.fold_ty(x)), + folder.map_exprs(|x| folder.fold_expr(x), *args), blk ) } ExprBinary(callee_id, binop, lhs, rhs) => { - ExprBinary( - fld.new_id(callee_id), - binop, - fld.fold_expr(lhs), - fld.fold_expr(rhs) - ) + ExprBinary(folder.new_id(callee_id), + binop, + folder.fold_expr(lhs), + folder.fold_expr(rhs)) } ExprUnary(callee_id, binop, ohs) => { - ExprUnary( - fld.new_id(callee_id), - binop, - fld.fold_expr(ohs) - ) + ExprUnary(folder.new_id(callee_id), binop, folder.fold_expr(ohs)) } - ExprDoBody(f) => ExprDoBody(fld.fold_expr(f)), - ExprLit(_) => (*e).clone(), + ExprDoBody(f) => ExprDoBody(folder.fold_expr(f)), + ExprLit(_) => e.node.clone(), ExprCast(expr, ref ty) => { - ExprCast(fld.fold_expr(expr), fld.fold_ty(ty)) + ExprCast(folder.fold_expr(expr), folder.fold_ty(ty)) } - ExprAddrOf(m, ohs) => ExprAddrOf(m, fld.fold_expr(ohs)), + ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)), ExprIf(cond, ref tr, fl) => { - ExprIf( - fld.fold_expr(cond), - fld.fold_block(tr), - fl.map_move(|x| fld.fold_expr(x)) - ) + ExprIf(folder.fold_expr(cond), + folder.fold_block(tr), + fl.map_move(|x| folder.fold_expr(x))) } ExprWhile(cond, ref body) => { - ExprWhile(fld.fold_expr(cond), fld.fold_block(body)) + ExprWhile(folder.fold_expr(cond), folder.fold_block(body)) } - ExprForLoop(pat, iter, ref body, opt_ident) => { - ExprForLoop(fld.fold_pat(pat), - fld.fold_expr(iter), - fld.fold_block(body), - opt_ident.map_move(|x| fld.fold_ident(x))) + ExprForLoop(pat, iter, ref body, ref maybe_ident) => { + ExprForLoop(folder.fold_pat(pat), + folder.fold_expr(iter), + folder.fold_block(body), + maybe_ident.map_move(|i| folder.fold_ident(i))) } ExprLoop(ref body, opt_ident) => { - ExprLoop( - fld.fold_block(body), - opt_ident.map_move(|x| fld.fold_ident(x)) - ) + ExprLoop(folder.fold_block(body), + opt_ident.map_move(|x| folder.fold_ident(x))) } ExprMatch(expr, ref arms) => { - ExprMatch( - fld.fold_expr(expr), - arms.map(|x| fld.fold_arm(x)) - ) + ExprMatch(folder.fold_expr(expr), + arms.map(|x| folder.fold_arm(x))) } ExprFnBlock(ref decl, ref body) => { ExprFnBlock( - fold_fn_decl(decl, fld), - fld.fold_block(body) + fold_fn_decl(decl, folder), + folder.fold_block(body) ) } - ExprBlock(ref blk) => ExprBlock(fld.fold_block(blk)), + ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk)), ExprAssign(el, er) => { - ExprAssign(fld.fold_expr(el), fld.fold_expr(er)) + ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) } ExprAssignOp(callee_id, op, el, er) => { - ExprAssignOp( - fld.new_id(callee_id), - op, - fld.fold_expr(el), - fld.fold_expr(er) - ) + ExprAssignOp(folder.new_id(callee_id), + op, + folder.fold_expr(el), + folder.fold_expr(er)) } ExprField(el, id, ref tys) => { - ExprField( - fld.fold_expr(el), fld.fold_ident(id), - tys.map(|x| fld.fold_ty(x)) - ) + ExprField(folder.fold_expr(el), folder.fold_ident(id), + tys.map(|x| folder.fold_ty(x))) } ExprIndex(callee_id, el, er) => { - ExprIndex( - fld.new_id(callee_id), - fld.fold_expr(el), - fld.fold_expr(er) - ) + ExprIndex(folder.new_id(callee_id), + folder.fold_expr(el), + folder.fold_expr(er)) } - ExprPath(ref pth) => ExprPath(fld.fold_path(pth)), + ExprPath(ref pth) => ExprPath(folder.fold_path(pth)), ExprSelf => ExprSelf, - ExprBreak(ref opt_ident) => { - // FIXME #6993: add fold_name to fold.... then cut out the - // bogus Name->Ident->Name conversion. - ExprBreak(opt_ident.map_move(|x| { - // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug - let newx = Ident::new(x); - fld.fold_ident(newx).name - })) - } - ExprAgain(ref opt_ident) => { - // FIXME #6993: add fold_name to fold.... - ExprAgain(opt_ident.map_move(|x| { - // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug - let newx = Ident::new(x); - fld.fold_ident(newx).name - })) - } - ExprRet(ref e) => { - ExprRet(e.map_move(|x| fld.fold_expr(x))) - } ExprLogLevel => ExprLogLevel, + ExprBreak(opt_ident) => ExprBreak(opt_ident), + ExprAgain(opt_ident) => ExprAgain(opt_ident), + ExprRet(ref e) => { + ExprRet(e.map_move(|x| folder.fold_expr(x))) + } ExprInlineAsm(ref a) => { ExprInlineAsm(inline_asm { - inputs: a.inputs.map(|&(c, input)| (c, fld.fold_expr(input))), - outputs: a.outputs.map(|&(c, out)| (c, fld.fold_expr(out))), + inputs: a.inputs.map(|&(c, input)| (c, folder.fold_expr(input))), + outputs: a.outputs.map(|&(c, out)| (c, folder.fold_expr(out))), .. (*a).clone() }) } - ExprMac(ref mac) => ExprMac(fld.fold_mac(mac)), + ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)), ExprStruct(ref path, ref fields, maybe_expr) => { - ExprStruct( - fld.fold_path(path), - fields.map(|x| fold_field(*x)), - maybe_expr.map_move(|x| fld.fold_expr(x)) - ) + ExprStruct(folder.fold_path(path), + fields.map(|x| fold_field(*x)), + maybe_expr.map_move(|x| folder.fold_expr(x))) }, - ExprParen(ex) => ExprParen(fld.fold_expr(ex)) - } -} - -pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { - fn fold_mt(mt: &mt, fld: @ast_fold) -> mt { - mt { - ty: ~fld.fold_ty(mt.ty), - mutbl: mt.mutbl, - } - } - fn fold_field(f: TypeField, fld: @ast_fold) -> TypeField { - ast::TypeField { - ident: fld.fold_ident(f.ident), - mt: fold_mt(&f.mt, fld), - span: fld.new_span(f.span), - } - } - fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold) - -> Option<OptVec<TyParamBound>> { - do b.map |bounds| { - do bounds.map |bound| { fld.fold_ty_param_bound(bound) } - } - } - match *t { - ty_nil | ty_bot | ty_infer => (*t).clone(), - ty_box(ref mt) => ty_box(fold_mt(mt, fld)), - ty_uniq(ref mt) => ty_uniq(fold_mt(mt, fld)), - ty_vec(ref mt) => ty_vec(fold_mt(mt, fld)), - ty_ptr(ref mt) => ty_ptr(fold_mt(mt, fld)), - ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, fld)), - ty_closure(ref f) => { - ty_closure(@TyClosure { - sigil: f.sigil, - purity: f.purity, - region: f.region, - onceness: f.onceness, - bounds: fold_opt_bounds(&f.bounds, fld), - decl: fold_fn_decl(&f.decl, fld), - lifetimes: fld.fold_lifetimes(&f.lifetimes) - }) - } - ty_bare_fn(ref f) => { - ty_bare_fn(@TyBareFn { - lifetimes: fld.fold_lifetimes(&f.lifetimes), - purity: f.purity, - abis: f.abis, - decl: fold_fn_decl(&f.decl, fld) - }) - } - ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(ty))), - ty_path(ref path, ref bounds, id) => - ty_path(fld.fold_path(path), fold_opt_bounds(bounds, fld), fld.new_id(id)), - ty_fixed_length_vec(ref mt, e) => { - ty_fixed_length_vec( - fold_mt(mt, fld), - fld.fold_expr(e) - ) - } - ty_typeof(e) => ty_typeof(fld.fold_expr(e)), - ty_mac(ref mac) => ty_mac(fld.fold_mac(mac)) - } -} - -// ...nor do modules -pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod { - ast::_mod { - view_items: m.view_items.iter().map(|x| fld.fold_view_item(x)).collect(), - items: m.items.iter().filter_map(|x| fld.fold_item(*x)).collect(), - } -} - -fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod { - ast::foreign_mod { - sort: nm.sort, - abis: nm.abis, - view_items: nm.view_items.iter().map(|x| fld.fold_view_item(x)).collect(), - items: nm.items.iter().map(|x| fld.fold_foreign_item(*x)).collect(), - } -} - -fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { - let kind = match v.kind { - tuple_variant_kind(ref variant_args) => { - tuple_variant_kind(variant_args.map(|x| fld.fold_variant_arg(x))) - } - struct_variant_kind(ref struct_def) => { - struct_variant_kind(@ast::struct_def { - fields: struct_def.fields.iter() - .map(|f| fld.fold_struct_field(*f)).collect(), - ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c)) - }) - } + ExprParen(ex) => ExprParen(folder.fold_expr(ex)) }; - let attrs = fld.fold_attributes(v.attrs); + @Expr { + id: folder.new_id(e.id), + node: node, + span: folder.new_span(e.span), + } +} - let de = match v.disr_expr { - Some(e) => Some(fld.fold_expr(e)), - None => None +pub fn noop_fold_stmt<T:ast_fold>(s: &Stmt, folder: &T) -> Option<@Stmt> { + let node = match s.node { + StmtDecl(d, nid) => { + match folder.fold_decl(d) { + Some(d) => Some(StmtDecl(d, folder.new_id(nid))), + None => None, + } + } + StmtExpr(e, nid) => { + Some(StmtExpr(folder.fold_expr(e), folder.new_id(nid))) + } + StmtSemi(e, nid) => { + Some(StmtSemi(folder.fold_expr(e), folder.new_id(nid))) + } + StmtMac(ref mac, semi) => Some(StmtMac(folder.fold_mac(mac), semi)) }; - ast::variant_ { - name: v.name, - attrs: attrs, - kind: kind, - id: fld.new_id(v.id), - disr_expr: de, - vis: v.vis, - } -} -fn noop_fold_ident(i: Ident, _fld: @ast_fold) -> Ident { - i -} - -fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path { - ast::Path { - span: fld.new_span(p.span), - global: p.global, - segments: p.segments.map(|segment| ast::PathSegment { - identifier: fld.fold_ident(segment.identifier), - lifetime: segment.lifetime, - types: segment.types.map(|typ| fld.fold_ty(typ)), - }) - } -} - -fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local { - @Local { - is_mutbl: l.is_mutbl, - ty: fld.fold_ty(&l.ty), - pat: fld.fold_pat(l.pat), - init: l.init.map_move(|e| fld.fold_expr(e)), - id: fld.new_id(l.id), - span: fld.new_span(l.span), - } -} - -// the default macro traversal. visit the path -// using fold_path, and the tts using fold_tts, -// and the span using new_span -fn noop_fold_mac(m: &mac_, fld: @ast_fold) -> mac_ { - match *m { - mac_invoc_tt(ref p,ref tts,ctxt) => - mac_invoc_tt(fld.fold_path(p), - fold_tts(*tts,fld), - ctxt) - } -} - - -/* temporarily eta-expand because of a compiler bug with using `fn<T>` as a - value */ -fn noop_map_exprs(f: @fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] { - es.map(|x| f(*x)) -} - -fn noop_id(i: NodeId) -> NodeId { return i; } - -fn noop_span(sp: Span) -> Span { return sp; } - -pub fn default_ast_fold() -> ast_fold_fns { - @AstFoldFns { - fold_crate: noop_fold_crate, - fold_view_item: noop_fold_view_item, - fold_foreign_item: noop_fold_foreign_item, - fold_item: noop_fold_item, - fold_struct_field: noop_fold_struct_field, - fold_item_underscore: noop_fold_item_underscore, - fold_type_method: noop_fold_type_method, - fold_method: noop_fold_method, - fold_block: noop_fold_block, - fold_stmt: |x, s, fld| (noop_fold_stmt(x, fld), s), - fold_arm: noop_fold_arm, - fold_pat: wrap(noop_fold_pat), - fold_decl: |x, s, fld| (noop_fold_decl(x, fld), s), - fold_expr: wrap(noop_fold_expr), - fold_ty: wrap(noop_fold_ty), - fold_mod: noop_fold_mod, - fold_foreign_mod: noop_fold_foreign_mod, - fold_variant: wrap(noop_fold_variant), - fold_ident: noop_fold_ident, - fold_path: noop_fold_path, - fold_local: noop_fold_local, - fold_mac: wrap(noop_fold_mac), - map_exprs: noop_map_exprs, - new_id: noop_id, - new_span: noop_span, - } -} - -impl ast_fold for AstFoldFns { - /* naturally, a macro to write these would be nice */ - fn fold_crate(@self, c: &Crate) -> Crate { - (self.fold_crate)(c, self as @ast_fold) - } - fn fold_view_item(@self, x: &view_item) -> view_item { - ast::view_item { - node: (self.fold_view_item)(&x.node, self as @ast_fold), - attrs: self.fold_attributes(x.attrs), - vis: x.vis, - span: (self.new_span)(x.span), - } - } - fn fold_foreign_item(@self, x: @foreign_item) -> @foreign_item { - (self.fold_foreign_item)(x, self as @ast_fold) - } - fn fold_item(@self, i: @item) -> Option<@item> { - (self.fold_item)(i, self as @ast_fold) - } - fn fold_struct_field(@self, sf: @struct_field) -> @struct_field { - @Spanned { - node: ast::struct_field_ { - kind: sf.node.kind, - id: (self.new_id)(sf.node.id), - ty: self.fold_ty(&sf.node.ty), - attrs: self.fold_attributes(sf.node.attrs), - }, - span: (self.new_span)(sf.span), - } - } - fn fold_item_underscore(@self, i: &item_) -> item_ { - (self.fold_item_underscore)(i, self as @ast_fold) - } - fn fold_type_method(@self, m: &TypeMethod) -> TypeMethod { - (self.fold_type_method)(m, self as @ast_fold) - } - fn fold_method(@self, x: @method) -> @method { - (self.fold_method)(x, self as @ast_fold) - } - fn fold_block(@self, x: &Block) -> Block { - (self.fold_block)(x, self as @ast_fold) - } - fn fold_stmt(@self, x: &Stmt) -> Option<@Stmt> { - let (n_opt, s) = (self.fold_stmt)(&x.node, x.span, self as @ast_fold); - match n_opt { - Some(n) => Some(@Spanned { node: n, span: (self.new_span)(s) }), - None => None, - } - } - fn fold_arm(@self, x: &Arm) -> Arm { - (self.fold_arm)(x, self as @ast_fold) - } - fn fold_pat(@self, x: @Pat) -> @Pat { - let (n, s) = (self.fold_pat)(&x.node, x.span, self as @ast_fold); - @Pat { - id: (self.new_id)(x.id), - node: n, - span: (self.new_span)(s), - } - } - fn fold_decl(@self, x: @Decl) -> Option<@Decl> { - let (n_opt, s) = (self.fold_decl)(&x.node, x.span, self as @ast_fold); - match n_opt { - Some(n) => Some(@Spanned { node: n, span: (self.new_span)(s) }), - None => None, - } - } - fn fold_expr(@self, x: @Expr) -> @Expr { - let (n, s) = (self.fold_expr)(&x.node, x.span, self as @ast_fold); - @Expr { - id: (self.new_id)(x.id), - node: n, - span: (self.new_span)(s), - } - } - fn fold_ty(@self, x: &Ty) -> Ty { - let (n, s) = (self.fold_ty)(&x.node, x.span, self as @ast_fold); - Ty { - id: (self.new_id)(x.id), - node: n, - span: (self.new_span)(s), - } - } - fn fold_mod(@self, x: &_mod) -> _mod { - (self.fold_mod)(x, self as @ast_fold) - } - fn fold_foreign_mod(@self, x: &foreign_mod) -> foreign_mod { - (self.fold_foreign_mod)(x, self as @ast_fold) - } - fn fold_variant(@self, x: &variant) -> variant { - let (n, s) = (self.fold_variant)(&x.node, x.span, self as @ast_fold); - Spanned { node: n, span: (self.new_span)(s) } - } - fn fold_ident(@self, x: Ident) -> Ident { - (self.fold_ident)(x, self as @ast_fold) - } - fn fold_path(@self, x: &Path) -> Path { - (self.fold_path)(x, self as @ast_fold) - } - fn fold_local(@self, x: @Local) -> @Local { - (self.fold_local)(x, self as @ast_fold) - } - fn fold_mac(@self, x: &mac) -> mac { - let (n, s) = (self.fold_mac)(&x.node, x.span, self as @ast_fold); - Spanned { node: n, span: (self.new_span)(s) } - } - fn map_exprs(@self, - f: @fn(@Expr) -> @Expr, - e: &[@Expr]) - -> ~[@Expr] { - (self.map_exprs)(f, e) - } - fn new_id(@self, node_id: ast::NodeId) -> NodeId { - (self.new_id)(node_id) - } - fn new_span(@self, span: Span) -> Span { - (self.new_span)(span) - } -} - -// brson agrees with me that this function's existence is probably -// not a good or useful thing. -pub fn make_fold(afp: ast_fold_fns) -> @ast_fold { - afp as @ast_fold + node.map_move(|node| @Spanned { + node: node, + span: folder.new_span(s.span), + }) } #[cfg(test)] @@ -1048,16 +870,23 @@ mod test { use print::pprust; use super::*; + struct IdentFolder { + f: @fn(ast::ident)->ast::ident, + } + + impl ast_fold for IdentFolder { + fn fold_ident(@self, i: ident) -> ident { + (self.f)(i) + } + } + // taken from expand // given a function from idents to idents, produce // an ast_fold that applies that function: - pub fn fun_to_ident_folder(f: @fn(ast::Ident)->ast::Ident) -> @ast_fold{ - let afp = default_ast_fold(); - let f_pre = @AstFoldFns{ - fold_ident : |id, _| f(id), - .. *afp - }; - make_fold(f_pre) + pub fn fun_to_ident_folder(f: @fn(ast::ident)->ast::ident) -> @ast_fold { + @IdentFolder { + f: f, + } as @ast_fold } // this version doesn't care about getting comments or docstrings in. @@ -1120,3 +949,4 @@ mod test { ~"fn zz(){let zz=13 as zz;}"); } } + diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs index 2e4ae7f8544..b6976b2c355 100644 --- a/src/test/compile-fail/dead-code-ret.rs +++ b/src/test/compile-fail/dead-code-ret.rs @@ -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 diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs index eb60e34df8f..c39c258c701 100644 --- a/src/test/compile-fail/issue-897-2.rs +++ b/src/test/compile-fail/issue-897-2.rs @@ -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.