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}
@@ -491,11 +514,19 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
491514/// A tree-folder that performs macro expansion
492515pub struct MacroExpander < ' a , ' b : ' a > {
493516 pub cx : & ' a mut ExtCtxt < ' b > ,
517+ pub single_step : bool ,
518+ pub keep_macs : bool ,
494519}
495520
496521impl < ' 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+ }
499530 }
500531
501532 fn strip_unconfigured ( & mut self ) -> StripUnconfigured {
@@ -673,38 +704,45 @@ impl<'feat> ExpansionConfig<'feat> {
673704 }
674705}
675706
676- pub fn expand_crate ( mut cx : ExtCtxt ,
707+ pub fn expand_crate ( cx : & mut ExtCtxt ,
677708 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 {
679719 if std_inject:: no_core ( & c) {
680- cx. crate_root = None ;
720+ expander . cx . crate_root = None ;
681721 } else if std_inject:: no_std ( & c) {
682- cx. crate_root = Some ( "core" ) ;
722+ expander . cx . crate_root = Some ( "core" ) ;
683723 } else {
684- cx. crate_root = Some ( "std" ) ;
724+ expander . cx . crate_root = Some ( "std" ) ;
685725 }
686- let ret = {
687- let mut expander = MacroExpander :: new ( & mut cx) ;
688726
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+ }
692732
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 ( ) ;
696736
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 ( ) ;
700740
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+ }
704744
705- ret
706- } ;
707- return ( ret, cx. syntax_env . names ) ;
745+ ret
708746}
709747
710748// A Marker adds the given mark to the syntax context and
@@ -780,8 +818,8 @@ mod tests {
780818 Vec :: new ( ) , & sess) . unwrap ( ) ;
781819 // should fail:
782820 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) ;
785823 }
786824
787825 // make sure that macros can't escape modules
@@ -795,8 +833,8 @@ mod tests {
795833 src,
796834 Vec :: new ( ) , & sess) . unwrap ( ) ;
797835 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) ;
800838 }
801839
802840 // macro_use modules should allow macros to escape
@@ -809,17 +847,17 @@ mod tests {
809847 src,
810848 Vec :: new ( ) , & sess) . unwrap ( ) ;
811849 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) ;
814852 }
815853
816854 fn expand_crate_str ( crate_str : String ) -> ast:: Crate {
817855 let ps = parse:: ParseSess :: new ( ) ;
818856 let crate_ast = panictry ! ( string_to_parser( & ps, crate_str) . parse_crate_mod( ) ) ;
819857 // the cfg argument actually does matter, here...
820858 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)
823861 }
824862
825863 #[ test] fn macro_tokens_should_match ( ) {
0 commit comments