about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2015-04-25 14:04:46 +1200
committerNick Cameron <ncameron@mozilla.com>2015-04-25 14:04:46 +1200
commit0a62a05c6736dce542529cb1eb67fc54c0b70db4 (patch)
tree5489a37f8b0991af0dce8bb1e6fb70474720d213
parentf9e53c7f2c8285f3422ac7ac091349ce572c4baa (diff)
parent143f2db3174103e459218958f567985b1f47944b (diff)
downloadrust-0a62a05c6736dce542529cb1eb67fc54c0b70db4.tar.gz
rust-0a62a05c6736dce542529cb1eb67fc54c0b70db4.zip
Merge branch 'syntax' of https://github.com/aochagavia/rust into mulit-decor
Conflicts:
	src/librustc/plugin/registry.rs
	src/libsyntax/ext/base.rs
	src/libsyntax/ext/cfg_attr.rs
	src/libsyntax/ext/deriving/mod.rs
	src/libsyntax/ext/expand.rs
	src/libsyntax/print/pprust.rs
	src/test/auxiliary/macro_crate_test.rs
-rw-r--r--src/librustc/plugin/registry.rs7
-rw-r--r--src/libsyntax/ext/base.rs58
-rw-r--r--src/libsyntax/ext/deriving/mod.rs20
-rw-r--r--src/libsyntax/ext/expand.rs32
-rw-r--r--src/libsyntax/print/pprust.rs1
-rw-r--r--src/test/auxiliary/macro_crate_test.rs83
-rw-r--r--src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs52
7 files changed, 239 insertions, 14 deletions
diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs
index 322b5d3a8cf..fccde9a2f17 100644
--- a/src/librustc/plugin/registry.rs
+++ b/src/librustc/plugin/registry.rs
@@ -14,8 +14,13 @@ use lint::{LintPassObject, LintId, Lint};
 use session::Session;
 
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
+<<<<<<< HEAD
 use syntax::ext::base::{IdentTT, Decorator, Modifier, MultiModifier, MacroRulesTT};
 use syntax::ext::base::MacroExpanderFn;
+=======
+use syntax::ext::base::{IdentTT, Decorator, MultiDecorator, Modifier, MultiModifier, MacroRulesTT};
+use syntax::ext::base::{MacroExpanderFn};
+>>>>>>> 143f2db3174103e459218958f567985b1f47944b
 use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::ptr::P;
