> {
- let mut module = self.current_module;
- let mut module_data;
- loop {
- module_data = self.data(module);
- if let Some(ext) = module_data.macros.get(&name) {
- return Some(ext.clone());
- }
- if module == module_data.parent {
- return None;
- }
- module = module_data.parent;
- }
- }
-
- pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
- if let NormalTT(..) = ext {
- self.names.insert(name);
- }
-
- let mut module = self.current_module;
- while self.data(module).macros_escape {
- module = self.data(module).parent;
- }
- self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
- }
-
- pub fn is_crate_root(&mut self) -> bool {
- self.current_module == Module(0)
- }
-}
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d8365391153bc..beb1687dfdc72 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -25,6 +25,7 @@ use parse::token::{intern, keywords};
use ptr::P;
use tokenstream::TokenTree;
use util::small_vector::SmallVector;
+use visit::Visitor;
use std::mem;
use std::path::PathBuf;
@@ -32,7 +33,8 @@ use std::rc::Rc;
macro_rules! expansions {
($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
- $(.$fold:ident)* $(lift .$fold_elt:ident)*;)*) => {
+ $(.$fold:ident)* $(lift .$fold_elt:ident)*,
+ $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
#[derive(Copy, Clone)]
pub enum ExpansionKind { OptExpr, $( $kind, )* }
pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
@@ -77,6 +79,17 @@ macro_rules! expansions {
}, )*)*
}
}
+
+ pub fn visit_with(&self, visitor: &mut V) {
+ match *self {
+ Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
+ Expansion::OptExpr(None) => {}
+ $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
+ $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
+ visitor.$visit_elt(ast);
+ }, )*)*
+ }
+ }
}
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -94,17 +107,17 @@ macro_rules! expansions {
}
expansions! {
- Expr: P [], "expression", .make_expr, .fold_expr;
- Pat: P [], "pattern", .make_pat, .fold_pat;
- Ty: P [], "type", .make_ty, .fold_ty;
+ Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr;
+ Pat: P [], "pattern", .make_pat, .fold_pat, .visit_pat;
+ Ty: P [], "type", .make_ty, .fold_ty, .visit_ty;
Stmts: SmallVector [SmallVector, ast::Stmt],
- "statement", .make_stmts, lift .fold_stmt;
+ "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
Items: SmallVector> [SmallVector, P],
- "item", .make_items, lift .fold_item;
+ "item", .make_items, lift .fold_item, lift .visit_item;
TraitItems: SmallVector [SmallVector, ast::TraitItem],
- "trait item", .make_trait_items, lift .fold_trait_item;
+ "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
ImplItems: SmallVector [SmallVector, ast::ImplItem],
- "impl item", .make_impl_items, lift .fold_impl_item;
+ "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
}
impl ExpansionKind {
@@ -127,15 +140,12 @@ impl ExpansionKind {
}
pub struct Invocation {
- kind: InvocationKind,
+ pub kind: InvocationKind,
expansion_kind: ExpansionKind,
- mark: Mark,
- module: Module,
- backtrace: ExpnId,
- depth: usize,
+ expansion_data: ExpansionData,
}
-enum InvocationKind {
+pub enum InvocationKind {
Bang {
attrs: Vec,
mac: ast::Mac,
@@ -148,6 +158,19 @@ enum InvocationKind {
},
}
+impl Invocation {
+ fn span(&self) -> Span {
+ match self.kind {
+ InvocationKind::Bang { span, .. } => span,
+ InvocationKind::Attr { ref attr, .. } => attr.span,
+ }
+ }
+
+ pub fn mark(&self) -> Mark {
+ self.expansion_data.mark
+ }
+}
+
pub struct MacroExpander<'a, 'b:'a> {
pub cx: &'a mut ExtCtxt<'b>,
pub single_step: bool,
@@ -170,7 +193,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let items = Expansion::Items(SmallVector::many(krate.module.items));
krate.module.items = self.expand(items).make_items().into();
- krate.exported_macros = self.cx.exported_macros.clone();
+ krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new());
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
self.cx.parse_sess.span_diagnostic.abort_if_errors();
@@ -181,21 +204,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
// Fully expand all the invocations in `expansion`.
fn expand(&mut self, expansion: Expansion) -> Expansion {
- self.cx.recursion_count = 0;
+ let orig_expansion_data = self.cx.current_expansion.clone();
+ self.cx.current_expansion.depth = 0;
+
let (expansion, mut invocations) = self.collect_invocations(expansion);
invocations.reverse();
let mut expansions = vec![vec![(0, expansion)]];
while let Some(invoc) = invocations.pop() {
- let Invocation { mark, module, depth, backtrace, .. } = invoc;
- self.cx.syntax_env.current_module = module;
- self.cx.recursion_count = depth;
- self.cx.backtrace = backtrace;
+ let ExpansionData { depth, mark, .. } = invoc.expansion_data;
+ self.cx.current_expansion = invoc.expansion_data.clone();
- let expansion = self.expand_invoc(invoc);
+ let expansion = match self.cx.resolver.resolve_invoc(&invoc) {
+ Some(ext) => self.expand_invoc(invoc, ext),
+ None => invoc.expansion_kind.dummy(invoc.span()),
+ };
- self.cx.syntax_env.current_module = module;
- self.cx.recursion_count = depth + 1;
+ self.cx.current_expansion.depth = depth + 1;
let (expansion, new_invocations) = self.collect_invocations(expansion);
if expansions.len() == depth {
@@ -207,6 +232,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
+ self.cx.current_expansion = orig_expansion_data;
+
let mut placeholder_expander = PlaceholderExpander::new();
while let Some(expansions) = expansions.pop() {
for (mark, expansion) in expansions.into_iter().rev() {
@@ -233,30 +260,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
};
(expansion.fold_with(&mut collector), collector.invocations)
};
-
self.cx.cfg = crate_config;
+
+ let mark = self.cx.current_expansion.mark;
+ self.cx.resolver.visit_expansion(mark, &result.0);
result
}
- fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
+ fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion {
match invoc.kind {
- InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
- InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc),
+ InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
+ InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
}
}
- fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
+ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion {
let Invocation { expansion_kind: kind, .. } = invoc;
let (attr, item) = match invoc.kind {
InvocationKind::Attr { attr, item } => (attr, item),
_ => unreachable!(),
};
- let extension = match self.cx.syntax_env.find(intern(&attr.name())) {
- Some(extension) => extension,
- None => unreachable!(),
- };
-
attr::mark_used(&attr);
self.cx.bt_push(ExpnInfo {
call_site: attr.span,
@@ -267,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
});
- match *extension {
+ match *ext {
MultiModifier(ref mac) => {
let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
kind.expect_from_annotatables(item)
@@ -284,8 +308,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
/// Expand a macro invocation. Returns the result of expansion.
- fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
- let Invocation { mark, expansion_kind: kind, .. } = invoc;
+ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion {
+ let (mark, kind) = (invoc.mark(), invoc.expansion_kind);
let (attrs, mac, ident, span) = match invoc.kind {
InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
_ => unreachable!(),
@@ -306,19 +330,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
let extname = path.segments[0].identifier.name;
- let extension = if let Some(extension) = self.cx.syntax_env.find(extname) {
- extension
- } else {
- let mut err =
- self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
- self.cx.suggest_macro_name(&extname.as_str(), &mut err);
- err.emit();
- return kind.dummy(span);
- };
-
let ident = ident.unwrap_or(keywords::Invalid.ident());
let marked_tts = mark_tts(&tts, mark);
- let opt_expanded = match *extension {
+ let opt_expanded = match *ext {
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
if ident.name != keywords::Invalid.name() {
let msg =
@@ -442,10 +456,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.invocations.push(Invocation {
kind: kind,
expansion_kind: expansion_kind,
- mark: mark,
- module: self.cx.syntax_env.current_module,
- backtrace: self.cx.backtrace,
- depth: self.cx.recursion_count,
+ expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
});
placeholder(expansion_kind, mark.as_u32())
}
@@ -462,50 +473,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
}
// If `item` is an attr invocation, remove and return the macro attribute.
- fn classify_item(&self, mut item: T) -> (T, Option) {
+ fn classify_item(&mut self, mut item: T) -> (T, Option) {
let mut attr = None;
item = item.map_attrs(|mut attrs| {
- for i in 0..attrs.len() {
- if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
- match *extension {
- MultiModifier(..) | MultiDecorator(..) => {
- attr = Some(attrs.remove(i));
- break;
- }
- _ => {}
- }
- }
- }
+ attr = self.cx.resolver.find_attr_invoc(&mut attrs);
attrs
});
(item, attr)
}
- // does this attribute list contain "macro_use" ?
- fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
- for attr in attrs {
- let mut is_use = attr.check_name("macro_use");
- if attr.check_name("macro_escape") {
- let msg = "macro_escape is a deprecated synonym for macro_use";
- let mut err = self.cx.struct_span_warn(attr.span, msg);
- is_use = true;
- if let ast::AttrStyle::Inner = attr.node.style {
- err.help("consider an outer attribute, #[macro_use] mod ...").emit();
- } else {
- err.emit();
- }
- };
-
- if is_use {
- if !attr.is_word() {
- self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
- }
- return true;
- }
- }
- false
- }
-
fn configure(&mut self, node: T) -> Option {
self.cfg.configure(node)
}
@@ -574,11 +550,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
}
fn fold_block(&mut self, block: P) -> P {
- let paths = self.cx.syntax_env.paths();
- let module = self.cx.syntax_env.add_module(false, true, paths);
- let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module);
+ let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
let result = noop_fold_block(block, self);
- self.cx.syntax_env.current_module = orig_module;
+ self.cx.current_expansion.in_block = orig_in_block;
result
}
@@ -613,8 +587,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
})
}
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
- let mut paths = (*self.cx.syntax_env.paths()).clone();
- paths.mod_path.push(item.ident);
+ let mut module = (*self.cx.current_expansion.module).clone();
+ module.mod_path.push(item.ident);
// Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
// In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
@@ -622,28 +596,26 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
if inline_module {
- paths.directory.push(&*{
+ module.directory.push(&*{
::attr::first_attr_value_str_by_name(&item.attrs, "path")
.unwrap_or(item.ident.name.as_str())
});
} else {
- paths.directory =
+ module.directory =
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
- paths.directory.pop();
+ module.directory.pop();
}
- let macro_use = self.contains_macro_use(&item.attrs);
- let in_block = self.cx.syntax_env.in_block();
- let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
- let module = mem::replace(&mut self.cx.syntax_env.current_module, module);
+ let orig_module =
+ mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
let result = noop_fold_item(item, self);
- self.cx.syntax_env.current_module = module;
- result
- },
+ self.cx.current_expansion.module = orig_module;
+ return result;
+ }
ast::ItemKind::ExternCrate(..) => {
// We need to error on `#[macro_use] extern crate` when it isn't at the
// crate root, because `$crate` won't work properly.
- let is_crate_root = self.cx.syntax_env.is_crate_root();
+ let is_crate_root = self.cx.current_expansion.module.mod_path.len() == 1;
for def in self.cx.resolver.load_crate(&*item, is_crate_root) {
match def {
LoadedMacro::Def(def) => self.cx.insert_macro(def),
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
index 27e8eab62e114..34126fac4ac78 100644
--- a/src/libsyntax/ext/hygiene.rs
+++ b/src/libsyntax/ext/hygiene.rs
@@ -29,7 +29,7 @@ pub struct SyntaxContextData {
pub prev_ctxt: SyntaxContext,
}
-/// A mark represents a unique id associated with a macro expansion.
+/// A mark is a unique id associated with a macro expansion.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct Mark(u32);
@@ -41,6 +41,11 @@ impl Mark {
})
}
+ /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
+ pub fn root() -> Self {
+ Mark(0)
+ }
+
pub fn as_u32(&self) -> u32 {
self.0
}
@@ -56,8 +61,8 @@ impl HygieneData {
fn new() -> Self {
HygieneData {
syntax_contexts: vec![SyntaxContextData {
- outer_mark: Mark(0), // the null mark
- prev_ctxt: SyntaxContext(0), // the empty context
+ outer_mark: Mark::root(),
+ prev_ctxt: SyntaxContext::empty(),
}],
markings: HashMap::new(),
next_mark: Mark(1),
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 105b226111738..e75e41d0c2d4b 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -74,8 +74,8 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre
pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
-> Box {
base::check_zero_tts(cx, sp, tts, "module_path!");
- let paths = cx.syntax_env.paths();
- let string = paths.mod_path.iter().map(|x| x.to_string()).collect::>().join("::");
+ let mod_path = &cx.current_expansion.module.mod_path;
+ let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::");
base::MacEager::expr(cx.expr_str(
sp,
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index ed80ec9cbc49e..51ef45b97be6f 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
imported_from,
rhs);
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
- p.directory = cx.syntax_env.paths().directory.clone();
- p.restrictions = match cx.syntax_env.in_block() {
+ p.directory = cx.current_expansion.module.directory.clone();
+ p.restrictions = match cx.current_expansion.in_block {
true => Restrictions::NO_NONINLINE_MOD,
false => Restrictions::empty(),
};
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index fcbce36389082..6162beb80eccc 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -11,8 +11,7 @@
//! The compiler code necessary to implement the `#[derive]` extensions.
use syntax::ast::{self, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
-use syntax::ext::base::MultiModifier;
+use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap;
@@ -89,7 +88,7 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
}
}
-fn expand_derive(cx: &mut ExtCtxt,
+pub fn expand_derive(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
annotatable: Annotatable)
@@ -243,10 +242,6 @@ fn expand_derive(cx: &mut ExtCtxt,
macro_rules! derive_traits {
($( $name:expr => $func:path, )+) => {
- pub fn register_all(env: &mut SyntaxEnv) {
- env.insert(intern("derive"), MultiModifier(Box::new(expand_derive)));
- }
-
pub fn is_builtin_trait(name: &str) -> bool {
match name {
$( $name )|+ => true,
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 2065d92fd6ed7..3a6212e5445ce 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -34,11 +34,6 @@ extern crate syntax_pos;
extern crate rustc_macro;
extern crate rustc_errors as errors;
-use syntax::ext::base::{MacroExpanderFn, NormalTT};
-use syntax::ext::base::{SyntaxEnv, SyntaxExtension};
-use syntax::parse::token::intern;
-
-
mod asm;
mod cfg;
mod concat;
@@ -53,28 +48,67 @@ pub mod rustc_macro_registrar;
// for custom_derive
pub mod deriving;
-pub fn register_builtins(env: &mut SyntaxEnv) {
- // utility function to simplify creating NormalTT syntax extensions
- fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
- NormalTT(Box::new(f), None, false)
+use std::rc::Rc;
+use syntax::ast;
+use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier};
+use syntax::ext::hygiene::Mark;
+use syntax::parse::token::intern;
+
+pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
+ let mut register = |name, ext| {
+ resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
+ };
+
+ register("macro_rules", MacroRulesTT);
+
+ macro_rules! register {
+ ($( $name:ident: $f:expr, )*) => { $(
+ register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false));
+ )* }
}
- env.insert(intern("asm"), builtin_normal_expander(asm::expand_asm));
- env.insert(intern("cfg"), builtin_normal_expander(cfg::expand_cfg));
- env.insert(intern("concat"),
- builtin_normal_expander(concat::expand_syntax_ext));
- env.insert(intern("concat_idents"),
- builtin_normal_expander(concat_idents::expand_syntax_ext));
- env.insert(intern("env"), builtin_normal_expander(env::expand_env));
- env.insert(intern("option_env"),
- builtin_normal_expander(env::expand_option_env));
- env.insert(intern("format_args"),
- // format_args uses `unstable` things internally.
- NormalTT(Box::new(format::expand_format_args), None, true));
- env.insert(intern("log_syntax"),
- builtin_normal_expander(log_syntax::expand_syntax_ext));
- env.insert(intern("trace_macros"),
- builtin_normal_expander(trace_macros::expand_trace_macros));
-
- deriving::register_all(env);
+ if enable_quotes {
+ use syntax::ext::quote::*;
+ register! {
+ quote_tokens: expand_quote_tokens,
+ quote_expr: expand_quote_expr,
+ quote_ty: expand_quote_ty,
+ quote_item: expand_quote_item,
+ quote_pat: expand_quote_pat,
+ quote_arm: expand_quote_arm,
+ quote_stmt: expand_quote_stmt,
+ quote_matcher: expand_quote_matcher,
+ quote_attr: expand_quote_attr,
+ quote_arg: expand_quote_arg,
+ quote_block: expand_quote_block,
+ quote_meta_item: expand_quote_meta_item,
+ quote_path: expand_quote_path,
+ }
+ }
+
+ use syntax::ext::source_util::*;
+ register! {
+ line: expand_line,
+ column: expand_column,
+ file: expand_file,
+ stringify: expand_stringify,
+ include: expand_include,
+ include_str: expand_include_str,
+ include_bytes: expand_include_bytes,
+ module_path: expand_mod,
+
+ asm: asm::expand_asm,
+ cfg: cfg::expand_cfg,
+ concat: concat::expand_syntax_ext,
+ concat_idents: concat_idents::expand_syntax_ext,
+ env: env::expand_env,
+ option_env: env::expand_option_env,
+ log_syntax: log_syntax::expand_syntax_ext,
+ trace_macros: trace_macros::expand_trace_macros,
+ }
+
+ // format_args uses `unstable` things internally.
+ register("format_args", NormalTT(Box::new(format::expand_format_args), None, true));
+
+ register("derive", MultiModifier(Box::new(deriving::expand_derive)));
}