Skip to content

Commit 61c7569

Browse files
Extended expand.rs to support alternate expansion behaviours
Added single_step & keep_macs flags and functionality to expander
1 parent f2e59cc commit 61c7569

File tree

3 files changed

+82
-46
lines changed

3 files changed

+82
-46
lines changed

src/librustc_driver/driver.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -672,13 +672,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
672672
cfg,
673673
&mut loader);
674674
syntax_ext::register_builtins(&mut ecx.syntax_env);
675-
let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx,
676-
syntax_exts,
677-
krate);
675+
let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
678676
if cfg!(windows) {
679677
env::set_var("PATH", &old_path);
680678
}
681-
*sess.available_macros.borrow_mut() = macro_names;
679+
*sess.available_macros.borrow_mut() = ecx.syntax_env.names;
682680
ret
683681
});
684682

src/libsyntax/ext/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ impl<'a> ExtCtxt<'a> {
633633

634634
/// Returns a `Folder` for deeply expanding all macros in an AST node.
635635
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
636-
expand::MacroExpander::new(self)
636+
expand::MacroExpander::new(self, false, false)
637637
}
638638

639639
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])

src/libsyntax/ext/expand.rs

+79-41
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use ast::{Block, Crate, Ident, Mac_, Name, PatKind};
11+
use ast::{Block, Crate, Ident, Mac_, PatKind};
1212
use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
1313
use ast;
1414
use ext::hygiene::Mark;
@@ -29,8 +29,6 @@ use visit;
2929
use visit::Visitor;
3030
use std_inject;
3131

32-
use std::collections::HashSet;
33-
3432
// A trait for AST nodes and AST node lists into which macro invocations may expand.
3533
trait MacroGenerable: Sized {
3634
// 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
218216
}
219217
});
220218

221-
// DON'T mark before expansion.
222-
fld.cx.insert_macro(ast::MacroDef {
219+
let def = ast::MacroDef {
223220
ident: ident,
224221
id: ast::DUMMY_NODE_ID,
225222
span: call_site,
@@ -229,10 +226,30 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
229226
export: attr::contains_name(&attrs, "macro_export"),
230227
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
231228
attrs: attrs,
232-
});
229+
};
233230

234-
// macro_rules! has a side effect but expands to nothing.
235-
Some(Box::new(MacroScopePlaceholder))
231+
fld.cx.insert_macro(def.clone());
232+
233+
// macro_rules! has a side effect, but expands to nothing.
234+
// If keep_macs is true, expands to a MacEager::items instead.
235+
if fld.keep_macs {
236+
Some(MacEager::items(SmallVector::one(P(ast::Item {
237+
ident: def.ident,
238+
attrs: def.attrs.clone(),
239+
id: ast::DUMMY_NODE_ID,
240+
node: ast::ItemKind::Mac(ast::Mac {
241+
span: def.span,
242+
node: ast::Mac_ {
243+
path: path.clone(),
244+
tts: def.body.clone(),
245+
}
246+
}),
247+
vis: ast::Visibility::Inherited,
248+
span: def.span,
249+
}))))
250+
} else {
251+
Some(Box::new(MacroScopePlaceholder))
252+
}
236253
}
237254

238255
MultiDecorator(..) | MultiModifier(..) => {
@@ -260,7 +277,13 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
260277
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
261278
let configured = marked.fold_with(&mut fld.strip_unconfigured());
262279
fld.load_macros(&configured);
263-
let fully_expanded = configured.fold_with(fld);
280+
281+
let fully_expanded = if fld.single_step {
282+
configured
283+
} else {
284+
configured.fold_with(fld)
285+
};
286+
264287
fld.cx.bt_pop();
265288
fully_expanded
266289
}
@@ -491,11 +514,19 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
491514
/// A tree-folder that performs macro expansion
492515
pub struct MacroExpander<'a, 'b:'a> {
493516
pub cx: &'a mut ExtCtxt<'b>,
517+
pub single_step: bool,
518+
pub keep_macs: bool,
494519
}
495520

