Implement #[plugin_registrar]

See RFC 22.

[breaking-change]
This commit is contained in:
Keegan McAllister 2014-05-24 16:16:10 -07:00
parent e55f64f997
commit 6d15c6749c
19 changed files with 331 additions and 236 deletions

View File

@ -18,12 +18,14 @@ use front;
use lib::llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
use metadata::creader;
use metadata::creader::Loader;
use middle::cfg;
use middle::cfg::graphviz::LabelledCFG;
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
use middle::dependency_format;
use middle;
use plugin::load::Plugins;
use plugin::registry::Registry;
use plugin;
use util::common::time;
use util::ppaux;
use util::nodemap::{NodeSet};
@ -39,7 +41,6 @@ use syntax::ast;
use syntax::attr;
use syntax::attr::{AttrMetaMethods};
use syntax::crateid::CrateId;
use syntax::ext::base::CrateLoader;
use syntax::parse;
use syntax::parse::token;
use syntax::print::{pp, pprust};
@ -75,11 +76,10 @@ pub fn compile_input(sess: Session,
output,
krate.attrs.as_slice(),
&sess);
let loader = &mut Loader::new(&sess);
let id = link::find_crate_id(krate.attrs.as_slice(),
outputs.out_filestem.as_slice());
let (expanded_crate, ast_map) =
phase_2_configure_and_expand(&sess, loader, krate, &id);
phase_2_configure_and_expand(&sess, krate, &id);
(outputs, expanded_crate, ast_map)
};
write_out_deps(&sess, input, &outputs, &expanded_crate);
@ -172,7 +172,6 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
/// harness if one is to be provided and injection of a dependency on the
/// standard library and prelude.
pub fn phase_2_configure_and_expand(sess: &Session,
loader: &mut CrateLoader,
mut krate: ast::Crate,
crate_id: &CrateId)
-> (ast::Crate, syntax::ast_map::Map) {
@ -197,25 +196,42 @@ pub fn phase_2_configure_and_expand(sess: &Session,
krate = time(time_passes, "configuration 1", krate, |krate|
front::config::strip_unconfigured_items(krate));
krate = time(time_passes, "expansion", krate, |krate| {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
// dependent dlls. Note that this uses cfg!(windows) as opposed to
// targ_cfg because syntax extensions are always loaded for the host
// compiler, not for the target.
if cfg!(windows) {
sess.host_filesearch().add_dylib_search_paths();
let Plugins { macros, registrars }
= time(time_passes, "plugin loading", (), |_|
plugin::load::load_plugins(sess, &krate));
let mut registry = Registry::new(&krate);
time(time_passes, "plugin registration", (), |_| {
for &registrar in registrars.iter() {
registrar(&mut registry);
}
let cfg = syntax::ext::expand::ExpansionConfig {
loader: loader,
deriving_hash_type_parameter: sess.features.default_type_params.get(),
crate_id: crate_id.clone(),
};
syntax::ext::expand::expand_crate(&sess.parse_sess,
cfg,
krate)
});
let Registry { syntax_exts, .. } = registry;
krate = time(time_passes, "expansion", (krate, macros, syntax_exts),
|(krate, macros, syntax_exts)| {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
// dependent dlls. Note that this uses cfg!(windows) as opposed to
// targ_cfg because syntax extensions are always loaded for the host
// compiler, not for the target.
if cfg!(windows) {
sess.host_filesearch().add_dylib_search_paths();
}
let cfg = syntax::ext::expand::ExpansionConfig {
deriving_hash_type_parameter: sess.features.default_type_params.get(),
crate_id: crate_id.clone(),
};
syntax::ext::expand::expand_crate(&sess.parse_sess,
cfg,
macros,
syntax_exts,
krate)
}
);
// strip again, in case expansion added anything with a #[cfg].
krate = time(time_passes, "configuration 2", krate, |krate|
front::config::strip_unconfigured_items(krate));
@ -281,9 +297,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
time(time_passes, "looking for entry point", (),
|_| middle::entry::find_entry_point(&sess, krate, &ast_map));
sess.macro_registrar_fn.set(
time(time_passes, "looking for macro registrar", (), |_|
syntax::ext::registrar::find_macro_registrar(
sess.plugin_registrar_fn.set(
time(time_passes, "looking for plugin registrar", (), |_|
plugin::build::find_plugin_registrar(
sess.diagnostic(), krate)));
let freevars = time(time_passes, "freevar finding", (), |_|
@ -596,9 +612,7 @@ pub fn pretty_print_input(sess: Session,
let (krate, ast_map, is_expanded) = match ppm {
PpmExpanded | PpmExpandedIdentified | PpmTyped | PpmFlowGraph(_) => {
let loader = &mut Loader::new(&sess);
let (krate, ast_map) = phase_2_configure_and_expand(&sess,
loader,
krate,
&id);
(krate, Some(ast_map), true)

View File

@ -36,7 +36,7 @@ pub struct Session {
// For a library crate, this is always none
pub entry_fn: RefCell<Option<(NodeId, codemap::Span)>>,
pub entry_type: Cell<Option<config::EntryFnType>>,
pub macro_registrar_fn: Cell<Option<ast::NodeId>>,
pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
pub default_sysroot: Option<Path>,
// The name of the root source file of the crate, in the local file system. The path is always
// expected to be absolute. `None` means that there is no source file.
@ -232,7 +232,7 @@ pub fn build_session_(sopts: config::Options,
// For a library crate, this is always none
entry_fn: RefCell::new(None),
entry_type: Cell::new(None),
macro_registrar_fn: Cell::new(None),
plugin_registrar_fn: Cell::new(None),
default_sysroot: default_sysroot,
local_crate_source_file: local_crate_source_file,
working_dir: os::getcwd(),

View File

@ -46,7 +46,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("thread_local", Active),
("link_args", Active),
("phase", Active),
("macro_registrar", Active),
("plugin_registrar", Active),
("log_syntax", Active),
("trace_macros", Active),
("concat_idents", Active),
@ -192,10 +192,9 @@ impl<'a> Visitor<()> for Context<'a> {
}
ast::ItemFn(..) => {
if attr::contains_name(i.attrs.as_slice(), "macro_registrar") {
self.gate_feature("macro_registrar", i.span,
"cross-crate macro exports are \
experimental and possibly buggy");
if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
self.gate_feature("plugin_registrar", i.span,
"compiler plugins are experimental and possibly buggy");
}
}

View File

@ -81,7 +81,7 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
InternedString::new("phase"),
vec!(
attr::mk_word_item(InternedString::new("syntax")),
attr::mk_word_item(InternedString::new("plugin")),
attr::mk_word_item(InternedString::new("link")
))))),
vis: ast::Inherited,

View File

@ -16,7 +16,6 @@
use driver::session::Session;
use front::config;
use front::std_inject::with_version;
use metadata::creader::Loader;
use std::cell::RefCell;
use std::slice;
@ -150,12 +149,10 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
fn generate_test_harness(sess: &Session, krate: ast::Crate)
-> ast::Crate {
let loader = &mut Loader::new(sess);
let mut cx: TestCtxt = TestCtxt {
sess: sess,
ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(),
ExpansionConfig {
loader: loader,
deriving_hash_type_parameter: false,
crate_id: from_str("test").unwrap(),
}),

View File

@ -109,6 +109,14 @@ pub mod metadata;
pub mod driver;
pub mod plugin {
pub use self::registry::Registry;
pub mod registry;
pub mod load;
pub mod build;
}
pub mod util {
pub mod common;
pub mod ppaux;

View File

@ -198,7 +198,7 @@ pub static tag_native_libraries_lib: uint = 0x88;
pub static tag_native_libraries_name: uint = 0x89;
pub static tag_native_libraries_kind: uint = 0x8a;
pub static tag_macro_registrar_fn: uint = 0x8b;
pub static tag_plugin_registrar_fn: uint = 0x8b;
pub static tag_exported_macros: uint = 0x8c;
pub static tag_macro_def: uint = 0x8d;

View File

@ -21,6 +21,7 @@ use metadata::cstore::{CStore, CrateSource};
use metadata::decoder;
use metadata::loader;
use metadata::loader::CratePaths;
use plugin::load::PluginMetadata;
use std::rc::Rc;
use std::collections::HashMap;
@ -30,7 +31,6 @@ use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::{Span};
use syntax::diagnostic::SpanHandler;
use syntax::ext::base::{CrateLoader, MacroCrate};
use syntax::parse::token::InternedString;
use syntax::parse::token;
use syntax::crateid::CrateId;
@ -379,23 +379,21 @@ fn resolve_crate_deps(e: &mut Env,
}).collect()
}
pub struct Loader<'a> {
pub struct PluginMetadataReader<'a> {
env: Env<'a>,
}
impl<'a> Loader<'a> {
pub fn new(sess: &'a Session) -> Loader<'a> {
Loader {
impl<'a> PluginMetadataReader<'a> {
pub fn new(sess: &'a Session) -> PluginMetadataReader<'a> {
PluginMetadataReader {
env: Env {
sess: sess,
next_crate_num: sess.cstore.next_crate_num(),
}
}
}
}
impl<'a> CrateLoader for Loader<'a> {
fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate {
pub fn read_plugin_metadata(&mut self, krate: &ast::ViewItem) -> PluginMetadata {
let info = extract_crate_info(&self.env, krate).unwrap();
let target_triple = self.env.sess.targ_cfg.target_strs.target_triple.as_slice();
let is_cross = target_triple != driver::host_triple();
@ -425,8 +423,8 @@ impl<'a> CrateLoader for Loader<'a> {
load_ctxt.os = config::cfg_os_to_meta_os(self.env.sess.targ_cfg.os);
load_ctxt.filesearch = self.env.sess.target_filesearch();
let lib = load_ctxt.load_library_crate();
if decoder::get_macro_registrar_fn(lib.metadata.as_slice()).is_some() {
let message = format!("crate `{}` contains a macro_registrar fn but \
if decoder::get_plugin_registrar_fn(lib.metadata.as_slice()).is_some() {
let message = format!("crate `{}` contains a plugin_registrar fn but \
only a version for triple `{}` could be found (need {})",
info.ident, target_triple, driver::host_triple());
self.env.sess.span_err(krate.span, message.as_slice());
@ -441,10 +439,10 @@ impl<'a> CrateLoader for Loader<'a> {
None => { load_ctxt.report_load_errs(); unreachable!() },
};
let macros = decoder::get_exported_macros(library.metadata.as_slice());
let registrar = decoder::get_macro_registrar_fn(library.metadata.as_slice()).map(|id| {
let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
decoder::get_symbol(library.metadata.as_slice(), id).to_string()
});
let mc = MacroCrate {
let pc = PluginMetadata {
lib: library.dylib.clone(),
macros: macros.move_iter().map(|x| x.to_string()).collect(),
registrar_symbol: registrar,
@ -454,6 +452,6 @@ impl<'a> CrateLoader for Loader<'a> {
register_crate(&mut self.env, &None, info.ident.as_slice(),
&info.crate_id, krate.span, library);
}
mc
pc
}
}

View File

@ -139,9 +139,6 @@ impl CStore {
.map(|source| source.clone())
}
pub fn dump_phase_syntax_crates(&self) {
}
pub fn reset(&self) {
self.metas.borrow_mut().clear();
self.extern_mod_crate_map.borrow_mut().clear();

View File

@ -1255,8 +1255,8 @@ pub fn get_native_libraries(cdata: Cmd)
return result;
}
pub fn get_macro_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
reader::maybe_get_doc(ebml::Doc::new(data), tag_macro_registrar_fn)
pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
reader::maybe_get_doc(ebml::Doc::new(data), tag_plugin_registrar_fn)
.map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap())
}

View File

@ -1582,9 +1582,9 @@ fn encode_native_libraries(ecx: &EncodeContext, ebml_w: &mut Encoder) {
ebml_w.end_tag();
}
fn encode_macro_registrar_fn(ecx: &EncodeContext, ebml_w: &mut Encoder) {
match ecx.tcx.sess.macro_registrar_fn.get() {
Some(id) => { ebml_w.wr_tagged_u32(tag_macro_registrar_fn, id); }
fn encode_plugin_registrar_fn(ecx: &EncodeContext, ebml_w: &mut Encoder) {
match ecx.tcx.sess.plugin_registrar_fn.get() {
Some(id) => { ebml_w.wr_tagged_u32(tag_plugin_registrar_fn, id); }
None => {}
}
}
@ -1791,7 +1791,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
dep_bytes: u64,
lang_item_bytes: u64,
native_lib_bytes: u64,
macro_registrar_fn_bytes: u64,
plugin_registrar_fn_bytes: u64,
macro_defs_bytes: u64,
impl_bytes: u64,
misc_bytes: u64,
@ -1805,7 +1805,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
dep_bytes: 0,
lang_item_bytes: 0,
native_lib_bytes: 0,
macro_registrar_fn_bytes: 0,
plugin_registrar_fn_bytes: 0,
macro_defs_bytes: 0,
impl_bytes: 0,
misc_bytes: 0,
@ -1870,10 +1870,10 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
encode_native_libraries(&ecx, &mut ebml_w);
stats.native_lib_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode the macro registrar function
// Encode the plugin registrar function
i = ebml_w.writer.tell().unwrap();
encode_macro_registrar_fn(&ecx, &mut ebml_w);
stats.macro_registrar_fn_bytes = ebml_w.writer.tell().unwrap() - i;
encode_plugin_registrar_fn(&ecx, &mut ebml_w);
stats.plugin_registrar_fn_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode macro definitions
i = ebml_w.writer.tell().unwrap();
@ -1912,18 +1912,18 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
}
println!("metadata stats:");
println!(" attribute bytes: {}", stats.attr_bytes);
println!(" dep bytes: {}", stats.dep_bytes);
println!(" lang item bytes: {}", stats.lang_item_bytes);
println!(" native bytes: {}", stats.native_lib_bytes);
println!("macro registrar bytes: {}", stats.macro_registrar_fn_bytes);
println!(" macro def bytes: {}", stats.macro_defs_bytes);
println!(" impl bytes: {}", stats.impl_bytes);
println!(" misc bytes: {}", stats.misc_bytes);
println!(" item bytes: {}", stats.item_bytes);
println!(" index bytes: {}", stats.index_bytes);
println!(" zero bytes: {}", stats.zero_bytes);
println!(" total bytes: {}", stats.total_bytes);
println!(" attribute bytes: {}", stats.attr_bytes);
println!(" dep bytes: {}", stats.dep_bytes);
println!(" lang item bytes: {}", stats.lang_item_bytes);
println!(" native bytes: {}", stats.native_lib_bytes);
println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
println!(" macro def bytes: {}", stats.macro_defs_bytes);
println!(" impl bytes: {}", stats.impl_bytes);
println!(" misc bytes: {}", stats.misc_bytes);
println!(" item bytes: {}", stats.item_bytes);
println!(" index bytes: {}", stats.index_bytes);
println!(" zero bytes: {}", stats.zero_bytes);
println!(" total bytes: {}", stats.total_bytes);
}
}

View File

@ -8,23 +8,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast;
use attr;
use codemap::Span;
use diagnostic;
use visit;
use visit::Visitor;
use syntax::ast;
use syntax::attr;
use syntax::codemap::Span;
use syntax::diagnostic;
use syntax::visit;
use syntax::visit::Visitor;
struct MacroRegistrarContext {
struct RegistrarFinder {
registrars: Vec<(ast::NodeId, Span)> ,
}
impl Visitor<()> for MacroRegistrarContext {
impl Visitor<()> for RegistrarFinder {
fn visit_item(&mut self, item: &ast::Item, _: ()) {
match item.node {
ast::ItemFn(..) => {
if attr::contains_name(item.attrs.as_slice(),
"macro_registrar") {
"plugin_registrar") {
self.registrars.push((item.id, item.span));
}
}
@ -35,20 +35,22 @@ impl Visitor<()> for MacroRegistrarContext {
}
}
pub fn find_macro_registrar(diagnostic: &diagnostic::SpanHandler,
krate: &ast::Crate) -> Option<ast::NodeId> {
let mut ctx = MacroRegistrarContext { registrars: Vec::new() };
visit::walk_crate(&mut ctx, krate, ());
/// Find the function marked with `#[plugin_registrar]`, if any.
/// Used while compiling a crate which defines a registrar.
pub fn find_plugin_registrar(diagnostic: &diagnostic::SpanHandler,
krate: &ast::Crate) -> Option<ast::NodeId> {
let mut finder = RegistrarFinder { registrars: Vec::new() };
visit::walk_crate(&mut finder, krate, ());
match ctx.registrars.len() {
match finder.registrars.len() {
0 => None,
1 => {
let (node_id, _) = ctx.registrars.pop().unwrap();
let (node_id, _) = finder.registrars.pop().unwrap();
Some(node_id)
},
_ => {
diagnostic.handler().err("multiple macro registration functions found");
for &(_, span) in ctx.registrars.iter() {
diagnostic.handler().err("multiple plugin registration functions found");
for &(_, span) in finder.registrars.iter() {
diagnostic.span_note(span, "one is here");
}
diagnostic.handler().abort_if_errors();

131
src/librustc/plugin/load.rs Normal file
View File

@ -0,0 +1,131 @@
// 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.
use plugin::registry::PluginRegistrarFun;
use driver::session::Session;
use metadata::creader::PluginMetadataReader;
use std::mem;
use std::os;
use std::unstable::dynamic_lib::DynamicLibrary;
use syntax::ast;
use syntax::attr;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::ext::expand::ExportedMacros;
use syntax::attr::AttrMetaMethods;
pub struct PluginMetadata {
pub macros: Vec<String>,
pub lib: Option<Path>,
pub registrar_symbol: Option<String>,
}
pub struct Plugins {
pub macros: Vec<ExportedMacros>,
pub registrars: Vec<PluginRegistrarFun>,
}
struct PluginLoader<'a> {
sess: &'a Session,
reader: PluginMetadataReader<'a>,
plugins: Plugins,
}
impl<'a> PluginLoader<'a> {
fn new(sess: &'a Session) -> PluginLoader<'a> {
PluginLoader {
sess: sess,
reader: PluginMetadataReader::new(sess),
plugins: Plugins {
macros: vec!(),
registrars: vec!(),
},
}
}
}
pub fn load_plugins(sess: &Session, krate: &ast::Crate) -> Plugins {
let mut loader = PluginLoader::new(sess);
visit::walk_crate(&mut loader, krate, ());
loader.plugins
}
impl<'a> Visitor<()> for PluginLoader<'a> {
fn visit_view_item(&mut self, vi: &ast::ViewItem, _: ()) {
match vi.node {
ast::ViewItemExternCrate(name, _, _) => {
let mut plugin_phase = false;
for attr in vi.attrs.iter().filter(|a| a.check_name("phase")) {
let phases = attr.meta_item_list().unwrap_or(&[]);
if attr::contains_name(phases, "plugin") {
plugin_phase = true;
}
if attr::contains_name(phases, "syntax") {
plugin_phase = true;
self.sess.span_warn(attr.span,
"phase(syntax) is a deprecated synonym for phase(plugin)");
}
}
if !plugin_phase { return; }
let PluginMetadata { macros, lib, registrar_symbol } =
self.reader.read_plugin_metadata(vi);
self.plugins.macros.push(ExportedMacros {
crate_name: name,
macros: macros,
});
match (lib, registrar_symbol) {
(Some(lib), Some(symbol))
=> self.dylink_registrar(vi, lib, symbol),
_ => (),
}
}
_ => (),
}
}
}
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) {
// Make sure the path contains a / or the linker will search for it.
let path = os::make_absolute(&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(vi.span, err.as_slice())
};
unsafe {
let registrar: PluginRegistrarFun =
match lib.symbol(symbol.as_slice()) {
Ok(registrar) => registrar,
// again fatal if we can't register macros
Err(err) => self.sess.span_fatal(vi.span, err.as_slice())
};
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);
}
}
}

View File

@ -0,0 +1,55 @@
// 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.
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
use syntax::ext::base::{IdentTT, ItemDecorator, ItemModifier, BasicMacroExpander};
use syntax::ext::base::{MacroExpanderFn};
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ast;
pub struct Registry {
#[doc(hidden)]
pub krate_span: Span,
#[doc(hidden)]
pub syntax_exts: Vec<NamedSyntaxExtension>,
}
pub type PluginRegistrarFun =
fn(&mut Registry);
impl Registry {
#[doc(hidden)]
pub fn new(krate: &ast::Crate) -> Registry {
Registry {
krate_span: krate.span,
syntax_exts: vec!(),
}
}
pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
self.syntax_exts.push((name, match extension {
NormalTT(ext, _) => NormalTT(ext, Some(self.krate_span)),
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
ItemDecorator(ext) => ItemDecorator(ext),
ItemModifier(ext) => ItemModifier(ext),
}));
}
pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
self.register_syntax_extension(
token::intern(name),
NormalTT(box BasicMacroExpander {
expander: expander,
span: None,
}, None));
}
}

View File

@ -10,7 +10,6 @@
use rustc;
use rustc::{driver, middle};
use rustc::metadata::creader::Loader;
use rustc::middle::privacy;
use rustc::middle::lint;
@ -100,8 +99,8 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
}
let krate = phase_1_parse_input(&sess, cfg, &input);
let (krate, ast_map) = phase_2_configure_and_expand(&sess, &mut Loader::new(&sess),
krate, &from_str("rustdoc").unwrap());
let (krate, ast_map) = phase_2_configure_and_expand(&sess, krate,
&from_str("rustdoc").unwrap());
let driver::driver::CrateAnalysis {
exported_items, public_items, ty_cx, ..
} = phase_3_run_analysis_passes(sess, &krate, ast_map);

View File

@ -23,7 +23,6 @@ use rustc::back::link;
use rustc::driver::config;
use rustc::driver::driver;
use rustc::driver::session;
use rustc::metadata::creader::Loader;
use syntax::ast;
use syntax::codemap::{CodeMap, dummy_spanned};
use syntax::diagnostic;
@ -68,7 +67,7 @@ pub fn run(input: &str,
@dummy_spanned(ast::MetaWord(cfg_))
}));
let krate = driver::phase_1_parse_input(&sess, cfg, &input);
let (krate, _) = driver::phase_2_configure_and_expand(&sess, &mut Loader::new(&sess), krate,
let (krate, _) = driver::phase_2_configure_and_expand(&sess, krate,
&from_str("rustdoc-test").unwrap());
let ctx = @core::DocContext {

View File

@ -95,9 +95,6 @@ impl IdentMacroExpander for BasicIdentMacroExpander {
pub type IdentMacroExpanderFn =
fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree>) -> Box<MacResult>;
pub type MacroCrateRegistrationFun =
fn(|ast::Name, SyntaxExtension|);
/// The result of a macro expansion. The return values of the various
/// methods are spliced into the AST at the callsite of the macro (or
/// just into the compiler's internal macro table, for `make_def`).
@ -268,6 +265,8 @@ pub enum SyntaxExtension {
IdentTT(Box<IdentMacroExpander:'static>, Option<Span>),
}
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
pub struct BlockInfo {
// should macros escape from this scope?
pub macros_escape: bool,
@ -392,16 +391,6 @@ pub fn syntax_expander_table() -> SyntaxEnv {
syntax_expanders
}
pub struct MacroCrate {
pub lib: Option<Path>,
pub macros: Vec<String>,
pub registrar_symbol: Option<String>,
}
pub trait CrateLoader {
fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate;
}
// One of these is made during expansion and incrementally updated as we go;
// when a macro expansion occurs, the resulting nodes have the backtrace()
// -> expn_info of their expansion context stored into their span.
@ -409,7 +398,7 @@ pub struct ExtCtxt<'a> {
pub parse_sess: &'a parse::ParseSess,
pub cfg: ast::CrateConfig,
pub backtrace: Option<@ExpnInfo>,
pub ecfg: expand::ExpansionConfig<'a>,
pub ecfg: expand::ExpansionConfig,
pub mod_path: Vec<ast::Ident> ,
pub trace_mac: bool,
@ -417,7 +406,7 @@ pub struct ExtCtxt<'a> {
impl<'a> ExtCtxt<'a> {
pub fn new<'a>(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> {
ecfg: expand::ExpansionConfig) -> ExtCtxt<'a> {
ExtCtxt {
parse_sess: parse_sess,
cfg: cfg,

View File

@ -29,10 +29,6 @@ use visit;
use visit::Visitor;
use util::small_vector::SmallVector;
use std::mem;
use std::os;
use std::unstable::dynamic_lib::DynamicLibrary;
pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
match e.node {
// expr_mac should really be expr_ext or something; it's the
@ -497,96 +493,6 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander)
return items;
}
// load macros from syntax-phase crates
pub fn expand_view_item(vi: &ast::ViewItem,
fld: &mut MacroExpander)
-> ast::ViewItem {
match vi.node {
ast::ViewItemExternCrate(..) => {
let should_load = vi.attrs.iter().any(|attr| {
attr.check_name("phase") &&
attr.meta_item_list().map_or(false, |phases| {
attr::contains_name(phases, "syntax")
})
});
if should_load {
load_extern_macros(vi, fld);
}
}
ast::ViewItemUse(_) => {}
}
noop_fold_view_item(vi, fld)
}
fn load_extern_macros(krate: &ast::ViewItem, fld: &mut MacroExpander) {
let MacroCrate { lib, macros, registrar_symbol } =
fld.cx.ecfg.loader.load_crate(krate);
let crate_name = match krate.node {
ast::ViewItemExternCrate(name, _, _) => name,
_ => unreachable!()
};
let name = format!("<{} macros>", token::get_ident(crate_name));
let name = name.to_string();
for source in macros.iter() {
let item = parse::parse_item_from_source_str(name.clone(),
(*source).clone(),
fld.cx.cfg(),
fld.cx.parse_sess())
.expect("expected a serialized item");
expand_item_mac(item, fld);
}
let path = match lib {
Some(path) => path,
None => return
};
// Make sure the path contains a / or the linker will search for it.
let path = os::make_absolute(&path);
let registrar = match registrar_symbol {
Some(registrar) => registrar,
None => return
};
debug!("load_extern_macros: mapped crate {} to path {} and registrar {:s}",
crate_name, path.display(), registrar);
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) => fld.cx.span_fatal(krate.span, err.as_slice())
};
unsafe {
let registrar: MacroCrateRegistrationFun =
match lib.symbol(registrar.as_slice()) {
Ok(registrar) => registrar,
// again fatal if we can't register macros
Err(err) => fld.cx.span_fatal(krate.span, err.as_slice())
};
registrar(|name, extension| {
let extension = match extension {
NormalTT(ext, _) => NormalTT(ext, Some(krate.span)),
IdentTT(ext, _) => IdentTT(ext, Some(krate.span)),
ItemDecorator(ext) => ItemDecorator(ext),
ItemModifier(ext) => ItemModifier(ext),
};
fld.extsbox.insert(name, extension);
});
// Intentionally leak the dynamic library. We can't ever unload it
// since the library can do things that will outlive the expansion
// phase (e.g. make an @-box cycle or launch a task).
mem::forget(lib);
}
}
// expand a stmt
pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> {
// why the copying here and not in expand_expr?
@ -969,10 +875,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
expand_item(item, self)
}
fn fold_view_item(&mut self, vi: &ast::ViewItem) -> ast::ViewItem {
expand_view_item(vi, self)
}
fn fold_stmt(&mut self, stmt: &ast::Stmt) -> SmallVector<@ast::Stmt> {
expand_stmt(stmt, self)
}
@ -986,14 +888,20 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}
}
pub struct ExpansionConfig<'a> {
pub loader: &'a mut CrateLoader,
pub struct ExpansionConfig {
pub deriving_hash_type_parameter: bool,
pub crate_id: CrateId,
}
pub struct ExportedMacros {
pub crate_name: Ident,
pub macros: Vec<String>,
}
pub fn expand_crate(parse_sess: &parse::ParseSess,
cfg: ExpansionConfig,
macros: Vec<ExportedMacros>,
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
let mut expander = MacroExpander {
@ -1001,6 +909,24 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
cx: &mut cx,
};
for ExportedMacros { crate_name, macros } in macros.move_iter() {
let name = format!("<{} macros>", token::get_ident(crate_name))
.into_string();
for source in macros.move_iter() {
let item = parse::parse_item_from_source_str(name.clone(),
source,
expander.cx.cfg(),
expander.cx.parse_sess())
.expect("expected a serialized item");
expand_item_mac(item, &mut expander);
}
}
for (name, extension) in user_exts.move_iter() {
expander.extsbox.insert(name, extension);
}
let ret = expander.fold_crate(c);
parse_sess.span_diagnostic.handler().abort_if_errors();
return ret;
@ -1093,7 +1019,6 @@ mod test {
use attr;
use codemap;
use codemap::Spanned;
use ext::base::{CrateLoader, MacroCrate};
use ext::mtwt;
use parse;
use parse::token;
@ -1137,14 +1062,6 @@ mod test {
}
}
struct ErrLoader;
impl CrateLoader for ErrLoader {
fn load_crate(&mut self, _: &ast::ViewItem) -> MacroCrate {
fail!("lolwut")
}
}
// these following tests are quite fragile, in that they don't test what
// *kind* of failure occurs.
@ -1159,13 +1076,11 @@ mod test {
src,
Vec::new(), &sess);
// should fail:
let mut loader = ErrLoader;
let cfg = ::syntax::ext::expand::ExpansionConfig {
loader: &mut loader,
deriving_hash_type_parameter: false,
crate_id: from_str("test").unwrap(),
};
expand_crate(&sess,cfg,crate_ast);
expand_crate(&sess,cfg,vec!(),vec!(),crate_ast);
}
// make sure that macros can leave scope for modules
@ -1178,14 +1093,11 @@ mod test {
"<test>".to_string(),
src,
Vec::new(), &sess);
// should fail:
let mut loader = ErrLoader;
let cfg = ::syntax::ext::expand::ExpansionConfig {
loader: &mut loader,
deriving_hash_type_parameter: false,
crate_id: from_str("test").unwrap(),
};
expand_crate(&sess,cfg,crate_ast);
expand_crate(&sess,cfg,vec!(),vec!(),crate_ast);
}
// macro_escape modules shouldn't cause macros to leave scope
@ -1198,13 +1110,11 @@ mod test {
src,
Vec::new(), &sess);
// should fail:
let mut loader = ErrLoader;
let cfg = ::syntax::ext::expand::ExpansionConfig {
loader: &mut loader,
deriving_hash_type_parameter: false,
crate_id: from_str("test").unwrap(),
};
expand_crate(&sess, cfg, crate_ast);
expand_crate(&sess, cfg, vec!(), vec!(), crate_ast);
}
#[test] fn test_contains_flatten (){
@ -1237,13 +1147,11 @@ mod test {
let ps = parse::new_parse_sess();
let crate_ast = string_to_parser(&ps, crate_str).parse_crate_mod();
// the cfg argument actually does matter, here...
let mut loader = ErrLoader;
let cfg = ::syntax::ext::expand::ExpansionConfig {
loader: &mut loader,
deriving_hash_type_parameter: false,
crate_id: from_str("test").unwrap(),
};
expand_crate(&ps,cfg,crate_ast)
expand_crate(&ps,cfg,vec!(),vec!(),crate_ast)
}
//fn expand_and_resolve(crate_str: @str) -> ast::crate {

View File

@ -74,7 +74,6 @@ pub mod ext {
pub mod asm;
pub mod base;
pub mod expand;
pub mod registrar;
pub mod quote;