Extended expand.rs to support alternate expansion behaviours
Added single_step & keep_macs flags and functionality to expander
This commit is contained in:
@@ -672,13 +672,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
|||||||
cfg,
|
cfg,
|
||||||
&mut loader);
|
&mut loader);
|
||||||
syntax_ext::register_builtins(&mut ecx.syntax_env);
|
syntax_ext::register_builtins(&mut ecx.syntax_env);
|
||||||
let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx,
|
let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
|
||||||
syntax_exts,
|
|
||||||
krate);
|
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
env::set_var("PATH", &old_path);
|
env::set_var("PATH", &old_path);
|
||||||
}
|
}
|
||||||
*sess.available_macros.borrow_mut() = macro_names;
|
*sess.available_macros.borrow_mut() = ecx.syntax_env.names;
|
||||||
ret
|
ret
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ impl<'a> ExtCtxt<'a> {
|
|||||||
|
|
||||||
/// Returns a `Folder` for deeply expanding all macros in an AST node.
|
/// Returns a `Folder` for deeply expanding all macros in an AST node.
|
||||||
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
|
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
|
||||||
expand::MacroExpander::new(self)
|
expand::MacroExpander::new(self, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
|
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// 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 ast::{Block, Crate, Ident, Mac_, Name, PatKind};
|
use ast::{Block, Crate, Ident, Mac_, PatKind};
|
||||||
use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
|
use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
|
||||||
use ast;
|
use ast;
|
||||||
use ext::hygiene::Mark;
|
use ext::hygiene::Mark;
|
||||||
@@ -29,8 +29,6 @@ use visit;
|
|||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
use std_inject;
|
use std_inject;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
// A trait for AST nodes and AST node lists into which macro invocations may expand.
|
// A trait for AST nodes and AST node lists into which macro invocations may expand.
|
||||||
trait MacroGenerable: Sized {
|
trait MacroGenerable: Sized {
|
||||||
// Expand the given MacResult using its appropriate `make_*` method.
|
// Expand the given MacResult using its appropriate `make_*` method.
|
||||||
@@ -218,8 +216,7 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// DON'T mark before expansion.
|
let def = ast::MacroDef {
|
||||||
fld.cx.insert_macro(ast::MacroDef {
|
|
||||||
ident: ident,
|
ident: ident,
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
span: call_site,
|
span: call_site,
|
||||||
@@ -229,10 +226,30 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
|
|||||||
export: attr::contains_name(&attrs, "macro_export"),
|
export: attr::contains_name(&attrs, "macro_export"),
|
||||||
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
|
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
});
|
};
|
||||||
|
|
||||||
// macro_rules! has a side effect but expands to nothing.
|
fld.cx.insert_macro(def.clone());
|
||||||
Some(Box::new(MacroScopePlaceholder))
|
|
||||||
|
// macro_rules! has a side effect, but expands to nothing.
|
||||||
|
// If keep_macs is true, expands to a MacEager::items instead.
|
||||||
|
if fld.keep_macs {
|
||||||
|
Some(MacEager::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: path.clone(),
|
||||||
|
tts: def.body.clone(),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
vis: ast::Visibility::Inherited,
|
||||||
|
span: def.span,
|
||||||
|
}))))
|
||||||
|
} else {
|
||||||
|
Some(Box::new(MacroScopePlaceholder))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiDecorator(..) | MultiModifier(..) => {
|
MultiDecorator(..) | MultiModifier(..) => {
|
||||||
@@ -260,7 +277,13 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
|
|||||||
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
|
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
|
||||||
let configured = marked.fold_with(&mut fld.strip_unconfigured());
|
let configured = marked.fold_with(&mut fld.strip_unconfigured());
|
||||||
fld.load_macros(&configured);
|
fld.load_macros(&configured);
|
||||||
let fully_expanded = configured.fold_with(fld);
|
|
||||||
|
let fully_expanded = if fld.single_step {
|
||||||
|
configured
|
||||||
|
} else {
|
||||||
|
configured.fold_with(fld)
|
||||||
|
};
|
||||||
|
|
||||||
fld.cx.bt_pop();
|
fld.cx.bt_pop();
|
||||||
fully_expanded
|
fully_expanded
|
||||||
}
|
}
|
||||||
@@ -491,11 +514,19 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
|
|||||||
/// A tree-folder that performs macro expansion
|
/// 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 keep_macs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> MacroExpander<'a, 'b> {
|
impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
|
pub fn new(cx: &'a mut ExtCtxt<'b>,
|
||||||
MacroExpander { cx: cx }
|
single_step: bool,
|
||||||
|
keep_macs: bool) -> MacroExpander<'a, 'b> {
|
||||||
|
MacroExpander {
|
||||||
|
cx: cx,
|
||||||
|
single_step: single_step,
|
||||||
|
keep_macs: keep_macs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strip_unconfigured(&mut self) -> StripUnconfigured {
|
fn strip_unconfigured(&mut self) -> StripUnconfigured {
|
||||||
@@ -673,38 +704,45 @@ impl<'feat> ExpansionConfig<'feat> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_crate(mut cx: ExtCtxt,
|
pub fn expand_crate(cx: &mut ExtCtxt,
|
||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
mut c: Crate) -> (Crate, HashSet<Name>) {
|
c: Crate) -> Crate {
|
||||||
|
let mut expander = MacroExpander::new(cx, false, false);
|
||||||
|
expand_crate_with_expander(&mut expander, user_exts, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expands crate using supplied MacroExpander - allows for
|
||||||
|
// non-standard expansion behaviour (e.g. step-wise).
|
||||||
|
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
|
||||||
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
|
mut c: Crate) -> Crate {
|
||||||
if std_inject::no_core(&c) {
|
if std_inject::no_core(&c) {
|
||||||
cx.crate_root = None;
|
expander.cx.crate_root = None;
|
||||||
} else if std_inject::no_std(&c) {
|
} else if std_inject::no_std(&c) {
|
||||||
cx.crate_root = Some("core");
|
expander.cx.crate_root = Some("core");
|
||||||
} else {
|
} else {
|
||||||
cx.crate_root = Some("std");
|
expander.cx.crate_root = Some("std");
|
||||||
}
|
}
|
||||||
let ret = {
|
|
||||||
let mut expander = MacroExpander::new(&mut cx);
|
|
||||||
|
|
||||||
for (name, extension) in user_exts {
|
// User extensions must be added before expander.load_macros is called,
|
||||||
expander.cx.syntax_env.insert(name, extension);
|
// so that macros from external crates shadow user defined extensions.
|
||||||
}
|
for (name, extension) in user_exts {
|
||||||
|
expander.cx.syntax_env.insert(name, extension);
|
||||||
|
}
|
||||||
|
|
||||||
let items = SmallVector::many(c.module.items);
|
let items = SmallVector::many(c.module.items);
|
||||||
expander.load_macros(&items);
|
expander.load_macros(&items);
|
||||||
c.module.items = items.into();
|
c.module.items = items.into();
|
||||||
|
|
||||||
let err_count = cx.parse_sess.span_diagnostic.err_count();
|
let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
|
||||||
let mut ret = expander.fold_crate(c);
|
let mut ret = expander.fold_crate(c);
|
||||||
ret.exported_macros = expander.cx.exported_macros.clone();
|
ret.exported_macros = expander.cx.exported_macros.clone();
|
||||||
|
|
||||||
if cx.parse_sess.span_diagnostic.err_count() > err_count {
|
if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
||||||
cx.parse_sess.span_diagnostic.abort_if_errors();
|
expander.cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret
|
ret
|
||||||
};
|
|
||||||
return (ret, cx.syntax_env.names);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Marker adds the given mark to the syntax context and
|
// A Marker adds the given mark to the syntax context and
|
||||||
@@ -780,8 +818,8 @@ mod tests {
|
|||||||
Vec::new(), &sess).unwrap();
|
Vec::new(), &sess).unwrap();
|
||||||
// should fail:
|
// should fail:
|
||||||
let mut loader = DummyMacroLoader;
|
let mut loader = DummyMacroLoader;
|
||||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
|
let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
|
||||||
expand_crate(ecx, vec![], crate_ast);
|
expand_crate(&mut ecx, vec![], crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that macros can't escape modules
|
// make sure that macros can't escape modules
|
||||||
@@ -795,8 +833,8 @@ mod tests {
|
|||||||
src,
|
src,
|
||||||
Vec::new(), &sess).unwrap();
|
Vec::new(), &sess).unwrap();
|
||||||
let mut loader = DummyMacroLoader;
|
let mut loader = DummyMacroLoader;
|
||||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
|
let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
|
||||||
expand_crate(ecx, vec![], crate_ast);
|
expand_crate(&mut ecx, vec![], crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
// macro_use modules should allow macros to escape
|
// macro_use modules should allow macros to escape
|
||||||
@@ -809,8 +847,8 @@ mod tests {
|
|||||||
src,
|
src,
|
||||||
Vec::new(), &sess).unwrap();
|
Vec::new(), &sess).unwrap();
|
||||||
let mut loader = DummyMacroLoader;
|
let mut loader = DummyMacroLoader;
|
||||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
|
let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
|
||||||
expand_crate(ecx, vec![], crate_ast);
|
expand_crate(&mut ecx, vec![], crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_crate_str(crate_str: String) -> ast::Crate {
|
fn expand_crate_str(crate_str: String) -> ast::Crate {
|
||||||
@@ -818,8 +856,8 @@ mod tests {
|
|||||||
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
|
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
|
||||||
// the cfg argument actually does matter, here...
|
// the cfg argument actually does matter, here...
|
||||||
let mut loader = DummyMacroLoader;
|
let mut loader = DummyMacroLoader;
|
||||||
let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
|
let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
|
||||||
expand_crate(ecx, vec![], crate_ast).0
|
expand_crate(&mut ecx, vec![], crate_ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test] fn macro_tokens_should_match(){
|
#[test] fn macro_tokens_should_match(){
|
||||||
|
|||||||
Reference in New Issue
Block a user