Pass the #[plugin(...)] meta item to the registrar
This commit is contained in:
parent
416137eb31
commit
d0163d3311
@ -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;
|
||||
@ -29,12 +30,17 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 ®istrar in registrars.iter() {
|
||||
registrar(&mut registry);
|
||||
for registrar in registrars.into_iter() {
|
||||
registry.args_hidden = Some(registrar.args);
|
||||
(registrar.fun)(&mut registry);
|
||||
}
|
||||
});
|
||||
|
||||
|
50
src/test/auxiliary/plugin_args.rs
Normal file
50
src/test/auxiliary/plugin_args.rs
Normal file
@ -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));
|
||||
}
|
15
src/test/compile-fail/multi-plugin-attr.rs
Normal file
15
src/test/compile-fail/multi-plugin-attr.rs
Normal file
@ -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() {}
|
22
src/test/run-pass/plugin-args-1.rs
Normal file
22
src/test/run-pass/plugin-args-1.rs
Normal file
@ -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]");
|
||||
}
|
22
src/test/run-pass/plugin-args-2.rs
Normal file
22
src/test/run-pass/plugin-args-2.rs
Normal file
@ -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()]");
|
||||
}
|
22
src/test/run-pass/plugin-args-3.rs
Normal file
22
src/test/run-pass/plugin-args-3.rs
Normal file
@ -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\"))]");
|
||||
}
|
22
src/test/run-pass/plugin-args-4.rs
Normal file
22
src/test/run-pass/plugin-args-4.rs
Normal file
@ -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\"]");
|
||||
}
|
Loading…
Reference in New Issue
Block a user