Remove scope placeholders, remove method add_macro of ext::base::Resolver.
This commit is contained in:
parent
e80d1a8faf
commit
421c5d11c1
7 changed files with 91 additions and 122 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 );+
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue