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> {
}
// 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() {
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() {
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);
}
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(),
+ });
}
}
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();
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
}
}
}
use syntax::ext::base::{MacroExpanderFn};
use syntax::codemap::Span;
use syntax::parse::token;
+use syntax::ptr::P;
use syntax::ast;
use std::collections::HashMap;
/// from the plugin registrar.
pub sess: &'a Session,
+ #[doc(hidden)]
+ pub args_hidden: Option<P<ast::MetaItem>>,
+
#[doc(hidden)]
pub krate_span: Span,
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!(),
}
}
+ /// 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.
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);
diagnostics::plugin::expand_build_diagnostic_array);
}
- for ®istrar in registrars.iter() {
- registrar(&mut registry);
+ for registrar in registrars.into_iter() {
+ registry.args_hidden = Some(registrar.args);
+ (registrar.fun)(&mut registry);
}
});
--- /dev/null
+// 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));
+}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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]");
+}
--- /dev/null
+// 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()]");
+}
--- /dev/null
+// 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\"))]");
+}
--- /dev/null
+// 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\"]");
+}