496521
impl<'a, 'b> MacroExpander<'a, 'b> {
497-
pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
498-
MacroExpander { cx: cx }
522+
pub fn new(cx: &'a mut ExtCtxt<'b>,
523+
single_step: bool,
524+
keep_macs: bool) -> MacroExpander<'a, 'b> {
525+
MacroExpander {
526+
cx: cx,
527+
single_step: single_step,
528+
keep_macs: keep_macs
529+
}
499530
}
500531

501532
fn strip_unconfigured(&mut self) -> StripUnconfigured {
@@ -673,38 +704,45 @@ impl<'feat> ExpansionConfig<'feat> {
673704
}
674705
}
675706

676-
pub fn expand_crate(mut cx: ExtCtxt,
707+
pub fn expand_crate(cx: &mut ExtCtxt,
677708
user_exts: Vec<NamedSyntaxExtension>,
678-
mut c: Crate) -> (Crate, HashSet<Name>) {
709+
c: Crate) -> Crate {
710+
let mut expander = MacroExpander::new(cx, false, false);
711+
expand_crate_with_expander(&mut expander, user_exts, c)
712+
}
713+
714+
// Expands crate using supplied MacroExpander - allows for
715+
// non-standard expansion behaviour (e.g. step-wise).
716+
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
717+
user_exts: Vec<NamedSyntaxExtension>,
718+
mut c: Crate) -> Crate {
679719
if std_inject::no_core(&c) {
680-
cx.crate_root = None;
720+
expander.cx.crate_root = None;
681721
} else if std_inject::no_std(&c) {
682-
cx.crate_root = Some("core");
722+
expander.cx.crate_root = Some("core");
683723
} else {
684-
cx.crate_root = Some("std");
724+
expander.cx.crate_root = Some("std");
685725
}
686-
let ret = {
687-
let mut expander = MacroExpander::new(&mut cx);
688726

689-
for (name, extension) in user_exts {
690-
expander.cx.syntax_env.insert(name, extension);
691-
}
727+
// User extensions must be added before expander.load_macros is called,
728+
// so that macros from external crates shadow user defined extensions.
729+
for (name, extension) in user_exts {
730+
expander.cx.syntax_env.insert(name, extension);
731+
}
692732

693-
let items = SmallVector::many(c.module.items);
694-
expander.load_macros(&items);
695-
c.module.items = items.into();
733+
let items = SmallVector::many(c.module.items);
734+
expander.load_macros(&items);
735+
c.module.items = items.into();
696736

697-
let err_count = cx.parse_sess.span_diagnostic.err_count();
698-
let mut ret = expander.fold_crate(c);
699-
ret.exported_macros = expander.cx.exported_macros.clone();
737+
let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
738+
let mut ret = expander.fold_crate(c);
739+
ret.exported_macros = expander.cx.exported_macros.clone();
700740

701-
if cx.parse_sess.span_diagnostic.err_count() > err_count {
702-
cx.parse_sess.span_diagnostic.abort_if_errors();
703-
}
741+
if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
742+
expander.cx.parse_sess.span_diagnostic.abort_if_errors();
743+
}
704744

705-
ret
706-
};
707-
return (ret, cx.syntax_env.names);
745+
ret
708746
}
709747

710748
// A Marker adds the given mark to the syntax context and
@@ -780,8 +818,8 @@ mod tests {
780818
Vec::new(), &sess).unwrap();
781819
// should fail:
782820
let mut loader = DummyMacroLoader;
783-
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
784-
expand_crate(ecx, vec![], crate_ast);
821+
let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
822+
expand_crate(&mut ecx, vec![], crate_ast);
785823
}
786824

787825
// make sure that macros can't escape modules
@@ -795,8 +833,8 @@ mod tests {
795833
src,
796834
Vec::new(), &sess).unwrap();
797835
let mut loader = DummyMacroLoader;
798-
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
799-
expand_crate(ecx, vec![], crate_ast);
836+
let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
837+
expand_crate(&mut ecx, vec![], crate_ast);
800838
}
801839

802840
// macro_use modules should allow macros to escape
@@ -809,17 +847,17 @@ mod tests {
809847
src,
810848
Vec::new(), &sess).unwrap();
811849
let mut loader = DummyMacroLoader;
812-
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
813-
expand_crate(ecx, vec![], crate_ast);
850+
let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
851+
expand_crate(&mut ecx, vec![], crate_ast);
814852
}
815853

816854
fn expand_crate_str(crate_str: String) -> ast::Crate {
817855
let ps = parse::ParseSess::new();
818856
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
819857
// the cfg argument actually does matter, here...
820858
let mut loader = DummyMacroLoader;
821-
let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
822-
expand_crate(ecx, vec![], crate_ast).0
859+
let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
860+
expand_crate(&mut ecx, vec![], crate_ast)
823861
}
824862

825863
#[test] fn macro_tokens_should_match(){

0 commit comments

Comments
 (0)