Skip to content

Commit

Permalink
Pass the #[plugin(...)] meta item to the registrar
Browse files Browse the repository at this point in the history
  • Loading branch information
Keegan McAllister committed Jan 6, 2015
1 parent 416137e commit d0163d3
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 10 deletions.
32 changes: 25 additions & 7 deletions src/librustc/plugin/load.rs
Expand Up @@ -21,6 +21,7 @@ use std::collections::HashSet;
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;
Expand All @@ -29,12 +30,17 @@ 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> {
Expand Down Expand Up @@ -87,7 +93,7 @@ impl<'a, 'v> Visitor<'v> for 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() {
Expand All @@ -97,7 +103,12 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
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() {
Expand Down Expand Up @@ -145,6 +156,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
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);
Expand All @@ -167,7 +179,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
}

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(),
});
}
}

Expand All @@ -179,7 +195,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {

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();

Expand All @@ -201,13 +220,12 @@ impl<'a> PluginLoader<'a> {
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
}
}
}
13 changes: 13 additions & 0 deletions src/librustc/plugin/registry.rs
Expand Up @@ -18,6 +18,7 @@ use syntax::ext::base::{IdentTT, Decorator, Modifier, MacroRulesTT};
use syntax::ext::base::{MacroExpanderFn};
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ast;

use std::collections::HashMap;
Expand All @@ -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,

Expand All @@ -53,13 +57,22 @@ 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!(),
lint_groups: HashMap::new(),
}
}

/// 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.
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_driver/driver.rs
Expand Up @@ -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);
Expand All @@ -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);
}
});

Expand Down
50 changes: 50 additions & 0 deletions src/test/auxiliary/plugin_args.rs
@@ -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 changes: 15 additions & 0 deletions src/test/compile-fail/multi-plugin-attr.rs
@@ -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 changes: 22 additions & 0 deletions src/test/run-pass/plugin-args-1.rs
@@ -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 changes: 22 additions & 0 deletions src/test/run-pass/plugin-args-2.rs
@@ -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 changes: 22 additions & 0 deletions src/test/run-pass/plugin-args-3.rs
@@ -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 changes: 22 additions & 0 deletions src/test/run-pass/plugin-args-4.rs
@@ -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\"]");
}

0 comments on commit d0163d3

Please sign in to comment.