Replace LetSyntaxTT with MacroRulesTT
The implementation of LetSyntaxTT was specialized to macro_rules! in various ways. This gets rid of the false generality and simplifies the code.
This commit is contained in:
parent
d1cf1b1e6b
commit
5e5924b799
@ -11,9 +11,10 @@
|
||||
//! 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;
|
||||
@ -29,7 +30,11 @@ use std::collections::HashMap;
|
||||
/// 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,
|
||||
|
||||
@ -43,10 +48,11 @@ pub struct Registry {
|
||||
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!(),
|
||||
@ -63,8 +69,11 @@ impl Registry {
|
||||
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;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
= 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 {
|
||||
|
@ -328,13 +328,8 @@ pub enum SyntaxExtension {
|
||||
///
|
||||
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);
|
||||
@ -364,8 +359,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -7,7 +7,6 @@
|
||||
// <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};
|
||||
@ -18,6 +17,7 @@ use ast;
|
||||
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;
|
||||
@ -33,11 +33,6 @@ use util::small_vector::SmallVector;
|
||||
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>>)
|
||||
@ -548,8 +543,8 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||
|
||||
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: '{}!'",
|
||||
@ -600,11 +595,10 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||
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 {
|
||||
@ -612,11 +606,21 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||
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,
|
||||
@ -627,31 +631,17 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||
}
|
||||
};
|
||||
|
||||
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())[]);
|
||||
|
@ -129,15 +129,6 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@ -219,7 +210,7 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||
sp: Span,
|
||||
name: Ident,
|
||||
arg: Vec<ast::TokenTree> )
|
||||
-> Box<MacResult+'cx> {
|
||||
-> MacroDef {
|
||||
|
||||
let lhs_nm = gensym_ident("lhs");
|
||||
let rhs_nm = gensym_ident("rhs");
|
||||
@ -279,10 +270,8 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
25
src/test/auxiliary/macro_crate_MacroRulesTT.rs
Normal file
25
src/test/auxiliary/macro_crate_MacroRulesTT.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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);
|
||||
}
|
21
src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs
Normal file
21
src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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() { }
|
Loading…
x
Reference in New Issue
Block a user