Remove scope placeholders, remove method add_macro of ext::base::Resolver.

This commit is contained in:
Jeffrey Seyfried 2016-12-01 11:20:04 +00:00
parent e80d1a8faf
commit 421c5d11c1
7 changed files with 91 additions and 122 deletions

View file

@ -697,9 +697,13 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
fn visit_item(&mut self, item: &'a Item) {
let macro_use = match item.node {
ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
ItemKind::Mac(..) => {
return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
ItemKind::Mac(ref mac) => {
if mac.node.path.segments.is_empty() {
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
} else {
self.resolver.define_macro(item, &mut self.legacy_scope);
}
return
}
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
_ => false,

View file

@ -23,8 +23,8 @@ use syntax::ast::{self, Name, Ident};
use syntax::attr;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{NormalTT, SyntaxExtension};
use syntax::ext::expand::Expansion;
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::expand::{Expansion, mark_tts};
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{emit_feature_err, GateIssue};
@ -139,34 +139,6 @@ impl<'a> base::Resolver for Resolver<'a> {
invocation.expansion.set(visitor.legacy_scope);
}
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
if def.ident.name == "macro_rules" {
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
}
let invocation = self.invocations[&scope];
let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
parent: Cell::new(invocation.legacy_scope.get()),
name: def.ident.name,
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
span: def.span,
});
invocation.legacy_scope.set(LegacyScope::Binding(binding));
self.macro_names.insert(def.ident.name);
if attr::contains_name(&def.attrs, "macro_export") {
def.id = self.next_node_id();
DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
collector.visit_macro_def(&def)
});
self.macro_exports.push(Export {
name: def.ident.name,
def: Def::Macro(self.definitions.local_def_id(def.id)),
});
self.exported_macros.push(def);
}
}
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
if let NormalTT(..) = *ext {
self.macro_names.insert(ident.name);
@ -444,4 +416,47 @@ impl<'a> Resolver<'a> {
expansion.visit_with(def_collector)
});
}
pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) {
let tts = match item.node {
ast::ItemKind::Mac(ref mac) => &mac.node.tts,
_ => unreachable!(),
};
if item.ident.name == "macro_rules" {
self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`");
}
let mark = Mark::from_placeholder_id(item.id);
let invocation = self.invocations[&mark];
invocation.module.set(self.current_module);
let mut def = ast::MacroDef {
ident: item.ident,
attrs: item.attrs.clone(),
id: ast::DUMMY_NODE_ID,
span: item.span,
body: mark_tts(tts, mark),
};
*legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
parent: Cell::new(*legacy_scope),
name: def.ident.name,
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
span: def.span,
}));
self.macro_names.insert(def.ident.name);
if attr::contains_name(&def.attrs, "macro_export") {
def.id = self.next_node_id();
DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
collector.visit_macro_def(&def)
});
self.macro_exports.push(Export {
name: def.ident.name,
def: Def::Macro(self.definitions.local_def_id(def.id)),
});
self.exported_macros.push(def);
}
}
}

View file

@ -520,7 +520,6 @@ pub trait Resolver {
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>;
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
@ -544,7 +543,6 @@ impl Resolver for DummyResolver {
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}

View file

@ -392,14 +392,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
};
let Mac_ { path, tts, .. } = mac.node;
// Detect use of feature-gated or invalid attributes on macro invoations
// since they will not be detected after macro expansion.
for attr in attrs.iter() {
feature_gate::check_attribute(&attr, &self.cx.parse_sess,
&self.cx.parse_sess.codemap(),
&self.cx.ecfg.features.unwrap());
}
let extname = path.segments.last().unwrap().identifier.name;
let ident = ident.unwrap_or(keywords::Invalid.ident());
let marked_tts = mark_tts(&tts, mark);
@ -601,6 +593,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect_bang(
&mut self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind,
) -> Expansion {
self.check_attributes(&attrs);
self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span })
}
@ -622,6 +615,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
self.cfg.configure(node)
}
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
let codemap = &self.cx.parse_sess.codemap();
let features = self.cx.ecfg.features.unwrap();
for attr in attrs.iter() {
feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features);
}
}
}
// These are pretty nasty. Ideally, we would keep the tokens around, linked from
@ -740,14 +743,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
match item.node {
ast::ItemKind::Mac(..) => {
if match item.node {
ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
_ => unreachable!(),
} {
return SmallVector::one(item);
}
self.check_attributes(&item.attrs);
let is_macro_def = if let ItemKind::Mac(ref mac) = item.node {
mac.node.path.segments[0].identifier.name == "macro_rules"
} else {
unreachable!()
};
item.and_then(|item| match item.node {
item.and_then(|mut item| match item.node {
ItemKind::Mac(_) if is_macro_def => {
item.id = ast::NodeId::from_u32(Mark::fresh().as_u32());
SmallVector::one(P(item))
}
ItemKind::Mac(mac) => {
self.collect(ExpansionKind::Items, InvocationKind::Bang {
mac: mac,

View file

@ -12,9 +12,10 @@ use ast;
use codemap::{DUMMY_SP, dummy_spanned};
use ext::base::ExtCtxt;
use ext::expand::{Expansion, ExpansionKind};
use ext::hygiene::Mark;
use fold::*;
use ptr::P;
use symbol::{Symbol, keywords};
use symbol::keywords;
use util::move_map::MoveMap;
use util::small_vector::SmallVector;
@ -68,10 +69,6 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
}
}
pub fn macro_scope_placeholder() -> Expansion {
placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
}
pub struct PlaceholderExpander<'a, 'b: 'a> {
expansions: HashMap<ast::NodeId, Expansion>,
cx: &'a mut ExtCtxt<'b>,
@ -100,11 +97,12 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
match item.node {
// Scope placeholder
ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item),
ast::ItemKind::Mac(_) => self.remove(item.id).make_items(),
_ => noop_fold_item(item, self),
ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {}
ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(),
_ => {}
}
noop_fold_item(item, self)
}
fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
@ -172,10 +170,10 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
block.stmts = block.stmts.move_flat_map(|mut stmt| {
remaining_stmts -= 1;
// Scope placeholder
// `macro_rules!` macro definition
if let ast::StmtKind::Item(ref item) = stmt.node {
if let ast::ItemKind::Mac(..) = item.node {
macros.push(item.ident.ctxt.data().outer_mark);
if let ast::ItemKind::Mac(_) = item.node {
macros.push(Mark::from_placeholder_id(item.id));
return None;
}
}
@ -208,33 +206,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
let mut module = noop_fold_mod(module, self);
module.items = module.items.move_flat_map(|item| match item.node {
ast::ItemKind::Mac(_) => None, // remove scope placeholders from modules
ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => None, // remove macro definitions
_ => Some(item),
});
module
}
}
pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion {
Expansion::Items(SmallVector::one(P(ast::Item {
ident: def.ident,
attrs: def.attrs.clone(),
id: ast::DUMMY_NODE_ID,
node: ast::ItemKind::Mac(ast::Mac {
span: def.span,
node: ast::Mac_ {
path: ast::Path {
span: DUMMY_SP,
global: false,
segments: vec![ast::PathSegment {
identifier: ast::Ident::with_empty_ctxt(Symbol::intern("macro_rules")),
parameters: ast::PathParameters::none(),
}],
},
tts: def.body.clone(),
}
}),
vis: ast::Visibility::Inherited,
span: def.span,
})))
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
mac
}
}

View file

@ -10,10 +10,9 @@
use {ast, attr};
use syntax_pos::{Span, DUMMY_SP};
use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension};
use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander};
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
use ext::base::{NormalTT, TTMacroExpander};
use ext::expand::{Expansion, ExpansionKind};
use ext::placeholders;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::{parse, parse_failure_msg};
@ -151,35 +150,6 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
}
pub struct MacroRulesExpander;
impl IdentMacroExpander for MacroRulesExpander {
fn expand(&self,
cx: &mut ExtCtxt,
span: Span,
ident: ast::Ident,
tts: Vec<tokenstream::TokenTree>,
attrs: Vec<ast::Attribute>)
-> Box<MacResult> {
let def = ast::MacroDef {
ident: ident,
id: ast::DUMMY_NODE_ID,
span: span,
body: tts,
attrs: attrs,
};
// If keep_macs is true, expands to a MacEager::items instead.
let result = if cx.ecfg.keep_macs {
MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items())
} else {
MacEager::items(placeholders::macro_scope_placeholder().make_items())
};
cx.resolver.add_macro(cx.current_expansion.mark, def);
result
}
}
// Note that macro-by-example's input is also matched against a token tree:
// $( $lhs:tt => $rhs:tt );+
//

View file

@ -50,8 +50,7 @@ pub mod deriving;
use std::rc::Rc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension};
use syntax::ext::tt::macro_rules::MacroRulesExpander;
use syntax::ext::base::{MacroExpanderFn, NormalTT, MultiModifier, NamedSyntaxExtension};
use syntax::symbol::Symbol;
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
@ -61,8 +60,6 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
};
register(Symbol::intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false));
macro_rules! register {
($( $name:ident: $f:expr, )*) => { $(
register(Symbol::intern(stringify!($name)),