@@ -84,6 +89,7 @@ impl<'a> Registry<'a> {
     /// Register a syntax extension of any kind.
     ///
     /// This is the most general hook into `libsyntax`'s expansion behavior.
+    #[allow(deprecated)]
     pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
         self.syntax_exts.push((name, match extension {
             NormalTT(ext, _, allow_internal_unstable) => {
@@ -93,6 +99,7 @@ impl<'a> Registry<'a> {
                 IdentTT(ext, Some(self.krate_span), allow_internal_unstable)
             }
             Decorator(ext) => Decorator(ext),
+            MultiDecorator(ext) => MultiDecorator(ext),
             Modifier(ext) => Modifier(ext),
             MultiModifier(ext) => MultiModifier(ext),
             MacroRulesTT => {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 50ab430f148..f84d3ed98c7 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -30,6 +30,8 @@ use std::collections::HashMap;
 use std::rc::Rc;
 use std::default::Default;
 
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemDecorator")]
 pub trait ItemDecorator {
     fn expand(&self,
               ecx: &mut ExtCtxt,
@@ -39,6 +41,9 @@ pub trait ItemDecorator {
               push: &mut FnMut(P<ast::Item>));
 }
 
+#[allow(deprecated)]
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemDecorator")]
 impl<F> ItemDecorator for F
     where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P<ast::Item>))
 {
@@ -52,6 +57,8 @@ impl<F> ItemDecorator for F
     }
 }
 
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemModifier")]
 pub trait ItemModifier {
     fn expand(&self,
               ecx: &mut ExtCtxt,
@@ -61,9 +68,13 @@ pub trait ItemModifier {
               -> P<ast::Item>;
 }
 
+#[allow(deprecated)]
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemModifier")]
 impl<F> ItemModifier for F
     where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, P<ast::Item>) -> P<ast::Item>
 {
+
     fn expand(&self,
               ecx: &mut ExtCtxt,
               span: Span,
@@ -127,6 +138,29 @@ impl Annotatable {
     }
 }
 
+// A more flexible ItemDecorator.
+pub trait MultiItemDecorator {
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              sp: Span,
+              meta_item: &ast::MetaItem,
+              item: &Annotatable,
+              push: Box<FnMut(Annotatable)>);
+}
+
+impl<F> MultiItemDecorator for F
+    where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &Annotatable, Box<FnMut(Annotatable)>)
+{
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              sp: Span,
+              meta_item: &ast::MetaItem,
+              item: &Annotatable,
+              push: Box<FnMut(Annotatable)>) {
+        (*self)(ecx, sp, meta_item, item, push)
+    }
+}
+
 // A more flexible ItemModifier (ItemModifier should go away, eventually, FIXME).
 // meta_item is the annotation, item is the item being modified, parent_item
 // is the impl or trait item is declared in if item is part of such a thing.
@@ -397,12 +431,20 @@ impl MacResult for DummyResult {
 pub enum SyntaxExtension {
     /// A syntax extension that is attached to an item and creates new items
     /// based upon it.
-    ///
-    /// `#[derive(...)]` is an `ItemDecorator`.
+    #[unstable(feature = "rustc_private")]
+    #[deprecated(since = "1.0.0", reason = "replaced by MultiDecorator")]
     Decorator(Box<ItemDecorator + 'static>),
 
+    /// A syntax extension that is attached to an item and creates new items
+    /// based upon it.
+    ///
+    /// `#[derive(...)]` is a `MultiItemDecorator`.
+    MultiDecorator(Box<MultiItemDecorator + 'static>),
+
     /// A syntax extension that is attached to an item and modifies it
     /// in-place.
+    #[unstable(feature = "rustc_private")]
+    #[deprecated(since = "1.0.0", reason = "replaced by MultiModifier")]
     Modifier(Box<ItemModifier + 'static>),
 
     /// A syntax extension that is attached to an item and modifies it
@@ -473,6 +515,13 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
     syntax_expanders.insert(intern("log_syntax"),
                             builtin_normal_expander(
                                     ext::log_syntax::expand_syntax_ext));
+<<<<<<< HEAD
+=======
+    syntax_expanders.insert(intern("derive"),
+                            MultiDecorator(box ext::deriving::expand_meta_derive));
+    syntax_expanders.insert(intern("deriving"),
+                            MultiDecorator(box ext::deriving::expand_deprecated_deriving));
+>>>>>>> 143f2db3174103e459218958f567985b1f47944b
 
     ext::deriving::register_all(&mut syntax_expanders);
 
@@ -537,6 +586,11 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
     syntax_expanders.insert(intern("cfg"),
                             builtin_normal_expander(
                                     ext::cfg::expand_cfg));
+<<<<<<< HEAD
+=======
+    syntax_expanders.insert(intern("cfg_attr"),
+                            MultiModifier(box ext::cfg_attr::expand));
+>>>>>>> 143f2db3174103e459218958f567985b1f47944b
     syntax_expanders.insert(intern("trace_macros"),
                             builtin_normal_expander(
                                     ext::trace_macros::expand_trace_macros));
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index a3725355840..586e73ad645 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -13,9 +13,9 @@
 //! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
 //! the standard library, and "std" is the core library.
 
-use ast::{Item, MetaItem, MetaWord};
+use ast::{Item, MetaItem, MetaWord, MetaList, MetaNameValue};
 use attr::AttrMetaMethods;
-use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier};
+use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier, Annotatable};
 use ext::build::AstBuilder;
 use feature_gate;
 use codemap::Span;
@@ -78,9 +78,19 @@ pub mod ord;
 pub mod generic;
 
 fn expand_derive(cx: &mut ExtCtxt,
-                 _: Span,
+                 span: Span,
                  mitem: &MetaItem,
-                 item: P<Item>) -> P<Item> {
+                 annotatable: &Annotatable)
+                 -> P<Annotatable> {
+    // Derive can only be applied to items
+    let item = match annotatable {
+        &Annotatable::Item(ref it) => it.clone(),
+        _ => {
+            cx.span_err(span, "`derive` can only be applied to items");
+            return;
+        }
+    };
+
     item.map(|mut item| {
         if mitem.value_str().is_some() {
             cx.span_err(mitem.span, "unexpected value in `derive`");
@@ -113,7 +123,7 @@ fn expand_derive(cx: &mut ExtCtxt,
                 intern_and_get_ident(&format!("derive_{}", tname)))));
         }
 
-        item
+        Annotatable::Item(item)
     })
 }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d1db956adb3..76a4ef2f4ed 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -477,6 +477,7 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
         .into_iter().map(|i| i.expect_item()).collect()
 }
 
+#[allow(deprecated)] // This is needed because the `ItemModifier` trait is used
 fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
                          -> P<ast::Item> {
     // partition the attributes into ItemModifiers and others
@@ -1082,6 +1083,7 @@ impl<'a> Folder for PatIdentRenamer<'a> {
     }
 }
 
+#[allow(deprecated)] // This is needed because the `Decorator` variant is used
 fn expand_annotatable(a: Annotatable,
                       fld: &mut MacroExpander)
                       -> SmallVector<Annotatable> {
@@ -1120,9 +1122,31 @@ fn expand_annotatable(a: Annotatable,
                     let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
                     dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
                                &mut |item| items.push(item));
-                    decorator_items.extend(
-                        items.into_iter()
-                             .flat_map(|item| expand_item(item, fld).into_iter()));
+                    decorator_items.extend(items.into_iter()
+                        .flat_map(|item| expand_item(item, fld).into_iter()
+                                                               .map(|i| Annotatable::Item(i))));
+
+                    fld.cx.bt_pop();
+                }
+                MultiDecorator(ref dec) => {
+                    attr::mark_used(attr);
+
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.get().to_string(),
+                            format: MacroAttribute,
+                            span: None
+                        }
+                    });
+
+                    // we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
+                    // but that double-mut-borrows fld
+                    let mut anns: SmallVector<Annotatable> = SmallVector::zero();
+                    dec.expand(fld.cx, attr.span, &*attr.node.value, &a,
+                               &mut |ann| anns.push(ann));
+                    decorator_items.extend(anns.into_iter()
+                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
 
                     fld.cx.bt_pop();
                 }
@@ -1184,7 +1208,7 @@ fn expand_annotatable(a: Annotatable,
         }
     };
 
