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
}
@@ -490,11 +513,19 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
490
513
/// A tree-folder that performs macro expansion
491
514
pub struct MacroExpander < ' a , ' b : ' a > {
492
515
pub cx : & ' a mut ExtCtxt < ' b > ,
516
+ pub single_step : bool ,
517
+ pub keep_macs : bool ,
493
518
}
494
519
495
520
impl < ' a , ' b > MacroExpander < ' a , ' b > {
496
- pub fn new ( cx : & ' a mut ExtCtxt < ' b > ) -> MacroExpander < ' a , ' b > {
497
- MacroExpander { cx : cx }
521
+ pub fn new ( cx : & ' a mut ExtCtxt < ' b > ,
522
+ single_step : bool ,
523
+ keep_macs : bool ) -> MacroExpander < ' a , ' b > {
524
+ MacroExpander {
525
+ cx : cx,
526
+ single_step : single_step,
527
+ keep_macs : keep_macs
528
+ }
498
529
}
499
530
500
531
fn strip_unconfigured ( & mut self ) -> StripUnconfigured {
@@ -672,38 +703,45 @@ impl<'feat> ExpansionConfig<'feat> {
672
703
}
673
704
}
674
705
675
- pub fn expand_crate ( mut cx : ExtCtxt ,
706
+ pub fn expand_crate ( cx : & mut ExtCtxt ,
676
707
user_exts : Vec < NamedSyntaxExtension > ,
677
- mut c : Crate ) -> ( Crate , HashSet < Name > ) {
708
+ c : Crate ) -> Crate {
709
+ let mut expander = MacroExpander :: new ( cx, false , false ) ;
710
+ expand_crate_with_expander ( & mut expander, user_exts, c)
711
+ }
712
+
713
+ // Expands crate using supplied MacroExpander - allows for
714
+ // non-standard expansion behaviour (e.g. step-wise).
715
+ pub fn expand_crate_with_expander ( expander : & mut MacroExpander ,
716
+ user_exts : Vec < NamedSyntaxExtension > ,
717
+ mut c : Crate ) -> Crate {
678
718
if std_inject:: no_core ( & c) {
679
- cx. crate_root = None ;
719
+ expander . cx . crate_root = None ;
680
720
} else if std_inject:: no_std ( & c) {
681
- cx. crate_root = Some ( "core" ) ;
721
+ expander . cx . crate_root = Some ( "core" ) ;
682
722
} else {
683
- cx. crate_root = Some ( "std" ) ;
723
+ expander . cx . crate_root = Some ( "std" ) ;
684
724
}
685
- let ret = {
686
- let mut expander = MacroExpander :: new ( & mut cx) ;
687
725
688
- for ( name, extension) in user_exts {
689
- expander. cx . syntax_env . insert ( name, extension) ;
690
- }
726
+ // User extensions must be added before expander.load_macros is called,
727
+ // so that macros from external crates shadow user defined extensions.
728
+ for ( name, extension) in user_exts {
729
+ expander. cx . syntax_env . insert ( name, extension) ;
730
+ }
691
731
692
- let items = SmallVector :: many ( c. module . items ) ;
693
- expander. load_macros ( & items) ;
694
- c. module . items = items. into ( ) ;
732
+ let items = SmallVector :: many ( c. module . items ) ;
733
+ expander. load_macros ( & items) ;
734
+ c. module . items = items. into ( ) ;
695
735
696
- let err_count = cx. parse_sess . span_diagnostic . err_count ( ) ;
697
- let mut ret = expander. fold_crate ( c) ;
698
- ret. exported_macros = expander. cx . exported_macros . clone ( ) ;
736
+ let err_count = expander . cx . parse_sess . span_diagnostic . err_count ( ) ;
737
+ let mut ret = expander. fold_crate ( c) ;
738
+ ret. exported_macros = expander. cx . exported_macros . clone ( ) ;
699
739
700
- if cx. parse_sess . span_diagnostic . err_count ( ) > err_count {
701
- cx. parse_sess . span_diagnostic . abort_if_errors ( ) ;
702
- }
740
+ if expander . cx . parse_sess . span_diagnostic . err_count ( ) > err_count {
741
+ expander . cx . parse_sess . span_diagnostic . abort_if_errors ( ) ;
742
+ }
703
743
704
- ret
705
- } ;
706
- return ( ret, cx. syntax_env . names ) ;
744
+ ret
707
745
}
708
746
709
747
// A Marker adds the given mark to the syntax context and
0 commit comments