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:
Keegan McAllister 2014-09-15 16:09:09 -07:00
parent d1cf1b1e6b
commit 5e5924b799
7 changed files with 92 additions and 64 deletions

View File

@ -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;
}
}));
}

View File

@ -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 {

View File

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

View File

@ -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())[]);

View File

@ -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))
}
}

View 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);
}

View 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() { }