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:
|
// eval $e with a new exts frame:
|
||||||
macro_rules! with_exts_frame (
|
macro_rules! with_exts_frame (
|
||||||
($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
|
($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!`
|
// When we enter a module, record it, for the sake of `module!`
|
||||||
pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
|
pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
|
||||||
-> SmallVector<@ast::Item> {
|
-> 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::ItemMac(..) => expand_item_mac(it, fld),
|
||||||
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
|
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
|
||||||
fld.cx.mod_push(it.ident);
|
fld.cx.mod_push(it.ident);
|
||||||
@ -275,7 +257,10 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
|
|||||||
result
|
result
|
||||||
},
|
},
|
||||||
_ => noop_fold_item(it, fld)
|
_ => noop_fold_item(it, fld)
|
||||||
}
|
};
|
||||||
|
|
||||||
|
new_items.push_all(decorator_items);
|
||||||
|
new_items
|
||||||
}
|
}
|
||||||
|
|
||||||
// does this attribute list contain "macro_escape" ?
|
// 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)
|
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> {
|
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
|
||||||
expand_item(item, self)
|
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
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// 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 {
|
pub fn get<'a>(&'a self, idx: uint) -> &'a T {
|
||||||
match *self {
|
match *self {
|
||||||
One(ref v) if idx == 0 => v,
|
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