about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs29
-rw-r--r--src/libsyntax/ext/expand.rs47
2 files changed, 65 insertions, 11 deletions
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);
         });