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.
|
//! Used by plugin crates to tell `rustc` about the plugins they provide.
|
||||||
|
|
||||||
use lint::{LintPassObject, LintId, Lint};
|
use lint::{LintPassObject, LintId, Lint};
|
||||||
|
use session::Session;
|
||||||
|
|
||||||
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
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::ext::base::{MacroExpanderFn};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
@ -29,7 +30,11 @@ use std::collections::HashMap;
|
|||||||
/// This struct has public fields and other methods for use by `rustc`
|
/// This struct has public fields and other methods for use by `rustc`
|
||||||
/// itself. They are not documented here, and plugin authors should
|
/// itself. They are not documented here, and plugin authors should
|
||||||
/// not use them.
|
/// 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)]
|
#[doc(hidden)]
|
||||||
pub krate_span: Span,
|
pub krate_span: Span,
|
||||||
|
|
||||||
@ -43,10 +48,11 @@ pub struct Registry {
|
|||||||
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registry {
|
impl<'a> Registry<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn new(krate: &ast::Crate) -> Registry {
|
pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
|
||||||
Registry {
|
Registry {
|
||||||
|
sess: sess,
|
||||||
krate_span: krate.span,
|
krate_span: krate.span,
|
||||||
syntax_exts: vec!(),
|
syntax_exts: vec!(),
|
||||||
lint_passes: vec!(),
|
lint_passes: vec!(),
|
||||||
@ -63,8 +69,11 @@ impl Registry {
|
|||||||
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
|
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
|
||||||
Decorator(ext) => Decorator(ext),
|
Decorator(ext) => Decorator(ext),
|
||||||
Modifier(ext) => Modifier(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", (), |_|
|
= time(time_passes, "plugin loading", (), |_|
|
||||||
plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
|
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", (), |_| {
|
time(time_passes, "plugin registration", (), |_| {
|
||||||
if sess.features.borrow().rustc_diagnostic_macros {
|
if sess.features.borrow().rustc_diagnostic_macros {
|
||||||
|
@ -328,13 +328,8 @@ pub enum SyntaxExtension {
|
|||||||
///
|
///
|
||||||
IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
||||||
|
|
||||||
/// An ident macro that has two properties:
|
/// Represents `macro_rules!` itself.
|
||||||
/// - it adds a macro definition to the environment, and
|
MacroRulesTT,
|
||||||
/// - the definition it adds doesn't introduce any new
|
|
||||||
/// identifiers.
|
|
||||||
///
|
|
||||||
/// `macro_rules!` is a LetSyntaxTT
|
|
||||||
LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||||
@ -364,8 +359,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut syntax_expanders = SyntaxEnv::new();
|
let mut syntax_expanders = SyntaxEnv::new();
|
||||||
syntax_expanders.insert(intern("macro_rules"),
|
syntax_expanders.insert(intern("macro_rules"), MacroRulesTT);
|
||||||
LetSyntaxTT(box ext::tt::macro_rules::add_new_extension, None));
|
|
||||||
syntax_expanders.insert(intern("fmt"),
|
syntax_expanders.insert(intern("fmt"),
|
||||||
builtin_normal_expander(
|
builtin_normal_expander(
|
||||||
ext::fmt::expand_syntax_ext));
|
ext::fmt::expand_syntax_ext));
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
use self::Either::*;
|
|
||||||
|
|
||||||
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
||||||
use ast::{Local, Ident, MacInvocTT};
|
use ast::{Local, Ident, MacInvocTT};
|
||||||
@ -18,6 +17,7 @@ use ast;
|
|||||||
use ast_util::path_to_ident;
|
use ast_util::path_to_ident;
|
||||||
use ext::mtwt;
|
use ext::mtwt;
|
||||||
use ext::build::AstBuilder;
|
use ext::build::AstBuilder;
|
||||||
|
use ext::tt::macro_rules;
|
||||||
use attr;
|
use attr;
|
||||||
use attr::AttrMetaMethods;
|
use attr::AttrMetaMethods;
|
||||||
use codemap;
|
use codemap;
|
||||||
@ -33,11 +33,6 @@ use util::small_vector::SmallVector;
|
|||||||
use visit;
|
use visit;
|
||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
|
|
||||||
enum Either<L,R> {
|
|
||||||
Left(L),
|
|
||||||
Right(R)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expand_type(t: P<ast::Ty>,
|
pub fn expand_type(t: P<ast::Ty>,
|
||||||
fld: &mut MacroExpander,
|
fld: &mut MacroExpander,
|
||||||
impl_ty: Option<P<ast::Ty>>)
|
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 extnamestr = token::get_ident(extname);
|
||||||
let fm = fresh_mark();
|
let fm = fresh_mark();
|
||||||
let def_or_items = {
|
let items = {
|
||||||
let mut expanded = match fld.cx.syntax_env.find(&extname.name) {
|
let expanded = match fld.cx.syntax_env.find(&extname.name) {
|
||||||
None => {
|
None => {
|
||||||
fld.cx.span_err(path_span,
|
fld.cx.span_err(path_span,
|
||||||
format!("macro undefined: '{}!'",
|
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);
|
let marked_tts = mark_tts(tts[], fm);
|
||||||
expander.expand(fld.cx, it.span, it.ident, marked_tts)
|
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 {
|
if it.ident.name == parse::token::special_idents::invalid.name {
|
||||||
fld.cx.span_err(path_span,
|
fld.cx.span_err(path_span,
|
||||||
format!("macro {}! expects an ident argument",
|
format!("macro_rules! expects an ident argument")[]);
|
||||||
extnamestr.get())[]);
|
|
||||||
return SmallVector::zero();
|
return SmallVector::zero();
|
||||||
}
|
}
|
||||||
fld.cx.bt_push(ExpnInfo {
|
fld.cx.bt_push(ExpnInfo {
|
||||||
@ -612,11 +606,21 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
|||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
name: extnamestr.get().to_string(),
|
name: extnamestr.get().to_string(),
|
||||||
format: MacroBang,
|
format: MacroBang,
|
||||||
span: span
|
span: None,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// DON'T mark before expansion:
|
// DON'T mark before expansion.
|
||||||
expander.expand(fld.cx, it.span, it.ident, tts)
|
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,
|
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() {
|
expanded.make_items()
|
||||||
Some(def) => Left(def),
|
|
||||||
None => Right(expanded.make_items())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let items = match def_or_items {
|
let items = match items {
|
||||||
Left(MacroDef { name, ext }) => {
|
Some(items) => {
|
||||||
// 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)) => {
|
|
||||||
items.into_iter()
|
items.into_iter()
|
||||||
.map(|i| mark_item(i, fm))
|
.map(|i| mark_item(i, fm))
|
||||||
.flat_map(|i| fld.fold_item(i).into_iter())
|
.flat_map(|i| fld.fold_item(i).into_iter())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
Right(None) => {
|
None => {
|
||||||
fld.cx.span_err(path_span,
|
fld.cx.span_err(path_span,
|
||||||
format!("non-item macro in item position: {}",
|
format!("non-item macro in item position: {}",
|
||||||
extnamestr.get())[]);
|
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
|
/// Given `lhses` and `rhses`, this is the new macro we create
|
||||||
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
@ -219,7 +210,7 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
|||||||
sp: Span,
|
sp: Span,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
arg: Vec<ast::TokenTree> )
|
arg: Vec<ast::TokenTree> )
|
||||||
-> Box<MacResult+'cx> {
|
-> MacroDef {
|
||||||
|
|
||||||
let lhs_nm = gensym_ident("lhs");
|
let lhs_nm = gensym_ident("lhs");
|
||||||
let rhs_nm = gensym_ident("rhs");
|
let rhs_nm = gensym_ident("rhs");
|
||||||
@ -279,10 +270,8 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
|||||||
rhses: rhses,
|
rhses: rhses,
|
||||||
};
|
};
|
||||||
|
|
||||||
box MacroRulesDefiner {
|
MacroDef {
|
||||||
def: Some(MacroDef {
|
|
||||||
name: token::get_ident(name).to_string(),
|
name: token::get_ident(name).to_string(),
|
||||||
ext: NormalTT(exp, Some(sp))
|
ext: NormalTT(exp, Some(sp))
|
||||||
})
|
}
|
||||||
} as Box<MacResult+'cx>
|
|
||||||
}
|
}
|
||||||
|
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