@@ -30,6 +30,7 @@ use visit::Visitor;
30
30
use std_inject;
31
31
32
32
use std:: collections:: HashSet ;
33
+ use std:: rc:: Rc ;
33
34
34
35
// A trait for AST nodes and AST node lists into which macro invocations may expand.
35
36
trait MacroGenerable : Sized {
@@ -40,6 +41,10 @@ trait MacroGenerable: Sized {
40
41
fn fold_with < F : Folder > ( self , folder : & mut F ) -> Self ;
41
42
fn visit_with < V : Visitor > ( & self , visitor : & mut V ) ;
42
43
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
+
43
48
// The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics.
44
49
fn kind_name ( ) -> & ' static str ;
45
50
@@ -52,7 +57,8 @@ trait MacroGenerable: Sized {
52
57
macro_rules! impl_macro_generable {
53
58
( $( $ty: ty: $kind_name: expr, . $make: ident,
54
59
$( . $fold: ident) * $( lift . $fold_elt: ident) * ,
55
- $( . $visit: ident) * $( lift . $visit_elt: ident) * ; ) * ) => { $(
60
+ $( . $visit: ident) * $( lift . $visit_elt: ident) * ,
61
+ $( . $expand: ident) * ; ) * ) => { $(
56
62
impl MacroGenerable for $ty {
57
63
fn kind_name( ) -> & ' static str { $kind_name }
58
64
fn make_with<' a>( result: Box <MacResult + ' a>) -> Option <Self > { result. $make( ) }
@@ -64,20 +70,28 @@ macro_rules! impl_macro_generable {
64
70
$( visitor. $visit( self ) ) *
65
71
$( for item in self . as_slice( ) { visitor. $visit_elt ( item) } ) *
66
72
}
73
+ fn expand_with( self , expander: & mut MacroExpander ) -> Self {
74
+ $( let expand_fn = expander. $expand. clone( ) ;
75
+ expand_fn( expander, self ) ) *
76
+ }
67
77
}
68
78
) * }
69
79
}
70
80
71
81
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;
77
89
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;
79
92
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;
81
95
}
82
96
83
97
impl MacroGenerable for Option < P < ast:: Expr > > {
@@ -91,6 +105,10 @@ impl MacroGenerable for Option<P<ast::Expr>> {
91
105
fn visit_with < V : Visitor > ( & self , visitor : & mut V ) {
92
106
self . as_ref ( ) . map ( |expr| visitor. visit_expr ( expr) ) ;
93
107
}
108
+ fn expand_with ( self , expander : & mut MacroExpander ) -> Self {
109
+ let expand_fn = expander. expand_opt_expr . clone ( ) ;
110
+ expand_fn ( expander, self )
111
+ }
94
112
}
95
113
96
114
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
260
278
let marked = expanded. fold_with ( & mut Marker { mark : mark, expn_id : Some ( fld. cx . backtrace ( ) ) } ) ;
261
279
let configured = marked. fold_with ( & mut fld. strip_unconfigured ( ) ) ;
262
280
fld. load_macros ( & configured) ;
263
- let fully_expanded = configured. fold_with ( fld) ;
281
+ let fully_expanded = configured. expand_with ( fld) ;
264
282
fld. cx . bt_pop ( ) ;
265
283
fully_expanded
266
284
}
@@ -488,14 +506,41 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
488
506
fold:: noop_fold_ty ( t, fld)
489
507
}
490
508
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
+
491
516
/// A tree-folder that performs macro expansion
492
517
pub struct MacroExpander < ' a , ' b : ' a > {
493
518
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 > > >
494
529
}
495
530
496
531
impl < ' a , ' b > MacroExpander < ' a , ' b > {
497
532
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
+ }
499
544
}
500
545
501
546
fn strip_unconfigured ( & mut self ) -> StripUnconfigured {
@@ -673,23 +718,29 @@ impl<'feat> ExpansionConfig<'feat> {
673
718
}
674
719
}
675
720
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) {
680
724
cx. crate_root = None ;
681
- } else if std_inject:: no_std ( & c) {
725
+ } else if std_inject:: no_std ( c) {
682
726
cx. crate_root = Some ( "core" ) ;
683
727
} else {
684
728
cx. crate_root = Some ( "std" ) ;
685
729
}
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
+
686
741
let ret = {
687
742
let mut expander = MacroExpander :: new ( & mut cx) ;
688
743
689
- for ( name, extension) in user_exts {
690
- expander. cx . syntax_env . insert ( name, extension) ;
691
- }
692
-
693
744
let items = SmallVector :: many ( c. module . items ) ;
694
745
expander. load_macros ( & items) ;
695
746
c. module . items = items. into ( ) ;
@@ -707,6 +758,28 @@ pub fn expand_crate(mut cx: ExtCtxt,
707
758
return ( ret, cx. syntax_env . names ) ;
708
759
}
709
760
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
+
710
783
// A Marker adds the given mark to the syntax context and
711
784
// sets spans' `expn_id` to the given expn_id (unless it is `None`).
712
785
struct Marker { mark : Mark , expn_id : Option < ExpnId > }
0 commit comments