Skip to content

Commit d4358af

Browse files
Extended expand.rs to support alternate expansion behaviours
1 parent f2e59cc commit d4358af

File tree

1 file changed

+92
-19
lines changed

1 file changed

+92
-19
lines changed

src/libsyntax/ext/expand.rs

+92-19
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use visit::Visitor;
3030
use std_inject;
3131

3232
use std::collections::HashSet;
33+
use std::rc::Rc;
3334

3435
// A trait for AST nodes and AST node lists into which macro invocations may expand.
3536
trait MacroGenerable: Sized {
@@ -40,6 +41,10 @@ trait MacroGenerable: Sized {
4041
fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
4142
fn visit_with<V: Visitor>(&self, visitor: &mut V);
4243

44+
// Called in expand_mac_invoc after node expansion/marking/configuration.
45+
// Calls a closure in the expander to determine how (or if) to recursively expand.
46+
fn expand_with(self, expander: &mut MacroExpander) -> Self;
47+
4348
// The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics.
4449
fn kind_name() -> &'static str;
4550

@@ -52,7 +57,8 @@ trait MacroGenerable: Sized {
5257
macro_rules! impl_macro_generable {
5358
($($ty:ty: $kind_name:expr, .$make:ident,
5459
$(.$fold:ident)* $(lift .$fold_elt:ident)*,
55-
$(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { $(
60+
$(.$visit:ident)* $(lift .$visit_elt:ident)*,
61+
$(.$expand:ident)*;)*) => { $(
5662
impl MacroGenerable for $ty {
5763
fn kind_name() -> &'static str { $kind_name }
5864
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> { result.$make() }
@@ -64,20 +70,28 @@ macro_rules! impl_macro_generable {
6470
$( visitor.$visit(self) )*
6571
$( for item in self.as_slice() { visitor. $visit_elt (item) } )*
6672
}
73+
fn expand_with(self, expander: &mut MacroExpander) -> Self {
74+
$( let expand_fn = expander.$expand.clone();
75+
expand_fn(expander, self))*
76+
}
6777
}
6878
)* }
6979
}
7080

7181
impl_macro_generable! {
72-
P<ast::Expr>: "expression", .make_expr, .fold_expr, .visit_expr;
73-
P<ast::Pat>: "pattern", .make_pat, .fold_pat, .visit_pat;
74-
P<ast::Ty>: "type", .make_ty, .fold_ty, .visit_ty;
75-
SmallVector<ast::Stmt>: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
76-
SmallVector<P<ast::Item>>: "item", .make_items, lift .fold_item, lift .visit_item;
82+
P<ast::Expr>: "expression", .make_expr, .fold_expr, .visit_expr, .expand_expr;
83+
P<ast::Pat>: "pattern", .make_pat, .fold_pat, .visit_pat, .expand_pat;
84+
P<ast::Ty>: "type", .make_ty, .fold_ty, .visit_ty, .expand_ty;
85+
SmallVector<ast::Stmt>: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt,
86+
.expand_stmt;
87+
SmallVector<P<ast::Item>>: "item", .make_items, lift .fold_item, lift .visit_item,
88+
.expand_item;
7789
SmallVector<ast::TraitItem>:
78-
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
90+
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item,
91+
.expand_trait_item;
7992
SmallVector<ast::ImplItem>:
80-
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
93+
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item,
94+
.expand_impl_item;
8195
}
8296

8397
impl MacroGenerable for Option<P<ast::Expr>> {
@@ -91,6 +105,10 @@ impl MacroGenerable for Option<P<ast::Expr>> {
91105
fn visit_with<V: Visitor>(&self, visitor: &mut V) {
92106
self.as_ref().map(|expr| visitor.visit_expr(expr));
93107
}
108+
fn expand_with(self, expander: &mut MacroExpander) -> Self {
109+
let expand_fn = expander.expand_opt_expr.clone();
110+
expand_fn(expander, self)
111+
}
94112
}
95113

96114
pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
@@ -260,7 +278,7 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
260278
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
261279
let configured = marked.fold_with(&mut fld.strip_unconfigured());
262280
fld.load_macros(&configured);
263-
let fully_expanded = configured.fold_with(fld);
281+
let fully_expanded = configured.expand_with(fld);
264282
fld.cx.bt_pop();
265283
fully_expanded
266284
}
@@ -488,14 +506,41 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
488506
fold::noop_fold_ty(t, fld)
489507
}
490508

509+
pub type ExpandFn<T> = Rc<Box<Fn(&mut MacroExpander, T) -> T>>;
510+
511+
// Folds an expanded node with the folder again - this performs a full expansion.
512+
fn default_closure<T: MacroGenerable>() -> ExpandFn<T> {
513+
Rc::new(Box::new(|fld, node| node.fold_with(fld)))
514+
}
515+
491516
/// A tree-folder that performs macro expansion
492517
pub struct MacroExpander<'a, 'b:'a> {
493518
pub cx: &'a mut ExtCtxt<'b>,
519+
520+
// Closures controlling recursive expansion behaviour.
521+
pub expand_pat: ExpandFn<P<ast::Pat>>,
522+
pub expand_ty: ExpandFn<P<ast::Ty>>,
523+
pub expand_expr: ExpandFn<P<ast::Expr>>,
524+
pub expand_stmt: ExpandFn<SmallVector<ast::Stmt>>,
525+
pub expand_item: ExpandFn<SmallVector<P<ast::Item>>>,
526+
pub expand_trait_item: ExpandFn<SmallVector<ast::TraitItem>>,
527+
pub expand_impl_item: ExpandFn<SmallVector<ast::ImplItem>>,
528+
pub expand_opt_expr: ExpandFn<Option<P<ast::Expr>>>
494529
}
495530

496531
impl<'a, 'b> MacroExpander<'a, 'b> {
497532
pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
498-
MacroExpander { cx: cx }
533+
MacroExpander {
534+
cx: cx,
535+
expand_pat: default_closure(),
536+
expand_ty: default_closure(),
537+
expand_expr: default_closure(),
538+
expand_stmt: default_closure(),
539+
expand_item: default_closure(),
540+
expand_trait_item: default_closure(),
541+
expand_impl_item: default_closure(),
542+
expand_opt_expr: default_closure()
543+
}
499544
}
500545

501546
fn strip_unconfigured(&mut self) -> StripUnconfigured {
@@ -673,23 +718,29 @@ impl<'feat> ExpansionConfig<'feat> {
673718
}
674719
}
675720

676-
pub fn expand_crate(mut cx: ExtCtxt,
677-
user_exts: Vec<NamedSyntaxExtension>,
678-
mut c: Crate) -> (Crate, HashSet<Name>) {
679-
if std_inject::no_core(&c) {
721+
// Sets crate root and inserts user extensions into the context.
722+
fn init_cx(cx: &mut ExtCtxt, user_exts: Vec<NamedSyntaxExtension>, c: &Crate) {
723+
if std_inject::no_core(c) {
680724
cx.crate_root = None;
681-
} else if std_inject::no_std(&c) {
725+
} else if std_inject::no_std(c) {
682726
cx.crate_root = Some("core");
683727
} else {
684728
cx.crate_root = Some("std");
685729
}
730+
731+
for (name, extension) in user_exts {
732+
cx.syntax_env.insert(name, extension);
733+
}
734+
}
735+
736+
pub fn expand_crate(mut cx: ExtCtxt,
737+
user_exts: Vec<NamedSyntaxExtension>,
738+
mut c: Crate) -> (Crate, HashSet<Name>) {
739+
init_cx(&mut cx, user_exts, &c);
740+
686741
let ret = {
687742
let mut expander = MacroExpander::new(&mut cx);
688743

689-
for (name, extension) in user_exts {
690-
expander.cx.syntax_env.insert(name, extension);
691-
}
692-
693744
let items = SmallVector::many(c.module.items);
694745
expander.load_macros(&items);
695746
c.module.items = items.into();
@@ -707,6 +758,28 @@ pub fn expand_crate(mut cx: ExtCtxt,
707758
return (ret, cx.syntax_env.names);
708759
}
709760

761+
// Expands crate using supplied MacroExpander - allows for
762+
// non-standard expansion behaviour (e.g. step-wise).
763+
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
764+
user_exts: Vec<NamedSyntaxExtension>,
765+
mut c: Crate) -> (Crate, HashSet<Name>) {
766+
init_cx(expander.cx, user_exts, &c);
767+
768+
let items = SmallVector::many(c.module.items);
769+
expander.load_macros(&items);
770+
c.module.items = items.into();
771+
772+
let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
773+
let mut ret = expander.fold_crate(c);
774+
ret.exported_macros = expander.cx.exported_macros.clone();
775+
776+
if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
777+
expander.cx.parse_sess.span_diagnostic.abort_if_errors();
778+
}
779+
780+
return (ret, expander.cx.syntax_env.names.clone());
781+
}
782+
710783
// A Marker adds the given mark to the syntax context and
711784
// sets spans' `expn_id` to the given expn_id (unless it is `None`).
712785
struct Marker { mark: Mark, expn_id: Option<ExpnId> }

0 commit comments

Comments
 (0)