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 #4913
This commit is contained in:
parent
c1fac65396
commit
07ea23e15d
@ -203,52 +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 mut new_items = module_.items.clone();
|
||||
for item in module_.items.iter() {
|
||||
for attr in item.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
|
||||
}
|
||||
});
|
||||
dec_fn(fld.cx, attr.span, attr.node.value, *item,
|
||||
|item| new_items.push(item));
|
||||
fld.cx.bt_pop();
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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" ?
|
||||
@ -778,10 +763,6 @@ fn fold_expr(&mut self, expr: @ast::Expr) -> @ast::Expr {
|
||||
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)
|
||||
}
|
||||
|
@ -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 @@ pub fn push(&mut self, v: T) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_all(&mut self, other: SmallVector<T>) {
|
||||
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,
|
||||
|
19
src/test/run-pass/deriving-in-fn.rs
Normal file
19
src/test/run-pass/deriving-in-fn.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user