about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libstd/vec_ng.rs15
-rw-r--r--src/libsyntax/ext/base.rs29
-rw-r--r--src/libsyntax/ext/expand.rs47
-rw-r--r--src/test/auxiliary/macro_crate_test.rs15
-rw-r--r--src/test/run-pass-fulldeps/macro-crate.rs9
5 files changed, 101 insertions, 14 deletions
diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs
index a195ce8deae..76fd68a5265 100644
--- a/src/libstd/vec_ng.rs
+++ b/src/libstd/vec_ng.rs
@@ -108,6 +108,21 @@ impl<T: Clone> Vec<T> {
         }
         *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> {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 459c0d1d0e3..ae8c13a5f98 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -38,6 +38,9 @@ pub struct MacroDef {
 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>
@@ -126,21 +129,27 @@ impl MacResult {
     }
 }
 
+/// 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>),
 }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 30b04b7f377..dc79ceb4daa 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -260,7 +260,9 @@ 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> {
-    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();
 
@@ -307,6 +309,48 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
     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")
@@ -492,6 +536,7 @@ fn load_extern_macros(krate: &ast::ViewItem, fld: &mut MacroExpander) {
                 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);
         });
diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs
index b8baffcfea5..b473ca3264e 100644
--- a/src/test/auxiliary/macro_crate_test.rs
+++ b/src/test/auxiliary/macro_crate_test.rs
@@ -10,11 +10,11 @@
 
 // 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;
@@ -32,13 +32,22 @@ pub fn macro_registrar(register: |Name, SyntaxExtension|) {
             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() {}
diff --git a/src/test/run-pass-fulldeps/macro-crate.rs b/src/test/run-pass-fulldeps/macro-crate.rs
index 69c6e7b0585..6f412f01bb9 100644
--- a/src/test/run-pass-fulldeps/macro-crate.rs
+++ b/src/test/run-pass-fulldeps/macro-crate.rs
@@ -19,7 +19,16 @@
 #[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>) {}