}
*self.get_mut(index) = val;
}
+
+ pub fn partitioned(&self, f: |&T| -> bool) -> (Vec<T>, Vec<T>) {
+ let mut lefts = Vec::new();
+ let mut rights = Vec::new();
+
+ for elt in self.iter() {
+ if f(elt) {
+ lefts.push(elt.clone());
+ } else {
+ rights.push(elt.clone());
+ }
+ }
+
+ (lefts, rights)
+ }
}
impl<T:Clone> Clone for Vec<T> {
pub type ItemDecorator =
fn(&mut ExtCtxt, Span, @ast::MetaItem, @ast::Item, |@ast::Item|);
+pub type ItemModifier =
+ fn(&mut ExtCtxt, Span, @ast::MetaItem, @ast::Item) -> @ast::Item;
+
pub struct BasicMacroExpander {
expander: MacroExpanderFn,
span: Option<Span>
}
}
+/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
- // #[deriving] and such
+ /// A syntax extension that is attached to an item and creates new items
+ /// based upon it.
+ ///
+ /// `#[deriving(...)]` is an `ItemDecorator`.
ItemDecorator(ItemDecorator),
- // Token-tree expanders
- NormalTT(~MacroExpander:'static, Option<Span>),
+ /// A syntax extension that is attached to an item and modifies it
+ /// in-place.
+ ItemModifier(ItemModifier),
- // An IdentTT is a macro that has an
- // identifier in between the name of the
- // macro and the argument. Currently,
- // the only examples of this is
- // macro_rules!
+ /// A normal, function-like syntax extension.
+ ///
+ /// `bytes!` is a `NormalTT`.
+ NormalTT(~MacroExpander:'static, Option<Span>),
- // perhaps macro_rules! will lose its odd special identifier argument,
- // and this can go away also
+ /// A function-like syntax extension that has an extra ident before
+ /// the block.
+ ///
+ /// `macro_rules!` is an `IdentTT`.
IdentTT(~IdentMacroExpander:'static, Option<Span>),
}
// 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> {
- let mut decorator_items: SmallVector<@ast::Item> = SmallVector::zero();
+ let it = expand_item_modifiers(it, fld);
+
+ let mut decorator_items = SmallVector::zero();
for attr in it.attrs.rev_iter() {
let mname = attr.name();
new_items
}
+fn expand_item_modifiers(mut it: @ast::Item, fld: &mut MacroExpander)
+ -> @ast::Item {
+ let (modifiers, attrs) = it.attrs.partitioned(|attr| {
+ match fld.extsbox.find(&intern(attr.name().get())) {
+ Some(&ItemModifier(_)) => true,
+ _ => false
+ }
+ });
+
+ it = @ast::Item {
+ attrs: attrs,
+ ..(*it).clone()
+ };
+
+ if modifiers.is_empty() {
+ return it;
+ }
+
+ for attr in modifiers.iter() {
+ let mname = attr.name();
+
+ match fld.extsbox.find(&intern(mname.get())) {
+ Some(&ItemModifier(dec_fn)) => {
+ fld.cx.bt_push(ExpnInfo {
+ call_site: attr.span,
+ callee: NameAndSpan {
+ name: mname.get().to_str(),
+ format: MacroAttribute,
+ span: None,
+ }
+ });
+ it = dec_fn(fld.cx, attr.span, attr.node.value, it);
+ fld.cx.bt_pop();
+ }
+ _ => unreachable!()
+ }
+ }
+
+ // expansion may have added new ItemModifiers
+ expand_item_modifiers(it, fld)
+}
+
// does this attribute list contain "macro_escape" ?
pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "macro_escape")
NormalTT(ext, _) => NormalTT(ext, Some(krate.span)),
IdentTT(ext, _) => IdentTT(ext, Some(krate.span)),
ItemDecorator(ext) => ItemDecorator(ext),
+ ItemModifier(ext) => ItemModifier(ext),
};
fld.extsbox.insert(name, extension);
});
// force-host
-#[feature(globs, macro_registrar, macro_rules, quote)];
+#[feature(globs, macro_registrar, macro_rules, quote, managed_boxes)];
extern crate syntax;
-use syntax::ast::{Name, TokenTree};
+use syntax::ast::{Name, TokenTree, Item, MetaItem};
use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::parse::token;
span: None,
},
None));
+ register(token::intern("into_foo"), ItemModifier(expand_into_foo));
}
-pub fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
+fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
if !tts.is_empty() {
cx.span_fatal(sp, "make_a_1 takes no arguments");
}
MRExpr(quote_expr!(cx, 1i))
}
+fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: @MetaItem, it: @Item)
+ -> @Item {
+ @Item {
+ attrs: it.attrs.clone(),
+ ..(*quote_item!(cx, enum Foo { Bar, Baz }).unwrap()).clone()
+ }
+}
+
pub fn foo() {}
#[phase(syntax)]
extern crate macro_crate_test;
+#[into_foo]
+#[deriving(Eq, Clone, Show)]
+fn foo() -> AFakeTypeThatHadBetterGoAway {}
+
pub fn main() {
assert_eq!(1, make_a_1!());
assert_eq!(2, exported_macro!());
+
+ assert_eq!(Bar, Bar);
+ test(None::<Foo>);
}
+
+fn test<T: Eq+Clone>(_: Option<T>) {}