about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2014-02-13 22:57:43 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-02-14 07:48:00 -0800
commit07ea23e15dab673a3016d21b601234b296e59e57 (patch)
tree20d962e6a3b84c9149b9ff9c026aaa2d13421f3f /src/libsyntax
parentc1fac653962d28425134a4f1ec89d1ebea647cf3 (diff)
downloadrust-07ea23e15dab673a3016d21b601234b296e59e57.tar.gz
rust-07ea23e15dab673a3016d21b601234b296e59e57.zip
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
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/expand.rs85
-rw-r--r--src/libsyntax/util/small_vector.rs8
2 files changed, 40 insertions, 53 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e59afc6ffa6..97766e1a14b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -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 @@ impl<'a> Folder for MacroExpander<'a> {
         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)
     }
diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs
index e0d7fdd8790..32e5b83ee04 100644
--- a/src/libsyntax/util/small_vector.rs
+++ b/src/libsyntax/util/small_vector.rs
@@ -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 @@ impl<T> SmallVector<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,