//! Used by plugin crates to tell `rustc` about the plugins they provide.
use lint::{LintPassObject, LintId, Lint};
+use session::Session;
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
-use syntax::ext::base::{IdentTT, LetSyntaxTT, Decorator, Modifier};
+use syntax::ext::base::{IdentTT, Decorator, Modifier, MacroRulesTT};
use syntax::ext::base::{MacroExpanderFn};
use syntax::codemap::Span;
use syntax::parse::token;
/// 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 {
+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 krate_span: Span,
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
}
-impl Registry {
+impl<'a> Registry<'a> {
#[doc(hidden)]
- pub fn new(krate: &ast::Crate) -> Registry {
+ pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
Registry {
+ sess: sess,
krate_span: krate.span,
syntax_exts: vec!(),
lint_passes: vec!(),
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
Decorator(ext) => Decorator(ext),
Modifier(ext) => Modifier(ext),
- // there's probably a nicer way to signal this:
- LetSyntaxTT(_, _) => panic!("can't register a new LetSyntax!"),
+
+ MacroRulesTT => {
+ self.sess.err("plugin tried to register a new MacroRulesTT");
+ return;
+ }
}));
}
= time(time_passes, "plugin loading", (), |_|
plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
- let mut registry = Registry::new(&krate);
+ let mut registry = Registry::new(sess, &krate);
time(time_passes, "plugin registration", (), |_| {
if sess.features.borrow().rustc_diagnostic_macros {
///
IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
- /// An ident macro that has two properties:
- /// - it adds a macro definition to the environment, and
- /// - the definition it adds doesn't introduce any new
- /// identifiers.
- ///
- /// `macro_rules!` is a LetSyntaxTT
- LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
+ /// Represents `macro_rules!` itself.
+ MacroRulesTT,
}
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
}
let mut syntax_expanders = SyntaxEnv::new();
- syntax_expanders.insert(intern("macro_rules"),
- LetSyntaxTT(box ext::tt::macro_rules::add_new_extension, None));
+ syntax_expanders.insert(intern("macro_rules"), MacroRulesTT);
syntax_expanders.insert(intern("fmt"),
builtin_normal_expander(
ext::fmt::expand_syntax_ext));
// <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 self::Either::*;
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
use ast::{Local, Ident, MacInvocTT};
use ast_util::path_to_ident;
use ext::mtwt;
use ext::build::AstBuilder;
+use ext::tt::macro_rules;
use attr;
use attr::AttrMetaMethods;
use codemap;
use visit;
use visit::Visitor;
-enum Either<L,R> {
- Left(L),
- Right(R)
-}
-
pub fn expand_type(t: P<ast::Ty>,
fld: &mut MacroExpander,
impl_ty: Option<P<ast::Ty>>)
let extnamestr = token::get_ident(extname);
let fm = fresh_mark();
- let def_or_items = {
- let mut expanded = match fld.cx.syntax_env.find(&extname.name) {
+ let items = {
+ let expanded = match fld.cx.syntax_env.find(&extname.name) {
None => {
fld.cx.span_err(path_span,
format!("macro undefined: '{}!'",
let marked_tts = mark_tts(tts[], fm);
expander.expand(fld.cx, it.span, it.ident, marked_tts)
}
- LetSyntaxTT(ref expander, span) => {
+ MacroRulesTT => {
if it.ident.name == parse::token::special_idents::invalid.name {
fld.cx.span_err(path_span,
- format!("macro {}! expects an ident argument",
- extnamestr.get())[]);
+ format!("macro_rules! expects an ident argument")[]);
return SmallVector::zero();
}
fld.cx.bt_push(ExpnInfo {
callee: NameAndSpan {
name: extnamestr.get().to_string(),
format: MacroBang,
- span: span
+ span: None,
}
});
- // DON'T mark before expansion:
- expander.expand(fld.cx, it.span, it.ident, tts)
+ // DON'T mark before expansion.
+ let MacroDef { name, ext }
+ = macro_rules::add_new_extension(fld.cx, it.span, it.ident, tts);
+
+ fld.cx.syntax_env.insert(intern(name.as_slice()), ext);
+ if attr::contains_name(it.attrs.as_slice(), "macro_export") {
+ fld.cx.exported_macros.push(it);
+ }
+
+ // macro_rules! has a side effect but expands to nothing.
+ fld.cx.bt_pop();
+ return SmallVector::zero();
}
_ => {
fld.cx.span_err(it.span,
}
};
- match expanded.make_def() {
- Some(def) => Left(def),
- None => Right(expanded.make_items())
- }
+ expanded.make_items()
};
- let items = match def_or_items {
- Left(MacroDef { name, ext }) => {
- // hidden invariant: this should only be possible as the
- // result of expanding a LetSyntaxTT, and thus doesn't
- // need to be marked. Not that it could be marked anyway.
- // create issue to recommend refactoring here?
- fld.cx.syntax_env.insert(intern(name[]), ext);
- if attr::contains_name(it.attrs[], "macro_export") {
- fld.cx.exported_macros.push(it);
- }
- SmallVector::zero()
- }
- Right(Some(items)) => {
+ let items = match items {
+ Some(items) => {
items.into_iter()
.map(|i| mark_item(i, fm))
.flat_map(|i| fld.fold_item(i).into_iter())
.collect()
}
- Right(None) => {
+ None => {
fld.cx.span_err(path_span,
format!("non-item macro in item position: {}",
extnamestr.get())[]);
}
}
-struct MacroRulesDefiner {
- def: Option<MacroDef>
-}
-impl MacResult for MacroRulesDefiner {
- fn make_def(&mut self) -> Option<MacroDef> {
- Some(self.def.take().expect("empty MacroRulesDefiner"))
- }
-}
-
/// Given `lhses` and `rhses`, this is the new macro we create
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
sp: Span,
sp: Span,
name: Ident,
arg: Vec<ast::TokenTree> )
- -> Box<MacResult+'cx> {
+ -> MacroDef {
let lhs_nm = gensym_ident("lhs");
let rhs_nm = gensym_ident("rhs");
rhses: rhses,
};
- box MacroRulesDefiner {
- def: Some(MacroDef {
- name: token::get_ident(name).to_string(),
- ext: NormalTT(exp, Some(sp))
- })
- } as Box<MacResult+'cx>
+ MacroDef {
+ name: token::get_ident(name).to_string(),
+ ext: NormalTT(exp, Some(sp))
+ }
}
--- /dev/null
+// Copyright 2014 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 syntax::parse::token;
+use syntax::ext::base::MacroRulesTT;
+use rustc::plugin::Registry;
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+ reg.register_syntax_extension(token::intern("bogus"), MacroRulesTT);
+}
--- /dev/null
+// Copyright 2014 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:macro_crate_MacroRulesTT.rs
+// ignore-stage1
+// ignore-android
+// error-pattern: plugin tried to register a new MacroRulesTT
+
+#![feature(phase)]
+
+#[phase(plugin)]
+extern crate macro_crate_MacroRulesTT;
+
+fn main() { }