Pass the #[plugin(...)] meta item to the registrar

This commit is contained in:
Keegan McAllister 2015-01-02 18:26:00 -08:00
parent 416137eb31
commit d0163d3311
9 changed files with 195 additions and 10 deletions

View 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;
@ -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
}
}
}

View 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.

View 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);
}
});

View 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));
}

View 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() {}

View 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]");
}

View 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()]");
}

View 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\"))]");
}

View 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\"]");
}