Skip to content

Commit 907daa2

Browse files
committed
Expand ItemDecorator extensions in all contexts
Now that fold_item can return multiple items, this is pretty trivial. It also recursively expands generated items so ItemDecorators can generate items that are tagged with ItemDecorators! Closes rust-lang#4913
1 parent 3c02749 commit 907daa2

File tree

3 files changed

+59
-53
lines changed

3 files changed

+59
-53
lines changed

src/libsyntax/ext/expand.rs

+33-52
Original file line numberDiff line numberDiff line change
@@ -203,52 +203,6 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
203203
}
204204
}
205205

206-
// This is a secondary mechanism for invoking syntax extensions on items:
207-
// "decorator" attributes, such as #[auto_encode]. These are invoked by an
208-
// attribute prefixing an item, and are interpreted by feeding the item
209-
// through the named attribute _as a syntax extension_ and splicing in the
210-
// resulting item vec into place in favour of the decorator. Note that
211-
// these do _not_ work for macro extensions, just ItemDecorator ones.
212-
//
213-
// NB: there is some redundancy between this and expand_item, below, and
214-
// they might benefit from some amount of semantic and language-UI merger.
215-
pub fn expand_mod_items(module_: &ast::Mod, fld: &mut MacroExpander) -> ast::Mod {
216-
// Fold the contents first:
217-
let module_ = noop_fold_mod(module_, fld);
218-
219-
// For each item, look through the attributes. If any of them are
220-
// decorated with "item decorators", then use that function to transform
221-
// the item into a new set of items.
222-
let mut new_items = module_.items.clone();
223-
for item in module_.items.iter() {
224-
for attr in item.attrs.rev_iter() {
225-
let mname = attr.name();
226-
227-
match fld.extsbox.find(&intern(mname.get())) {
228-
Some(&ItemDecorator(dec_fn)) => {
229-
fld.cx.bt_push(ExpnInfo {
230-
call_site: attr.span,
231-
callee: NameAndSpan {
232-
name: mname.get().to_str(),
233-
format: MacroAttribute,
234-
span: None
235-
}
236-
});
237-
dec_fn(fld.cx, attr.span, attr.node.value, *item,
238-
|item| new_items.push(item));
239-
fld.cx.bt_pop();
240-
},
241-
_ => {},
242-
}
243-
}
244-
}
245-
246-
ast::Mod {
247-
items: new_items,
248-
..module_
249-
}
250-
}
251-
252206
// eval $e with a new exts frame:
253207
macro_rules! with_exts_frame (
254208
($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
@@ -263,7 +217,35 @@ macro_rules! with_exts_frame (
263217
// When we enter a module, record it, for the sake of `module!`
264218
pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
265219
-> SmallVector<@ast::Item> {
266-
match it.node {
220+
let mut decorator_items = SmallVector::zero();
221+
for attr in it.attrs.rev_iter() {
222+
let mname = attr.name();
223+
224+
match fld.extsbox.find(&intern(mname.get())) {
225+
Some(&ItemDecorator(dec_fn)) => {
226+
fld.cx.bt_push(ExpnInfo {
227+
call_site: attr.span,
228+
callee: NameAndSpan {
229+
name: mname.get().to_str(),
230+
format: MacroAttribute,
231+
span: None
232+
}
233+
});
234+
// we'd ideally decorator_items.push_all(expand_item(item, fld)),
235+
// but that double-mut-borrows fld
236+
dec_fn(fld.cx, attr.span, attr.node.value, it,
237+
|item| decorator_items.push(item));
238+
fld.cx.bt_pop();
239+
}
240+
_ => {}
241+
}
242+
}
243+
244+
let decorator_items = decorator_items.move_iter()
245+
.flat_map(|item| expand_item(item, fld).move_iter())
246+
.collect();
247+
248+
let mut new_items = match it.node {
267249
ast::ItemMac(..) => expand_item_mac(it, fld),
268250
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
269251
fld.cx.mod_push(it.ident);
@@ -275,7 +257,10 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
275257
result
276258
},
277259
_ => noop_fold_item(it, fld)
278-
}
260+
};
261+
262+
new_items.push_all(decorator_items);
263+
new_items
279264
}
280265

281266
// does this attribute list contain "macro_escape" ?
@@ -783,10 +768,6 @@ impl<'a> Folder for MacroExpander<'a> {
783768
expand_expr(expr, self)
784769
}
785770

786-
fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod {
787-
expand_mod_items(module, self)
788-
}
789-
790771
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
791772
expand_item(item, self)
792773
}

src/libsyntax/util/small_vector.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -64,6 +64,12 @@ impl<T> SmallVector<T> {
6464
}
6565
}
6666

67+
pub fn push_all(&mut self, other: SmallVector<T>) {
68+
for v in other.move_iter() {
69+
self.push(v);
70+
}
71+
}
72+
6773
pub fn get<'a>(&'a self, idx: uint) -> &'a T {
6874
match *self {
6975
One(ref v) if idx == 0 => v,

src/test/run-pass/deriving-in-fn.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub fn main() {
12+
#[deriving(ToStr)]
13+
struct Foo {
14+
foo: int,
15+
}
16+
17+
let f = Foo { foo: 10 };
18+
let _ = f.to_str();
19+
}

0 commit comments

Comments
 (0)