about summary refs log tree commit diff
path: root/src/librustc_plugin
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2015-11-22 22:14:09 +0200
committerAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2015-11-26 18:22:39 +0200
commit1430a3500076ad504a0b30be77fd2ad4468ea769 (patch)
tree61739ffce74c80568a634852a4b09b5ec689d365 /src/librustc_plugin
parent26b19206d34f578a8eae658ece59990d8abb43ba (diff)
downloadrust-1430a3500076ad504a0b30be77fd2ad4468ea769.tar.gz
rust-1430a3500076ad504a0b30be77fd2ad4468ea769.zip
move librustc/plugin to librustc_plugin
this is a [breaking-change] to all plugin authors - sorry
Diffstat (limited to 'src/librustc_plugin')
-rw-r--r--src/librustc_plugin/build.rs57
-rw-r--r--src/librustc_plugin/diagnostics.rs19
-rw-r--r--src/librustc_plugin/lib.rs80
-rw-r--r--src/librustc_plugin/load.rs146
-rw-r--r--src/librustc_plugin/registry.rs155
5 files changed, 457 insertions, 0 deletions
diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs
new file mode 100644
index 00000000000..00f58c6af91
--- /dev/null
+++ b/src/librustc_plugin/build.rs
@@ -0,0 +1,57 @@
+// Copyright 2012-2013 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.
+
+//! Used by `rustc` when compiling a plugin crate.
+
+use syntax::ast;
+use syntax::attr;
+use syntax::codemap::Span;
+use syntax::diagnostic;
+use rustc_front::intravisit::Visitor;
+use rustc_front::hir;
+
+struct RegistrarFinder {
+    registrars: Vec<(ast::NodeId, Span)> ,
+}
+
+impl<'v> Visitor<'v> for RegistrarFinder {
+    fn visit_item(&mut self, item: &hir::Item) {
+        if let hir::ItemFn(..) = item.node {
+            if attr::contains_name(&item.attrs,
+                                   "plugin_registrar") {
+                self.registrars.push((item.id, item.span));
+            }
+        }
+    }
+}
+
+/// Find the function marked with `#[plugin_registrar]`, if any.
+pub fn find_plugin_registrar(diagnostic: &diagnostic::SpanHandler,
+                             krate: &hir::Crate)
+                             -> Option<ast::NodeId> {
+    let mut finder = RegistrarFinder { registrars: Vec::new() };
+    krate.visit_all_items(&mut finder);
+
+    match finder.registrars.len() {
+        0 => None,
+        1 => {
+            let (node_id, _) = finder.registrars.pop().unwrap();
+            Some(node_id)
+        },
+        _ => {
+            diagnostic.handler().err("multiple plugin registration functions found");
+            for &(_, span) in &finder.registrars {
+                diagnostic.span_note(span, "one is here");
+            }
+            diagnostic.handler().abort_if_errors();
+            unreachable!();
+        }
+    }
+}
diff --git a/src/librustc_plugin/diagnostics.rs b/src/librustc_plugin/diagnostics.rs
new file mode 100644
index 00000000000..100c1db1439
--- /dev/null
+++ b/src/librustc_plugin/diagnostics.rs
@@ -0,0 +1,19 @@
+// 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.
+
+#![allow(non_snake_case)]
+
+register_long_diagnostics! {
+
+}
+
+register_diagnostics! {
+    E0498  // malformed plugin attribute
+}
diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs
new file mode 100644
index 00000000000..33d63d833c7
--- /dev/null
+++ b/src/librustc_plugin/lib.rs
@@ -0,0 +1,80 @@
+// Copyright 2012-2013 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.
+
+//! Infrastructure for compiler plugins.
+//!
+//! Plugins are Rust libraries which extend the behavior of `rustc`
+//! in various ways.
+//!
+//! Plugin authors will use the `Registry` type re-exported by
+//! this module, along with its methods.  The rest of the module
+//! is for use by `rustc` itself.
+//!
+//! To define a plugin, build a dylib crate with a
+//! `#[plugin_registrar]` function:
+//!
+//! ```rust,ignore
+//! #![crate_name = "myplugin"]
+//! #![crate_type = "dylib"]
+//! #![feature(plugin_registrar)]
+//!
+//! extern crate rustc;
+//!
+//! use rustc::plugin::Registry;
+//!
+//! #[plugin_registrar]
+//! pub fn plugin_registrar(reg: &mut Registry) {
+//!     reg.register_macro("mymacro", expand_mymacro);
+//! }
+//!
+//! fn expand_mymacro(...) {  // details elided
+//! ```
+//!
+//! WARNING: We currently don't check that the registrar function
+//! has the appropriate type!
+//!
+//! To use a plugin while compiling another crate:
+//!
+//! ```rust
+//! #![feature(plugin)]
+//! #![plugin(myplugin)]
+//! ```
+//!
+//! See the [Plugins Chapter](../../book/compiler-plugins.html) of the book
+//! for more examples.
+
+#![cfg_attr(stage0, feature(custom_attribute))]
+#![crate_name = "rustc_plugin"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![cfg_attr(stage0, staged_api)]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+      html_root_url = "https://doc.rust-lang.org/nightly/")]
+
+#![feature(dynamic_lib)]
+#![feature(staged_api)]
+#![feature(rustc_diagnostic_macros)]
+#![feature(rustc_private)]
+
+#[macro_use] extern crate log;
+#[macro_use] extern crate syntax;
+#[macro_use] #[no_link] extern crate rustc_bitflags;
+
+extern crate rustc;
+extern crate rustc_front;
+
+pub use self::registry::Registry;
+
+pub mod diagnostics;
+pub mod registry;
+pub mod load;
+pub mod build;
diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs
new file mode 100644
index 00000000000..d121a306c61
--- /dev/null
+++ b/src/librustc_plugin/load.rs
@@ -0,0 +1,146 @@
+// Copyright 2012-2013 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.
+
+//! Used by `rustc` when loading a plugin.
+
+use rustc::session::Session;
+use rustc::metadata::creader::CrateReader;
+use rustc::metadata::cstore::CStore;
+use registry::Registry;
+
+use std::borrow::ToOwned;
+use std::env;
+use std::mem;
+use std::path::PathBuf;
+use syntax::ast;
+use syntax::codemap::{Span, COMMAND_LINE_SP};
+use syntax::ptr::P;
+use syntax::attr::AttrMetaMethods;
+
+/// Pointer to a registrar function.
+pub type PluginRegistrarFun =
+    fn(&mut Registry);
+
+pub struct PluginRegistrar {
+    pub fun: PluginRegistrarFun,
+    pub args: Vec<P<ast::MetaItem>>,
+}
+
+struct PluginLoader<'a> {
+    sess: &'a Session,
+    reader: CrateReader<'a>,
+    plugins: Vec<PluginRegistrar>,
+}
+
+fn call_malformed_plugin_attribute(a: &Session, b: Span) {
+    span_err!(a, b, E0498, "malformed plugin attribute");
+}
+
+/// Read plugin metadata and dynamically load registrar functions.
+pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate,
+                    addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
+    let mut loader = PluginLoader::new(sess, cstore);
+
+    for attr in &krate.attrs {
+        if !attr.check_name("plugin") {
+            continue;
+        }
+
+        let plugins = match attr.meta_item_list() {
+            Some(xs) => xs,
+            None => {
+                call_malformed_plugin_attribute(sess, attr.span);
+                continue;
+            }
+        };
+
+        for plugin in plugins {
+            if plugin.value_str().is_some() {
+                call_malformed_plugin_attribute(sess, attr.span);
+                continue;
+            }
+
+            let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
+            loader.load_plugin(plugin.span, &*plugin.name(), args);
+        }
+    }
+
+    if let Some(plugins) = addl_plugins {
+        for plugin in plugins {
+            loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]);
+        }
+    }
+
+    loader.plugins
+}
+
+impl<'a> PluginLoader<'a> {
+    fn new(sess: &'a Session, cstore: &'a CStore) -> PluginLoader<'a> {
+        PluginLoader {
+            sess: sess,
+            reader: CrateReader::new(sess, cstore),
+            plugins: vec![],
+        }
+    }
+
+    fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
+        let registrar = self.reader.find_plugin_registrar(span, name);
+
+        if let Some((lib, symbol)) = registrar {
+            let fun = self.dylink_registrar(span, lib, symbol);
+            self.plugins.push(PluginRegistrar {
+                fun: fun,
+                args: args,
+            });
+        }
+    }
+
+    // Dynamically link a registrar function into the compiler process.
+    #[allow(deprecated)]
+    fn dylink_registrar(&mut self,
+                        span: Span,
+                        path: PathBuf,
+                        symbol: String) -> PluginRegistrarFun {
+        use std::dynamic_lib::DynamicLibrary;
+
+        // Make sure the path contains a / or the linker will search for it.
+        let path = env::current_dir().unwrap().join(&path);
+
+        let lib = match DynamicLibrary::open(Some(&path)) {
+            Ok(lib) => lib,
+            // this is fatal: there are almost certainly macros we need
+            // inside this crate, so continue would spew "macro undefined"
+            // errors
+            Err(err) => {
+                self.sess.span_fatal(span, &err[..])
+            }
+        };
+
+        unsafe {
+            let registrar =
+                match lib.symbol(&symbol[..]) {
+                    Ok(registrar) => {
+                        mem::transmute::<*mut u8,PluginRegistrarFun>(registrar)
+                    }
+                    // again fatal if we can't register macros
+                    Err(err) => {
+                        self.sess.span_fatal(span, &err[..])
+                    }
+                };
+
+            // 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 thread).
+            mem::forget(lib);
+
+            registrar
+        }
+    }
+}
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
new file mode 100644
index 00000000000..3138d7fa1db
--- /dev/null
+++ b/src/librustc_plugin/registry.rs
@@ -0,0 +1,155 @@
+// Copyright 2012-2013 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.
+
+//! Used by plugin crates to tell `rustc` about the plugins they provide.
+
+use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
+use rustc::session::Session;
+
+use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
+use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
+use syntax::ext::base::{MacroExpanderFn, MacroRulesTT};
+use syntax::codemap::Span;
+use syntax::parse::token;
+use syntax::ptr::P;
+use syntax::ast;
+use syntax::feature_gate::AttributeType;
+
+use std::collections::HashMap;
+use std::borrow::ToOwned;
+
+/// Structure used to register plugins.
+///
+/// A plugin registrar function takes an `&mut Registry` and should call
+/// methods to register its plugins.
+///
+/// This struct has public fields and other methods for use by `rustc`
+/// itself. They are not documented here, and plugin authors should
+/// not use them.
+pub struct Registry<'a> {
+    /// Compiler session. Useful if you want to emit diagnostic messages
+    /// from the plugin registrar.
+    pub sess: &'a Session,
+
+    #[doc(hidden)]
+    pub args_hidden: Option<Vec<P<ast::MetaItem>>>,
+
+    #[doc(hidden)]
+    pub krate_span: Span,
+
+    #[doc(hidden)]
+    pub syntax_exts: Vec<NamedSyntaxExtension>,
+
+    #[doc(hidden)]
+    pub early_lint_passes: Vec<EarlyLintPassObject>,
+
+    #[doc(hidden)]
+    pub late_lint_passes: Vec<LateLintPassObject>,
+
+    #[doc(hidden)]
+    pub lint_groups: HashMap<&'static str, Vec<LintId>>,
+
+    #[doc(hidden)]
+    pub llvm_passes: Vec<String>,
+
+    #[doc(hidden)]
+    pub attributes: Vec<(String, AttributeType)>,
+}
+
+impl<'a> Registry<'a> {
+    #[doc(hidden)]
+    pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
+        Registry {
+            sess: sess,
+            args_hidden: None,
+            krate_span: krate.span,
+            syntax_exts: vec!(),
+            early_lint_passes: vec!(),
+            late_lint_passes: vec!(),
+            lint_groups: HashMap::new(),
+            llvm_passes: vec!(),
+            attributes: vec!(),
+        }
+    }
+
+    /// Get the plugin's arguments, if any.
+    ///
+    /// These are specified inside the `plugin` crate attribute as
+    ///
+    /// ```no_run
+    /// #![plugin(my_plugin_name(... args ...))]
+    /// ```
+    pub fn args<'b>(&'b self) -> &'b Vec<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.
+    pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
+        self.syntax_exts.push((name, match extension {
+            NormalTT(ext, _, allow_internal_unstable) => {
+                NormalTT(ext, Some(self.krate_span), allow_internal_unstable)
+            }
+            IdentTT(ext, _, allow_internal_unstable) => {
+                IdentTT(ext, Some(self.krate_span), allow_internal_unstable)
+            }
+            MultiDecorator(ext) => MultiDecorator(ext),
+            MultiModifier(ext) => MultiModifier(ext),
+            MacroRulesTT => {
+                self.sess.err("plugin tried to register a new MacroRulesTT");
+                return;
+            }
+        }));
+    }
+
+    /// Register a macro of the usual kind.
+    ///
+    /// This is a convenience wrapper for `register_syntax_extension`.
+    /// It builds for you a `NormalTT` that calls `expander`,
+    /// and also takes care of interning the macro's name.
+    pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
+        self.register_syntax_extension(token::intern(name),
+                                       NormalTT(Box::new(expander), None, false));
+    }
+
+    /// Register a compiler lint pass.
+    pub fn register_early_lint_pass(&mut self, lint_pass: EarlyLintPassObject) {
+        self.early_lint_passes.push(lint_pass);
+    }
+
+    /// Register a compiler lint pass.
+    pub fn register_late_lint_pass(&mut self, lint_pass: LateLintPassObject) {
+        self.late_lint_passes.push(lint_pass);
+    }
+    /// Register a lint group.
+    pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) {
+        self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect());
+    }
+
+    /// Register an LLVM pass.
+    ///
+    /// Registration with LLVM itself is handled through static C++ objects with
+    /// constructors. This method simply adds a name to the list of passes to
+    /// execute.
+    pub fn register_llvm_pass(&mut self, name: &str) {
+        self.llvm_passes.push(name.to_owned());
+    }
+
+
+    /// Register an attribute with an attribute type.
+    ///
+    /// Registered attributes will bypass the `custom_attribute` feature gate.
+    /// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
+    /// lint. `CrateLevel` attributes will not be allowed on anything other than a crate.
+    pub fn register_attribute(&mut self, name: String, ty: AttributeType) {
+        self.attributes.push((name, ty));
+    }
+}