-    new_items.push_all(decorator_items.into_iter().map(|i| Annotatable::Item(i)).collect());
+    new_items.push_all(decorator_items);
     new_items
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5a57e09fcff..b56ecf7ae80 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -814,7 +814,6 @@ impl<'a> State<'a> {
         word(&mut self.s, ";")
     }
 
-
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
         try!(self.hardbreak_if_not_bol());
diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs
index 5b7e52e9164..07a18354c61 100644
--- a/src/test/auxiliary/macro_crate_test.rs
+++ b/src/test/auxiliary/macro_crate_test.rs
@@ -19,8 +19,7 @@ extern crate rustc;
 use syntax::ast::{self, TokenTree, Item, MetaItem};
 use syntax::codemap::Span;
 use syntax::ext::base::*;
-use syntax::parse::token;
-use syntax::parse;
+use syntax::parse::{self, token};
 use syntax::ptr::P;
 use rustc::plugin::Registry;
 
@@ -42,6 +41,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
         token::intern("into_multi_foo"),
         // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
         MultiModifier(Box::new(expand_into_foo_multi)));
+    reg.register_syntax_extension(
+        token::intern("duplicate"),
+        MultiDecorator(box expand_duplicate));
 }
 
 fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
@@ -104,6 +106,83 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
     }
 }
 
