]> git.lizzy.rs Git - rust.git/commitdiff
Pass the #[plugin(...)] meta item to the registrar
authorKeegan McAllister <kmcallister@mozilla.com>
Sat, 3 Jan 2015 02:26:00 +0000 (18:26 -0800)
committerKeegan McAllister <kmcallister@mozilla.com>
Tue, 6 Jan 2015 02:21:14 +0000 (18:21 -0800)
src/librustc/plugin/load.rs
src/librustc/plugin/registry.rs
src/librustc_driver/driver.rs
src/test/auxiliary/plugin_args.rs [new file with mode: 0644]
src/test/compile-fail/multi-plugin-attr.rs [new file with mode: 0644]
src/test/run-pass/plugin-args-1.rs [new file with mode: 0644]
src/test/run-pass/plugin-args-2.rs [new file with mode: 0644]
src/test/run-pass/plugin-args-3.rs [new file with mode: 0644]
src/test/run-pass/plugin-args-4.rs [new file with mode: 0644]

index 3a9083828fc703148dab8fd6b6731668a7e39b37..64a5a02b34b47777a7463446a8ed8676e33ebd22 100644 (file)
@@ -21,6 +21,7 @@
 use syntax::ast;
 use syntax::attr;
 use syntax::parse::token;
+use syntax::ptr::P;
 use syntax::visit;
 use syntax::visit::Visitor;
 use syntax::attr::AttrMetaMethods;
 pub type PluginRegistrarFun =
     fn(&mut Registry);
 
+pub struct PluginRegistrar {
+    pub fun: PluginRegistrarFun,
+    pub args: P<ast::MetaItem>,
+}
+
 /// Information about loaded plugins.
 pub struct Plugins {
     /// Imported macros.
     pub macros: Vec<ast::MacroDef>,
     /// Registrars, as function pointers.
-    pub registrars: Vec<PluginRegistrarFun>,
+    pub registrars: Vec<PluginRegistrar>,
 }
 
 struct PluginLoader<'a> {
@@ -87,7 +93,7 @@ fn visit_view_item(&mut self, vi: &ast::ViewItem) {
         }
 
         // Parse the attributes relating to macro / plugin loading.
