8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use ast:: { Block , Crate , Ident , Mac_ , Name , PatKind } ;
11
+ use ast:: { Block , Crate , Ident , Mac_ , PatKind } ;
12
12
use ast:: { MacStmtStyle , Stmt , StmtKind , ItemKind } ;
13
13
use ast;
14
14
use ext:: hygiene:: Mark ;
@@ -29,8 +29,6 @@ use visit;
29
29
use visit:: Visitor ;
30
30
use std_inject;
31
31
32
- use std:: collections:: HashSet ;
33
-
34
32
// A trait for AST nodes and AST node lists into which macro invocations may expand.
35
33
trait MacroGenerable : Sized {
36
34
// 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
218
216
}
219
217
} ) ;
220
218
221
- // DON'T mark before expansion.
222
- fld. cx . insert_macro ( ast:: MacroDef {
219
+ let def = ast:: MacroDef {
223
220
ident : ident,
224
221
id : ast:: DUMMY_NODE_ID ,
225
222
span : call_site,
@@ -229,10 +226,30 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
229
226
export : attr:: contains_name ( & attrs, "macro_export" ) ,
230
227
allow_internal_unstable : attr:: contains_name ( & attrs, "allow_internal_unstable" ) ,
231
228
attrs : attrs,
232
- } ) ;
229
+ } ;
233
230
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
+ }
236
253
}
237
254
238
255
MultiDecorator ( ..) | MultiModifier ( ..) => {
@@ -260,7 +277,13 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
260
277
let marked = expanded. fold_with ( & mut Marker { mark : mark, expn_id : Some ( fld. cx . backtrace ( ) ) } ) ;
261
278
let configured = marked. fold_with ( & mut fld. strip_unconfigured ( ) ) ;
262
279
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
+
264
287
fld. cx . bt_pop ( ) ;
265
288
fully_expanded
266
289
}
@@ -491,11 +514,19 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
491
514
/// A tree-folder that performs macro expansion
492
515
pub struct MacroExpander < ' a , ' b : ' a > {
493
516
pub cx : & ' a mut ExtCtxt < ' b > ,
517
+ pub single_step : bool ,
518
+ pub keep_macs : bool ,
494
519
}
495
520
496
521
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
+ }
499
530
}
500
531
501
532
fn strip_unconfigured ( & mut self ) -> StripUnconfigured {
@@ -673,38 +704,45 @@ impl<'feat> ExpansionConfig<'feat> {
673
704
}
674
705
}
675
706
676
- pub fn expand_crate ( mut cx : ExtCtxt ,
707
+ pub fn expand_crate ( cx : & mut ExtCtxt ,
677
708
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 {
679
719
if std_inject:: no_core ( & c) {
680
- cx. crate_root = None ;
720
+ expander . cx . crate_root = None ;
681
721
} else if std_inject:: no_std ( & c) {
682
- cx. crate_root = Some ( "core" ) ;
722
+ expander . cx . crate_root = Some ( "core" ) ;
683
723
} else {
684
- cx. crate_root = Some ( "std" ) ;
724
+ expander . cx . crate_root = Some ( "std" ) ;
685
725
}
686
- let ret = {
687
- let mut expander = MacroExpander :: new ( & mut cx) ;
688
726
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
+ }
692
732
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 ( ) ;
696
736
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 ( ) ;
700
740
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
+ }
704
744
705
- ret
706
- } ;
707
- return ( ret, cx. syntax_env . names ) ;
745
+ ret
708
746
}
709
747
710
748
// A Marker adds the given mark to the syntax context and
@@ -780,8 +818,8 @@ mod tests {
780
818
Vec :: new ( ) , & sess) . unwrap ( ) ;
781
819
// should fail:
782
820
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) ;
785
823
}
786
824
787
825
// make sure that macros can't escape modules
@@ -795,8 +833,8 @@ mod tests {
795
833
src,
796
834
Vec :: new ( ) , & sess) . unwrap ( ) ;
797
835
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) ;
800
838
}
801
839
802
840
// macro_use modules should allow macros to escape
@@ -809,17 +847,17 @@ mod tests {
809
847
src,
810
848
Vec :: new ( ) , & sess) . unwrap ( ) ;
811
849
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) ;
814
852
}
815
853
816
854
fn expand_crate_str ( crate_str : String ) -> ast:: Crate {
817
855
let ps = parse:: ParseSess :: new ( ) ;
818
856
let crate_ast = panictry ! ( string_to_parser( & ps, crate_str) . parse_crate_mod( ) ) ;
819
857
// the cfg argument actually does matter, here...
820
858
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)
823
861
}
824
862
825
863
#[ test] fn macro_tokens_should_match ( ) {
0 commit comments