+// Create a duplicate of the annotatable, based on the MetaItem
+fn expand_duplicate(cx: &mut ExtCtxt,
+                    sp: Span,
+                    mi: &MetaItem,
+                    it: &Annotatable,
+                    mut push: Box<FnMut(Annotatable)>)
+{
+    let copy_name = match mi.node {
+        ast::MetaItem_::MetaList(_, ref xs) => {
+            if let ast::MetaItem_::MetaWord(ref w) = xs[0].node {
+                token::str_to_ident(w.get())
+            } else {
+                cx.span_err(mi.span, "Expected word");
+                return;
+            }
+        }
+        _ => {
+            cx.span_err(mi.span, "Expected list");
+            return;
+        }
+    };
+
+    // Duplicate the item but replace its ident by the MetaItem
+    match it.clone() {
+        Annotatable::Item(it) => {
+            let mut new_it = (*it).clone();
+            new_it.attrs.clear();
+            new_it.ident = copy_name;
+            push(Annotatable::Item(P(new_it)));
+        }
+        Annotatable::ImplItem(it) => {
+            match it {
+                ImplItem::MethodImplItem(m) => {
+                    let mut new_m = (*m).clone();
+                    new_m.attrs.clear();
+                    replace_method_name(&mut new_m.node, copy_name);
+                    push(Annotatable::ImplItem(ImplItem::MethodImplItem(P(new_m))));
+                }
+                ImplItem::TypeImplItem(t) => {
+                    let mut new_t = (*t).clone();
+                    new_t.attrs.clear();
+                    new_t.ident = copy_name;
+                    push(Annotatable::ImplItem(ImplItem::TypeImplItem(P(new_t))));
+                }
+            }
+        }
+        Annotatable::TraitItem(it) => {
+            match it {
+                TraitItem::RequiredMethod(rm) => {
+                    let mut new_rm = rm.clone();
+                    new_rm.attrs.clear();
+                    new_rm.ident = copy_name;
+                    push(Annotatable::TraitItem(TraitItem::RequiredMethod(new_rm)));
+                }
+                TraitItem::ProvidedMethod(pm) => {
+                    let mut new_pm = (*pm).clone();
+                    new_pm.attrs.clear();
+                    replace_method_name(&mut new_pm.node, copy_name);
+                    push(Annotatable::TraitItem(TraitItem::ProvidedMethod(P(new_pm))));
+                }
+                TraitItem::TypeTraitItem(t) => {
+                    let mut new_t = (*t).clone();
+                    new_t.attrs.clear();
+                    new_t.ty_param.ident = copy_name;
+                    push(Annotatable::TraitItem(TraitItem::TypeTraitItem(P(new_t))));
+                }
+            }
+        }
+    }
+
+    fn replace_method_name(m: &mut ast::Method_, i: ast::Ident) {
+        if let &mut ast::Method_::MethDecl(ref mut ident, _, _, _, _, _, _, _) = m {
+            *ident = i
+        }
+    }
+}
+
 fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
     use syntax::ext::quote::rt::*;
 
diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs
new file mode 100644
index 00000000000..45341d12d07
--- /dev/null
+++ b/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs
@@ -0,0 +1,52 @@
+// Copyright 2013-2015 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.
+
+// aux-build:macro_crate_test.rs
+// ignore-stage1
+
+#![feature(plugin)]
+
+#[plugin] #[no_link]
+extern crate macro_crate_test;
+
+// The duplicate macro will create a copy of the item with the given identifier
+#[duplicate(MyCopy)]
+struct MyStruct {
+    number: i32
+}
+
+trait TestTrait {
+    #[duplicate(TestType2)]
+    type TestType;
+
+    #[duplicate(required_fn2)]
+    fn required_fn(&self);
+
+    #[duplicate(provided_fn2)]
+    fn provided_fn(&self) { }
+}
+
+impl TestTrait for MyStruct {
+    #[duplicate(TestType2)]
+    type TestType = f64;
+
+    #[duplicate(required_fn2)]
+    fn required_fn(&self) { }
+}
+
+fn main() {
+    let s = MyStruct { number: 42 };
+    s.required_fn();
+    s.required_fn2();
+    s.provided_fn();
+    s.provided_fn2();
+
+    let s = MyCopy { number: 42 };
+}