-        let mut load_registrar = false;
+        let mut plugin_attr = None;
         let mut macro_selection = Some(HashSet::new());  // None => load all
         let mut reexport = HashSet::new();
         for attr in vi.attrs.iter() {
@@ -97,7 +103,12 @@ fn visit_view_item(&mut self, vi: &ast::ViewItem) {
                     self.sess.span_err(attr.span, "#[phase] is deprecated; use \
                                        #[macro_use], #[plugin], and/or #[no_link]");
                 }
-                "plugin" => load_registrar = true,
+                "plugin" => {
+                    if plugin_attr.is_some() {
+                        self.sess.span_err(attr.span, "#[plugin] specified multiple times");
+                    }
+                    plugin_attr = Some(attr.node.value.clone());
+                }
                 "macro_use" => {
                     let names = attr.meta_item_list();
                     if names.is_none() {
@@ -145,6 +156,7 @@ fn visit_view_item(&mut self, vi: &ast::ViewItem) {
             Some(sel) => sel.len() != 0 || reexport.len() != 0,
             None => true,
         };
+        let load_registrar = plugin_attr.is_some();
 
         if load_macros || load_registrar {
             let pmd = self.reader.read_plugin_metadata(vi);
@@ -167,7 +179,11 @@ fn visit_view_item(&mut self, vi: &ast::ViewItem) {
         }
 
         if let Some((lib, symbol)) = registrar {
-            self.dylink_registrar(vi, lib, symbol);
+            let fun = self.dylink_registrar(vi, lib, symbol);
+            self.plugins.registrars.push(PluginRegistrar {
+                fun: fun,
+                args: plugin_attr.unwrap(),
+            });
         }
     }
 
@@ -179,7 +195,10 @@ fn visit_mac(&mut self, _: &ast::Mac) {
 
 impl<'a> PluginLoader<'a> {
     // Dynamically link a registrar function into the compiler process.
-    fn dylink_registrar(&mut self, vi: &ast::ViewItem, path: Path, symbol: String) {
+    fn dylink_registrar(&mut self,
+                        vi: &ast::ViewItem,
+                        path: Path,
+                        symbol: String) -> PluginRegistrarFun {
         // Make sure the path contains a / or the linker will search for it.
         let path = os::make_absolute(&path).unwrap();
 
@@ -201,13 +220,12 @@ fn dylink_registrar(&mut self, vi: &ast::ViewItem, path: Path, symbol: String) {
                     Err(err) => self.sess.span_fatal(vi.span, err[])
                 };
 
-            self.plugins.registrars.push(registrar);
-
             // Intentionally leak the dynamic library. We can't ever unload it
             // since the library can make things that will live arbitrarily long
             // (e.g. an @-box cycle or a task).
             mem::forget(lib);
 
+            registrar
         }
     }
 }
index c5550902f19895aba6efdd5f8254fbef3503a93a..feec97f02da55dd204399f7bdf39066605298934 100644 (file)
@@ -18,6 +18,7 @@
 use syntax::ext::base::{MacroExpanderFn};
 use syntax::codemap::Span;
 use syntax::parse::token;
+use syntax::ptr::P;
 use syntax::ast;
 
 use std::collections::HashMap;
@@ -35,6 +36,9 @@ pub struct Registry<'a> {
     /// from the plugin registrar.
     pub sess: &'a Session,
 
+    #[doc(hidden)]
+    pub args_hidden: Option<P<ast::MetaItem>>,
+
     #[doc(hidden)]
     pub krate_span: Span,
 
@@ -53,6 +57,7 @@ impl<'a> Registry<'a> {
     pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
         Registry {
             sess: sess,
+            args_hidden: None,
             krate_span: krate.span,
             syntax_exts: vec!(),
             lint_passes: vec!(),
@@ -60,6 +65,14 @@ pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
         }
     }
 
+    /// Get the `#[plugin]` attribute used to load this plugin.
+    ///
+    /// This gives access to arguments passed via `#[plugin=...]` or
+    /// `#[plugin(...)]`.
+    pub fn args<'b>(&'b self) -> &'b P<ast::MetaItem> {
+        self.args_hidden.as_ref().expect("args not set")
+    }
+
     /// Register a syntax extension of any kind.
     ///
     /// This is the most general hook into `libsyntax`'s expansion behavior.
index 261d73b5bf07ac42af9dcd635c4b8b93460606a3..c88ffffecc32d5b9a4e88ab1c35ef46acc9dae15 100644 (file)
@@ -218,7 +218,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
 
     let mut registry = Registry::new(sess, &krate);
 
-    time(time_passes, "plugin registration", (), |_| {
+    time(time_passes, "plugin registration", registrars, |registrars| {
         if sess.features.borrow().rustc_diagnostic_macros {
             registry.register_macro("__diagnostic_used",
                 diagnostics::plugin::expand_diagnostic_used);
@@ -228,8 +228,9 @@ pub fn phase_2_configure_and_expand(sess: &Session,
                 diagnostics::plugin::expand_build_diagnostic_array);
         }
 
-        for &registrar in registrars.iter() {
-            registrar(&mut registry);
+        for registrar in registrars.into_iter() {
+            registry.args_hidden = Some(registrar.args);
+            (registrar.fun)(&mut registry);
         }
     });
 
diff --git a/src/test/auxiliary/plugin_args.rs b/src/test/auxiliary/plugin_args.rs
new file mode 100644 (file)
index 0000000..b90c3f1
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 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.
+
+// force-host
+
+#![feature(plugin_registrar)]
+
+extern crate syntax;
+extern crate rustc;
+
+use std::borrow::ToOwned;
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacExpr, NormalTT};
+use syntax::parse::token;
+use syntax::print::pprust;
+use syntax::ptr::P;
+use rustc::plugin::Registry;
+
+struct Expander {
+    args: P<ast::MetaItem>,
+}
+
+impl TTMacroExpander for Expander {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   sp: Span,
+                   _: &[ast::TokenTree]) -> Box<MacResult+'cx> {
+
+        let attr = ecx.attribute(sp, self.args.clone());
+        let src = pprust::attribute_to_string(&attr);
+        let interned = token::intern_and_get_ident(src.as_slice());
+        MacExpr::new(ecx.expr_str(sp, interned))
+    }
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+    let args = reg.args().clone();
+    reg.register_syntax_extension(token::intern("plugin_args"),
+        NormalTT(box Expander { args: args, }, None));
+}
diff --git a/src/test/compile-fail/multi-plugin-attr.rs b/src/test/compile-fail/multi-plugin-attr.rs
new file mode 100644 (file)
index 0000000..1d98cd2
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 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.
+
+#[plugin]
+#[plugin]  //~ ERROR #[plugin] specified multiple times
+extern crate std;
+
+fn main() {}
diff --git a/src/test/run-pass/plugin-args-1.rs b/src/test/run-pass/plugin-args-1.rs
new file mode 100644 (file)
index 0000000..5a91f60
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 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:plugin_args.rs
+// ignore-stage1
+
+#![feature(plugin)]
+
+#[no_link]
+#[plugin]
+extern crate plugin_args;
+
+fn main() {
+    assert_eq!(plugin_args!(), "#[plugin]");
+}
diff --git a/src/test/run-pass/plugin-args-2.rs b/src/test/run-pass/plugin-args-2.rs
new file mode 100644 (file)
index 0000000..d0ac22a
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 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:plugin_args.rs
+// ignore-stage1
+
+#![feature(plugin)]
+
+#[no_link]
+#[plugin()]
+extern crate plugin_args;
+
+fn main() {
+    assert_eq!(plugin_args!(), "#[plugin()]");
+}
diff --git a/src/test/run-pass/plugin-args-3.rs b/src/test/run-pass/plugin-args-3.rs
new file mode 100644 (file)
index 0000000..7cac8ac
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 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:plugin_args.rs
+// ignore-stage1
+
+#![feature(plugin)]
+
+#[no_link]
+#[plugin(hello(there), how(are="you"))]
+extern crate plugin_args;
+
+fn main() {
+    assert_eq!(plugin_args!(), "#[plugin(hello(there), how(are = \"you\"))]");
+}
diff --git a/src/test/run-pass/plugin-args-4.rs b/src/test/run-pass/plugin-args-4.rs
new file mode 100644 (file)
index 0000000..8563c8c
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 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:plugin_args.rs
+// ignore-stage1
+
+#![feature(plugin)]
+
+#[no_link]
+#[plugin="foobar"]
+extern crate plugin_args;
+
+fn main() {
+    assert_eq!(plugin_args!(), "#[plugin = \"foobar\"]");
+}