diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7ac66ecaa3713..bb5245c240f4f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -35,7 +35,7 @@ pub struct MacroDef { } pub type ItemDecorator = - fn(&mut ExtCtxt, Span, @ast::MetaItem, ~[@ast::Item]) -> ~[@ast::Item]; + fn(&mut ExtCtxt, Span, @ast::MetaItem, @ast::Item, |@ast::Item|); pub struct BasicMacroExpander { expander: MacroExpanderFn, diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 76cf5997aee75..bd961002f5311 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -17,8 +17,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_clone(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "clone", "Clone"]), @@ -38,14 +38,14 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "clone", "DeepClone"]), @@ -67,7 +67,7 @@ pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn cs_clone( diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 4672f1a8db689..6592dc97f348e 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -17,7 +17,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_eq(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr { @@ -54,5 +55,5 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, md!("ne", cs_ne) ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 1a8ace69307a7..c41986fceef64 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -18,7 +18,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_ord(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { macro_rules! md ( ($name:expr, $op:expr, $equal:expr) => { MethodDef { @@ -46,7 +47,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, md!("ge", false, true) ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } /// Strict inequality. diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs index 7b7c1afa4d5cb..63e13b492020d 100644 --- a/src/libsyntax/ext/deriving/cmp/totaleq.rs +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -17,7 +17,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_totaleq(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { fn cs_equals(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr { cs_and(|cx, span, _, _| cx.expr_bool(span, false), cx, span, substr) @@ -41,5 +42,5 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt, } ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index 157b6dc7521b7..3e58d2edb2960 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -19,7 +19,8 @@ use std::cmp::{Ordering, Equal, Less, Greater}; pub fn expand_deriving_totalord(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "cmp", "TotalOrd"]), @@ -39,7 +40,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index fdf1ef17d538b..c5c9a43fa5f58 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -24,7 +24,8 @@ use parse::token; pub fn expand_deriving_decodable(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new_(~["serialize", "Decodable"], None, @@ -49,7 +50,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index 7b87152b7115a..7ed27168bb606 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -17,8 +17,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_default(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "default", "Default"]), @@ -37,7 +37,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, }, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 43edf6006b414..99c712caafef8 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -85,7 +85,8 @@ use parse::token; pub fn expand_deriving_encodable(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new_(~["serialize", "Encodable"], None, @@ -110,7 +111,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 9d290c93c6494..effcccdbaf831 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -322,27 +322,23 @@ impl<'a> TraitDef<'a> { pub fn expand(&self, cx: &mut ExtCtxt, _mitem: @ast::MetaItem, - in_items: ~[@ast::Item]) -> ~[@ast::Item] { - let mut result = ~[]; - for item in in_items.iter() { - result.push(*item); - match item.node { - ast::ItemStruct(struct_def, ref generics) => { - result.push(self.expand_struct_def(cx, - struct_def, - item.ident, - generics)); - } - ast::ItemEnum(ref enum_def, ref generics) => { - result.push(self.expand_enum_def(cx, - enum_def, - item.ident, - generics)); - } - _ => () + item: @ast::Item, + push: |@ast::Item|) { + match item.node { + ast::ItemStruct(struct_def, ref generics) => { + push(self.expand_struct_def(cx, + struct_def, + item.ident, + generics)); + } + ast::ItemEnum(ref enum_def, ref generics) => { + push(self.expand_enum_def(cx, + enum_def, + item.ident, + generics)); } + _ => () } - result } /** diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index 19e81b81df6a6..b1adf96b90af8 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -18,7 +18,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_iter_bytes(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "to_bytes", "IterBytes"]), @@ -41,7 +42,7 @@ pub fn expand_deriving_iter_bytes(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn iter_bytes_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 01e31fc5724d2..62408d79ee31e 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -48,25 +48,24 @@ pub mod generic; pub fn expand_meta_deriving(cx: &mut ExtCtxt, _span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { match mitem.node { MetaNameValue(_, ref l) => { cx.span_err(l.span, "unexpected value in `deriving`"); - in_items } MetaWord(_) | MetaList(_, []) => { cx.span_warn(mitem.span, "empty trait list in `deriving`"); - in_items } MetaList(_, ref titems) => { - titems.rev_iter().fold(in_items, |in_items, &titem| { + for &titem in titems.rev_iter() { match titem.node { MetaNameValue(ref tname, _) | MetaList(ref tname, _) | MetaWord(ref tname) => { macro_rules! expand(($func:path) => ($func(cx, titem.span, - titem, in_items))); + titem, item, + |i| push(i)))); match tname.get() { "Clone" => expand!(clone::expand_deriving_clone), "DeepClone" => expand!(clone::expand_deriving_deep_clone), @@ -94,12 +93,11 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt, ref tname => { cx.span_err(titem.span, format!("unknown \ `deriving` trait: `{}`", *tname)); - in_items } - } + }; } } - }) + } } } } diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 1b356667b6b31..9391c9cd23c74 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -19,7 +19,8 @@ use parse::token::InternedString; pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "num", "FromPrimitive"]), @@ -61,7 +62,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index ef7bd7c2bcdec..351264fed72af 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -19,8 +19,8 @@ use opt_vec; pub fn expand_deriving_rand(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "rand", "Rand"]), @@ -46,7 +46,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, } ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index e2d507f303510..984be122fe8a4 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -23,8 +23,8 @@ use std::hashmap::HashMap; pub fn expand_deriving_show(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { // &mut ::std::fmt::Formatter let fmtr = Ptr(~Literal(Path::new(~["std", "fmt", "Formatter"])), Borrowed(None, ast::MutMutable)); @@ -47,7 +47,7 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt, } ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } // we construct a format string and then defer to std::fmt, since that diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs index e5145fb15f7a1..1efcf61013f6a 100644 --- a/src/libsyntax/ext/deriving/to_str.rs +++ b/src/libsyntax/ext/deriving/to_str.rs @@ -20,8 +20,8 @@ use parse::token; pub fn expand_deriving_to_str(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "to_str", "ToStr"]), @@ -40,7 +40,7 @@ pub fn expand_deriving_to_str(cx: &mut ExtCtxt, } ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } // It used to be the case that this deriving implementation invoked diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs index ca5c1543d88dc..924ab3c9e0020 100644 --- a/src/libsyntax/ext/deriving/zero.rs +++ b/src/libsyntax/ext/deriving/zero.rs @@ -17,8 +17,8 @@ use ext::deriving::generic::*; pub fn expand_deriving_zero(cx: &mut ExtCtxt, span: Span, mitem: @MetaItem, - in_items: ~[@Item]) - -> ~[@Item] { + item: @Item, + push: |@Item|) { let trait_def = TraitDef { span: span, path: Path::new(~["std", "num", "Zero"]), @@ -53,7 +53,7 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt, } ] }; - trait_def.expand(cx, mitem, in_items) + trait_def.expand(cx, mitem, item, push) } fn zero_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d96fc27f3ddfe..921647ad7753f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -29,7 +29,6 @@ use visit::Visitor; use util::small_vector::SmallVector; use std::cast; -use std::vec; use std::unstable::dynamic_lib::DynamicLibrary; use std::os; @@ -204,51 +203,6 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { } } -// This is a secondary mechanism for invoking syntax extensions on items: -// "decorator" attributes, such as #[auto_encode]. These are invoked by an -// attribute prefixing an item, and are interpreted by feeding the item -// through the named attribute _as a syntax extension_ and splicing in the -// resulting item vec into place in favour of the decorator. Note that -// these do _not_ work for macro extensions, just ItemDecorator ones. -// -// NB: there is some redundancy between this and expand_item, below, and -// they might benefit from some amount of semantic and language-UI merger. -pub fn expand_mod_items(module_: &ast::Mod, fld: &mut MacroExpander) -> ast::Mod { - // Fold the contents first: - 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 - // the item into a new set of items. - let new_items = vec::flat_map(module_.items, |item| { - item.attrs.rev_iter().fold(~[*item], |items, attr| { - let mname = attr.name(); - - match fld.extsbox.find(&intern(mname.get())) { - Some(&ItemDecorator(dec_fn)) => { - fld.cx.bt_push(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - name: mname.get().to_str(), - format: MacroAttribute, - span: None - } - }); - let r = dec_fn(fld.cx, attr.span, attr.node.value, items); - fld.cx.bt_pop(); - r - }, - _ => items, - } - }) - }); - - ast::Mod { - items: new_items, - ..module_ - } -} - // eval $e with a new exts frame: macro_rules! with_exts_frame ( ($extsboxexpr:expr,$macros_escape:expr,$e:expr) => @@ -263,7 +217,35 @@ macro_rules! with_exts_frame ( // When we enter a module, record it, for the sake of `module!` pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander) -> SmallVector<@ast::Item> { - match it.node { + let mut decorator_items = SmallVector::zero(); + for attr in it.attrs.rev_iter() { + let mname = attr.name(); + + match fld.extsbox.find(&intern(mname.get())) { + Some(&ItemDecorator(dec_fn)) => { + fld.cx.bt_push(ExpnInfo { + call_site: attr.span, + callee: NameAndSpan { + name: mname.get().to_str(), + format: MacroAttribute, + span: None + } + }); + // we'd ideally decorator_items.push_all(expand_item(item, fld)), + // but that double-mut-borrows fld + dec_fn(fld.cx, attr.span, attr.node.value, it, + |item| decorator_items.push(item)); + fld.cx.bt_pop(); + } + _ => {} + } + } + + let decorator_items = decorator_items.move_iter() + .flat_map(|item| expand_item(item, fld).move_iter()) + .collect(); + + let mut new_items = match it.node { ast::ItemMac(..) => expand_item_mac(it, fld), ast::ItemMod(_) | ast::ItemForeignMod(_) => { fld.cx.mod_push(it.ident); @@ -275,7 +257,10 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander) result }, _ => noop_fold_item(it, fld) - } + }; + + new_items.push_all(decorator_items); + new_items } // does this attribute list contain "macro_escape" ? @@ -783,10 +768,6 @@ impl<'a> Folder for MacroExpander<'a> { expand_expr(expr, self) } - fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod { - expand_mod_items(module, self) - } - fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> { expand_item(item, self) } diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index e0d7fdd87908c..32e5b83ee04b7 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -64,6 +64,12 @@ impl SmallVector { } } + pub fn push_all(&mut self, other: SmallVector) { + for v in other.move_iter() { + self.push(v); + } + } + pub fn get<'a>(&'a self, idx: uint) -> &'a T { match *self { One(ref v) if idx == 0 => v, diff --git a/src/test/run-pass/deriving-in-fn.rs b/src/test/run-pass/deriving-in-fn.rs new file mode 100644 index 0000000000000..7fb7d601b81b9 --- /dev/null +++ b/src/test/run-pass/deriving-in-fn.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + #[deriving(ToStr)] + struct Foo { + foo: int, + } + + let f = Foo { foo: 10 }; + let _ = f.to_str(); +}