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 } ;
1212use ast:: { MacStmtStyle , Stmt , StmtKind , ItemKind } ;
1313use ast;
1414use ext:: hygiene:: Mark ;
@@ -29,8 +29,6 @@ use visit;
2929use visit:: Visitor ;
3030use 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.
3533trait 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}
@@ -490,11 +513,19 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
490513/// A tree-folder that performs macro expansion
491514pub struct MacroExpander < ' a , ' b : ' a > {
492515 pub cx : & ' a mut ExtCtxt < ' b > ,
516+ pub single_step : bool ,
517+ pub keep_macs : bool ,
493518}
494519
495520impl < ' 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+ }
498529 }
499530
500531 fn strip_unconfigured ( & mut self ) -> StripUnconfigured {
@@ -672,38 +703,45 @@ impl<'feat> ExpansionConfig<'feat> {
672703 }
673704}
674705
675- pub fn expand_crate ( mut cx : ExtCtxt ,
706+ pub fn expand_crate ( cx : & mut ExtCtxt ,
676707 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 {
678718 if std_inject:: no_core ( & c) {
679- cx. crate_root = None ;
719+ expander . cx . crate_root = None ;
680720 } else if std_inject:: no_std ( & c) {
681- cx. crate_root = Some ( "core" ) ;
721+ expander . cx . crate_root = Some ( "core" ) ;
682722 } else {
683- cx. crate_root = Some ( "std" ) ;
723+ expander . cx . crate_root = Some ( "std" ) ;
684724 }
685- let ret = {
686- let mut expander = MacroExpander :: new ( & mut cx) ;
687725
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+ }
691731
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 ( ) ;
695735
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 ( ) ;
699739
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+ }
703743
704- ret
705- } ;
706- return ( ret, cx. syntax_env . names ) ;
744+ ret
707745}
708746
709747// A Marker adds the given mark to the syntax context and
@@ -779,8 +817,8 @@ mod tests {
779817 Vec :: new ( ) , & sess) . unwrap ( ) ;
780818 // should fail:
781819 let mut loader = DummyMacroLoader ;
782- let ecx = ExtCtxt :: new ( & sess, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
783- expand_crate ( ecx, vec ! [ ] , crate_ast) ;
820+ let mut ecx = ExtCtxt :: new ( & sess, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
821+ expand_crate ( & mut ecx, vec ! [ ] , crate_ast) ;
784822 }
785823
786824 // make sure that macros can't escape modules
@@ -794,8 +832,8 @@ mod tests {
794832 src,
795833 Vec :: new ( ) , & sess) . unwrap ( ) ;
796834 let mut loader = DummyMacroLoader ;
797- let ecx = ExtCtxt :: new ( & sess, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
798- expand_crate ( ecx, vec ! [ ] , crate_ast) ;
835+ let mut ecx = ExtCtxt :: new ( & sess, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
836+ expand_crate ( & mut ecx, vec ! [ ] , crate_ast) ;
799837 }
800838
801839 // macro_use modules should allow macros to escape
@@ -808,17 +846,17 @@ mod tests {
808846 src,
809847 Vec :: new ( ) , & sess) . unwrap ( ) ;
810848 let mut loader = DummyMacroLoader ;
811- let ecx = ExtCtxt :: new ( & sess, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
812- expand_crate ( ecx, vec ! [ ] , crate_ast) ;
849+ let mut ecx = ExtCtxt :: new ( & sess, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
850+ expand_crate ( & mut ecx, vec ! [ ] , crate_ast) ;
813851 }
814852
815853 fn expand_crate_str ( crate_str : String ) -> ast:: Crate {
816854 let ps = parse:: ParseSess :: new ( ) ;
817855 let crate_ast = panictry ! ( string_to_parser( & ps, crate_str) . parse_crate_mod( ) ) ;
818856 // the cfg argument actually does matter, here...
819857 let mut loader = DummyMacroLoader ;
820- let ecx = ExtCtxt :: new ( & ps, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
821- expand_crate ( ecx, vec ! [ ] , crate_ast) . 0
858+ let mut ecx = ExtCtxt :: new ( & ps, vec ! [ ] , test_ecfg ( ) , & mut loader) ;
859+ expand_crate ( & mut ecx, vec ! [ ] , crate_ast)
822860 }
823861
824862 #[ test] fn macro_tokens_should_match ( ) {
0 commit comments