Implement stackless expansion.
This commit is contained in:
parent
c07ff8d26a
commit
d986bbe674
4 changed files with 194 additions and 181 deletions
|
@ -646,7 +646,6 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bt_push(&mut self, ei: ExpnInfo) {
|
pub fn bt_push(&mut self, ei: ExpnInfo) {
|
||||||
self.recursion_count += 1;
|
|
||||||
if self.recursion_count > self.ecfg.recursion_limit {
|
if self.recursion_count > self.ecfg.recursion_limit {
|
||||||
self.span_fatal(ei.call_site,
|
self.span_fatal(ei.call_site,
|
||||||
&format!("recursion limit reached while expanding the macro `{}`",
|
&format!("recursion limit reached while expanding the macro `{}`",
|
||||||
|
@ -660,17 +659,7 @@ impl<'a> ExtCtxt<'a> {
|
||||||
callee: ei.callee
|
callee: ei.callee
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pub fn bt_pop(&mut self) {
|
pub fn bt_pop(&mut self) {}
|
||||||
match self.backtrace {
|
|
||||||
NO_EXPANSION => self.bug("tried to pop without a push"),
|
|
||||||
expn_id => {
|
|
||||||
self.recursion_count -= 1;
|
|
||||||
self.backtrace = self.codemap().with_expn_info(expn_id, |expn_info| {
|
|
||||||
expn_info.map_or(NO_EXPANSION, |ei| ei.call_site.expn_id)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_macro(&mut self, def: ast::MacroDef) {
|
pub fn insert_macro(&mut self, def: ast::MacroDef) {
|
||||||
if def.export {
|
if def.export {
|
||||||
|
@ -799,8 +788,6 @@ impl<'a> ExtCtxt<'a> {
|
||||||
self.crate_root = Some("std");
|
self.crate_root = Some("std");
|
||||||
}
|
}
|
||||||
|
|
||||||
// User extensions must be added before expander.load_macros is called,
|
|
||||||
// so that macros from external crates shadow user defined extensions.
|
|
||||||
for (name, extension) in user_exts {
|
for (name, extension) in user_exts {
|
||||||
self.syntax_env.insert(name, extension);
|
self.syntax_env.insert(name, extension);
|
||||||
}
|
}
|
||||||
|
@ -900,7 +887,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
|
||||||
/// This environment maps Names to SyntaxExtensions.
|
/// This environment maps Names to SyntaxExtensions.
|
||||||
pub struct SyntaxEnv {
|
pub struct SyntaxEnv {
|
||||||
module_data: Vec<ModuleData>,
|
module_data: Vec<ModuleData>,
|
||||||
current_module: Module,
|
pub current_module: Module,
|
||||||
|
|
||||||
/// All bang-style macro/extension names
|
/// All bang-style macro/extension names
|
||||||
/// encountered so far; to be used for diagnostics in resolve
|
/// encountered so far; to be used for diagnostics in resolve
|
||||||
|
@ -940,10 +927,6 @@ impl SyntaxEnv {
|
||||||
&self.module_data[module.0 as usize]
|
&self.module_data[module.0 as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_current_module(&mut self, module: Module) -> Module {
|
|
||||||
::std::mem::replace(&mut self.current_module, module)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paths(&self) -> Rc<ModulePaths> {
|
pub fn paths(&self) -> Rc<ModulePaths> {
|
||||||
self.data(self.current_module).paths.clone()
|
self.data(self.current_module).paths.clone()
|
||||||
}
|
}
|
||||||
|
@ -994,8 +977,6 @@ impl SyntaxEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_crate_root(&mut self) -> bool {
|
pub fn is_crate_root(&mut self) -> bool {
|
||||||
// The first frame is pushed in `SyntaxEnv::new()` and the second frame is
|
self.current_module == Module(0)
|
||||||
// pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
|
|
||||||
self.current_module.0 <= 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use ast::{Block, Crate, Ident, Mac_, PatKind};
|
||||||
use ast::{MacStmtStyle, StmtKind, ItemKind};
|
use ast::{MacStmtStyle, StmtKind, ItemKind};
|
||||||
use ast;
|
use ast;
|
||||||
use ext::hygiene::Mark;
|
use ext::hygiene::Mark;
|
||||||
use ext::placeholders;
|
use ext::placeholders::{self, placeholder, PlaceholderExpander};
|
||||||
use attr::{self, HasAttrs};
|
use attr::{self, HasAttrs};
|
||||||
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
|
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
|
||||||
use syntax_pos::{self, Span, ExpnId};
|
use syntax_pos::{self, Span, ExpnId};
|
||||||
|
@ -28,11 +28,13 @@ use util::small_vector::SmallVector;
|
||||||
use visit;
|
use visit;
|
||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
macro_rules! expansions {
|
macro_rules! expansions {
|
||||||
($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
|
($($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)*;)*) => {
|
$(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -91,18 +93,32 @@ macro_rules! expansions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
|
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
||||||
|
self.expand(Expansion::OptExpr(Some(expr))).make_opt_expr()
|
||||||
|
}
|
||||||
|
$($(fn $fold(&mut self, node: $ty) -> $ty {
|
||||||
|
self.expand(Expansion::$kind(node)).$make()
|
||||||
|
})*)*
|
||||||
|
$($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty {
|
||||||
|
self.expand(Expansion::$kind(SmallVector::one(node))).$make()
|
||||||
|
})*)*
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expansions! {
|
expansions! {
|
||||||
Expr: P<ast::Expr>, "expression", .make_expr, .fold_expr, .visit_expr;
|
Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr, .visit_expr;
|
||||||
Pat: P<ast::Pat>, "pattern", .make_pat, .fold_pat, .visit_pat;
|
Pat: P<ast::Pat> [], "pattern", .make_pat, .fold_pat, .visit_pat;
|
||||||
Ty: P<ast::Ty>, "type", .make_ty, .fold_ty, .visit_ty;
|
Ty: P<ast::Ty> [], "type", .make_ty, .fold_ty, .visit_ty;
|
||||||
Stmts: SmallVector<ast::Stmt>, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
|
Stmts: SmallVector<ast::Stmt> [SmallVector, ast::Stmt],
|
||||||
Items: SmallVector<P<ast::Item>>, "item", .make_items, lift .fold_item, lift .visit_item;
|
"statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
|
||||||
TraitItems: SmallVector<ast::TraitItem>,
|
Items: SmallVector<P<ast::Item>> [SmallVector, P<ast::Item>],
|
||||||
|
"item", .make_items, lift .fold_item, lift .visit_item;
|
||||||
|
TraitItems: SmallVector<ast::TraitItem> [SmallVector, ast::TraitItem],
|
||||||
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
|
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
|
||||||
ImplItems: SmallVector<ast::ImplItem>,
|
ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
|
||||||
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
|
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +145,9 @@ pub struct Invocation {
|
||||||
kind: InvocationKind,
|
kind: InvocationKind,
|
||||||
expansion_kind: ExpansionKind,
|
expansion_kind: ExpansionKind,
|
||||||
mark: Mark,
|
mark: Mark,
|
||||||
|
module: Module,
|
||||||
|
backtrace: ExpnId,
|
||||||
|
depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InvocationKind {
|
enum InvocationKind {
|
||||||
|
@ -144,7 +163,6 @@ enum InvocationKind {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tree-folder that performs macro expansion
|
|
||||||
pub struct MacroExpander<'a, 'b:'a> {
|
pub struct MacroExpander<'a, 'b:'a> {
|
||||||
pub cx: &'a mut ExtCtxt<'b>,
|
pub cx: &'a mut ExtCtxt<'b>,
|
||||||
pub single_step: bool,
|
pub single_step: bool,
|
||||||
|
@ -162,13 +180,57 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strip_unconfigured(&mut self) -> StripUnconfigured {
|
fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||||
StripUnconfigured {
|
let err_count = self.cx.parse_sess.span_diagnostic.err_count();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
||||||
|
self.cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
krate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fully expand all the invocations in `expansion`.
|
||||||
|
fn expand(&mut self, expansion: Expansion) -> Expansion {
|
||||||
|
let (expansion, mut invocations) = self.collect_invocations(expansion);
|
||||||
|
invocations.reverse();
|
||||||
|
|
||||||
|
let mut expansions = HashMap::new();
|
||||||
|
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 expansion = self.expand_invoc(invoc);
|
||||||
|
|
||||||
|
self.cx.syntax_env.current_module = module;
|
||||||
|
self.cx.recursion_count = depth + 1;
|
||||||
|
let (expansion, new_invocations) = self.collect_invocations(expansion);
|
||||||
|
|
||||||
|
expansions.insert(mark.as_u32(), expansion);
|
||||||
|
if !self.single_step {
|
||||||
|
invocations.extend(new_invocations.into_iter().rev());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expansion.fold_with(&mut PlaceholderExpander::new(expansions))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
|
||||||
|
let expansion = expansion.fold_with(&mut StripUnconfigured {
|
||||||
config: &self.cx.cfg,
|
config: &self.cx.cfg,
|
||||||
should_test: self.cx.ecfg.should_test,
|
should_test: self.cx.ecfg.should_test,
|
||||||
sess: self.cx.parse_sess,
|
sess: self.cx.parse_sess,
|
||||||
features: self.cx.ecfg.features,
|
features: self.cx.ecfg.features,
|
||||||
}
|
});
|
||||||
|
self.load_macros(&expansion);
|
||||||
|
let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() };
|
||||||
|
(expansion.fold_with(&mut collector), collector.invocations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_macros(&mut self, node: &Expansion) {
|
fn load_macros(&mut self, node: &Expansion) {
|
||||||
|
@ -210,72 +272,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_invoc(&self, expansion_kind: ExpansionKind, kind: InvocationKind)
|
|
||||||
-> Invocation {
|
|
||||||
Invocation { mark: Mark::fresh(), kind: kind, expansion_kind: expansion_kind }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_bang_invoc(
|
|
||||||
&self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind,
|
|
||||||
) -> Invocation {
|
|
||||||
self.new_invoc(kind, InvocationKind::Bang {
|
|
||||||
attrs: attrs,
|
|
||||||
mac: mac,
|
|
||||||
ident: None,
|
|
||||||
span: span,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_attr_invoc(&self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
|
|
||||||
-> Invocation {
|
|
||||||
self.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item })
|
|
||||||
}
|
|
||||||
|
|
||||||
// If `item` is an attr invocation, remove and return the macro attribute.
|
|
||||||
fn classify_item<T: HasAttrs>(&self, mut item: T) -> (T, Option<ast::Attribute>) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 expand_invoc(&mut self, invoc: Invocation) -> Expansion {
|
fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
|
||||||
match invoc.kind {
|
match invoc.kind {
|
||||||
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
|
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
|
||||||
|
@ -305,7 +301,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let modified = match *extension {
|
match *extension {
|
||||||
MultiModifier(ref mac) => {
|
MultiModifier(ref mac) => {
|
||||||
let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
|
let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
|
||||||
kind.expect_from_annotatables(item)
|
kind.expect_from_annotatables(item)
|
||||||
|
@ -318,12 +314,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
kind.expect_from_annotatables(items)
|
kind.expect_from_annotatables(items)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
}
|
||||||
|
|
||||||
self.cx.bt_pop();
|
|
||||||
|
|
||||||
let configured = modified.fold_with(&mut self.strip_unconfigured());
|
|
||||||
configured.fold_with(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand a macro invocation. Returns the result of expansion.
|
/// Expand a macro invocation. Returns the result of expansion.
|
||||||
|
@ -457,30 +448,94 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
};
|
};
|
||||||
|
|
||||||
let marked = expanded.fold_with(&mut Marker {
|
expanded.fold_with(&mut Marker {
|
||||||
mark: mark,
|
mark: mark,
|
||||||
expn_id: Some(self.cx.backtrace())
|
expn_id: Some(self.cx.backtrace()),
|
||||||
});
|
})
|
||||||
let configured = marked.fold_with(&mut self.strip_unconfigured());
|
|
||||||
self.load_macros(&configured);
|
|
||||||
|
|
||||||
let fully_expanded = if self.single_step {
|
|
||||||
configured
|
|
||||||
} else {
|
|
||||||
configured.fold_with(self)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.cx.bt_pop();
|
|
||||||
fully_expanded
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
struct InvocationCollector<'a, 'b: 'a> {
|
||||||
|
cx: &'a mut ExtCtxt<'b>,
|
||||||
|
invocations: Vec<Invocation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
|
fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion {
|
||||||
|
let mark = Mark::fresh();
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
placeholder(expansion_kind, mark.as_u32())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_bang(
|
||||||
|
&mut self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind,
|
||||||
|
) -> Expansion {
|
||||||
|
self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
|
||||||
|
-> Expansion {
|
||||||
|
self.collect(kind, InvocationKind::Attr { attr: attr, item: item })
|
||||||
|
}
|
||||||
|
|
||||||
|
// If `item` is an attr invocation, remove and return the macro attribute.
|
||||||
|
fn classify_item<T: HasAttrs>(&self, mut item: T) -> (T, Option<ast::Attribute>) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||||
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
|
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
|
||||||
let expr = expr.unwrap();
|
let expr = expr.unwrap();
|
||||||
if let ast::ExprKind::Mac(mac) = expr.node {
|
if let ast::ExprKind::Mac(mac) = expr.node {
|
||||||
let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
|
self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr()
|
||||||
self.expand_invoc(invoc).make_expr()
|
|
||||||
} else {
|
} else {
|
||||||
P(noop_fold_expr(expr, self))
|
P(noop_fold_expr(expr, self))
|
||||||
}
|
}
|
||||||
|
@ -489,9 +544,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
||||||
let expr = expr.unwrap();
|
let expr = expr.unwrap();
|
||||||
if let ast::ExprKind::Mac(mac) = expr.node {
|
if let ast::ExprKind::Mac(mac) = expr.node {
|
||||||
let invoc =
|
self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr)
|
||||||
self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
|
.make_opt_expr()
|
||||||
self.expand_invoc(invoc).make_opt_expr()
|
|
||||||
} else {
|
} else {
|
||||||
Some(P(noop_fold_expr(expr, self)))
|
Some(P(noop_fold_expr(expr, self)))
|
||||||
}
|
}
|
||||||
|
@ -504,10 +558,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pat.and_then(|pat| match pat.node {
|
pat.and_then(|pat| match pat.node {
|
||||||
PatKind::Mac(mac) => {
|
PatKind::Mac(mac) =>
|
||||||
let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
|
self.collect_bang(mac, Vec::new(), pat.span, ExpansionKind::Pat).make_pat(),
|
||||||
self.expand_invoc(invoc).make_pat()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -518,35 +570,34 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
_ => return noop_fold_stmt(stmt, self),
|
_ => return noop_fold_stmt(stmt, self),
|
||||||
};
|
};
|
||||||
|
|
||||||
let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
|
let mut placeholder =
|
||||||
let mut fully_expanded = self.expand_invoc(invoc).make_stmts();
|
self.collect_bang(mac, attrs.into(), stmt.span, ExpansionKind::Stmts).make_stmts();
|
||||||
|
|
||||||
// If this is a macro invocation with a semicolon, then apply that
|
// If this is a macro invocation with a semicolon, then apply that
|
||||||
// semicolon to the final statement produced by expansion.
|
// semicolon to the final statement produced by expansion.
|
||||||
if style == MacStmtStyle::Semicolon {
|
if style == MacStmtStyle::Semicolon {
|
||||||
if let Some(stmt) = fully_expanded.pop() {
|
if let Some(stmt) = placeholder.pop() {
|
||||||
fully_expanded.push(stmt.add_trailing_semicolon());
|
placeholder.push(stmt.add_trailing_semicolon());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fully_expanded
|
placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
|
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
|
||||||
let paths = self.cx.syntax_env.paths();
|
let paths = self.cx.syntax_env.paths();
|
||||||
let module = self.cx.syntax_env.add_module(false, true, paths);
|
let module = self.cx.syntax_env.add_module(false, true, paths);
|
||||||
let orig_module = self.cx.syntax_env.set_current_module(module);
|
let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module);
|
||||||
|
|
||||||
let result = noop_fold_block(block, self);
|
let result = noop_fold_block(block, self);
|
||||||
self.cx.syntax_env.set_current_module(orig_module);
|
self.cx.syntax_env.current_module = orig_module;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
|
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
|
||||||
let (item, attr) = self.classify_item(item);
|
let (item, attr) = self.classify_item(item);
|
||||||
if let Some(attr) = attr {
|
if let Some(attr) = attr {
|
||||||
let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
|
let item = Annotatable::Item(item);
|
||||||
return self.expand_invoc(invoc).make_items();
|
return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
|
||||||
}
|
}
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
|
@ -560,13 +611,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
|
|
||||||
item.and_then(|item| match item.node {
|
item.and_then(|item| match item.node {
|
||||||
ItemKind::Mac(mac) => {
|
ItemKind::Mac(mac) => {
|
||||||
let invoc = self.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
|
self.collect(ExpansionKind::Items, InvocationKind::Bang {
|
||||||
mac: mac,
|
mac: mac,
|
||||||
attrs: item.attrs,
|
attrs: item.attrs,
|
||||||
ident: Some(item.ident),
|
ident: Some(item.ident),
|
||||||
span: item.span,
|
span: item.span,
|
||||||
});
|
}).make_items()
|
||||||
self.expand_invoc(invoc).make_items()
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
|
@ -590,9 +640,9 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
let macro_use = self.contains_macro_use(&item.attrs);
|
let macro_use = self.contains_macro_use(&item.attrs);
|
||||||
let in_block = self.cx.syntax_env.in_block();
|
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 = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
|
||||||
let module = self.cx.syntax_env.set_current_module(module);
|
let module = mem::replace(&mut self.cx.syntax_env.current_module, module);
|
||||||
let result = noop_fold_item(item, self);
|
let result = noop_fold_item(item, self);
|
||||||
self.cx.syntax_env.set_current_module(module);
|
self.cx.syntax_env.current_module = module;
|
||||||
result
|
result
|
||||||
},
|
},
|
||||||
_ => noop_fold_item(item, self),
|
_ => noop_fold_item(item, self),
|
||||||
|
@ -603,15 +653,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
let (item, attr) = self.classify_item(item);
|
let (item, attr) = self.classify_item(item);
|
||||||
if let Some(attr) = attr {
|
if let Some(attr) = attr {
|
||||||
let item = Annotatable::TraitItem(P(item));
|
let item = Annotatable::TraitItem(P(item));
|
||||||
let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
|
return self.collect_attr(attr, item, ExpansionKind::TraitItems).make_trait_items()
|
||||||
return self.expand_invoc(invoc).make_trait_items();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::TraitItemKind::Macro(mac) => {
|
ast::TraitItemKind::Macro(mac) => {
|
||||||
let ast::TraitItem { attrs, span, .. } = item;
|
let ast::TraitItem { attrs, span, .. } = item;
|
||||||
let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
|
self.collect_bang(mac, attrs, span, ExpansionKind::TraitItems).make_trait_items()
|
||||||
self.expand_invoc(invoc).make_trait_items()
|
|
||||||
}
|
}
|
||||||
_ => fold::noop_fold_trait_item(item, self),
|
_ => fold::noop_fold_trait_item(item, self),
|
||||||
}
|
}
|
||||||
|
@ -621,15 +669,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
let (item, attr) = self.classify_item(item);
|
let (item, attr) = self.classify_item(item);
|
||||||
if let Some(attr) = attr {
|
if let Some(attr) = attr {
|
||||||
let item = Annotatable::ImplItem(P(item));
|
let item = Annotatable::ImplItem(P(item));
|
||||||
let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
|
return self.collect_attr(attr, item, ExpansionKind::ImplItems).make_impl_items();
|
||||||
return self.expand_invoc(invoc).make_impl_items();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ImplItemKind::Macro(mac) => {
|
ast::ImplItemKind::Macro(mac) => {
|
||||||
let ast::ImplItem { attrs, span, .. } = item;
|
let ast::ImplItem { attrs, span, .. } = item;
|
||||||
let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
|
self.collect_bang(mac, attrs, span, ExpansionKind::ImplItems).make_impl_items()
|
||||||
self.expand_invoc(invoc).make_impl_items()
|
|
||||||
}
|
}
|
||||||
_ => fold::noop_fold_impl_item(item, self),
|
_ => fold::noop_fold_impl_item(item, self),
|
||||||
}
|
}
|
||||||
|
@ -642,10 +688,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match ty.node {
|
match ty.node {
|
||||||
ast::TyKind::Mac(mac) => {
|
ast::TyKind::Mac(mac) =>
|
||||||
let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
|
self.collect_bang(mac, Vec::new(), ty.span, ExpansionKind::Ty).make_ty(),
|
||||||
self.expand_invoc(invoc).make_ty()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -699,30 +743,17 @@ impl<'feat> ExpansionConfig<'feat> {
|
||||||
pub fn expand_crate(cx: &mut ExtCtxt,
|
pub fn expand_crate(cx: &mut ExtCtxt,
|
||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
c: Crate) -> Crate {
|
c: Crate) -> Crate {
|
||||||
let mut expander = MacroExpander::new(cx, false, false);
|
cx.initialize(user_exts, &c);
|
||||||
expand_crate_with_expander(&mut expander, user_exts, c)
|
cx.expander().expand_crate(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expands crate using supplied MacroExpander - allows for
|
// Expands crate using supplied MacroExpander - allows for
|
||||||
// non-standard expansion behaviour (e.g. step-wise).
|
// non-standard expansion behaviour (e.g. step-wise).
|
||||||
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
|
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
|
||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
mut c: Crate) -> Crate {
|
c: Crate) -> Crate {
|
||||||
expander.cx.initialize(user_exts, &c);
|
expander.cx.initialize(user_exts, &c);
|
||||||
|
expander.expand_crate(c)
|
||||||
let items = Expansion::Items(SmallVector::many(c.module.items));
|
|
||||||
let configured = items.fold_with(&mut expander.strip_unconfigured());
|
|
||||||
expander.load_macros(&configured);
|
|
||||||
c.module.items = configured.make_items().into();
|
|
||||||
|
|
||||||
let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
|
|
||||||
let mut ret = expander.fold_crate(c);
|
|
||||||
if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
|
||||||
expander.cx.parse_sess.span_diagnostic.abort_if_errors();
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.exported_macros = expander.cx.exported_macros.clone();
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Marker adds the given mark to the syntax context and
|
// A Marker adds the given mark to the syntax context and
|
||||||
|
|
|
@ -40,6 +40,10 @@ impl Mark {
|
||||||
::std::mem::replace(&mut data.next_mark, next_mark)
|
::std::mem::replace(&mut data.next_mark, next_mark)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_u32(&self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HygieneData {
|
struct HygieneData {
|
||||||
|
|
|
@ -300,14 +300,11 @@ fn generate_test_harness(sess: &ParseSess,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut fold = TestHarnessGenerator {
|
TestHarnessGenerator {
|
||||||
cx: cx,
|
cx: cx,
|
||||||
tests: Vec::new(),
|
tests: Vec::new(),
|
||||||
tested_submods: Vec::new(),
|
tested_submods: Vec::new(),
|
||||||
};
|
}.fold_crate(krate)
|
||||||
let res = fold.fold_crate(krate);
|
|
||||||
fold.cx.ext_cx.bt_pop();
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Craft a span that will be ignored by the stability lint's
|
/// Craft a span that will be ignored by the stability lint's
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue