@@ -35,6 +35,40 @@ use std_inject;
3535use std:: collections:: HashSet ;
3636use std:: env;
3737
38+ trait MacroGenerable : Sized {
39+ fn make_with < ' a > ( result : Box < MacResult + ' a > ) -> Option < Self > ;
40+ fn fold_with < F : Folder > ( self , folder : & mut F ) -> Self ;
41+ fn dummy ( span : Span ) -> Self ;
42+ fn kind_name ( ) -> & ' static str ;
43+ }
44+
45+ macro_rules! impl_macro_generable {
46+ ( $( $ty: ty: $kind_name: expr, . $make: ident, $( . $fold: ident) * $( lift . $fold_elt: ident) * ,
47+ |$span: ident| $dummy: expr; ) * ) => { $(
48+ impl MacroGenerable for $ty {
49+ fn kind_name( ) -> & ' static str { $kind_name }
50+ fn make_with<' a>( result: Box <MacResult + ' a>) -> Option <Self > { result. $make( ) }
51+ fn fold_with<F : Folder >( self , folder: & mut F ) -> Self {
52+ $( folder. $fold( self ) ) *
53+ $( self . into_iter( ) . flat_map( |item| folder. $fold_elt ( item) ) . collect( ) ) *
54+ }
55+ fn dummy( $span: Span ) -> Self { $dummy }
56+ }
57+ ) * }
58+ }
59+
60+ impl_macro_generable ! {
61+ P <ast:: Expr >: "expression" , . make_expr, . fold_expr, |span| DummyResult :: raw_expr( span) ;
62+ P <ast:: Pat >: "pattern" , . make_pat, . fold_pat, |span| P ( DummyResult :: raw_pat( span) ) ;
63+ P <ast:: Ty >: "type" , . make_ty, . fold_ty, |span| DummyResult :: raw_ty( span) ;
64+ SmallVector <ast:: ImplItem >:
65+ "impl item" , . make_impl_items, lift . fold_impl_item, |_span| SmallVector :: zero( ) ;
66+ SmallVector <P <ast:: Item >>:
67+ "item" , . make_items, lift . fold_item, |_span| SmallVector :: zero( ) ;
68+ SmallVector <ast:: Stmt >:
69+ "statement" , . make_stmts, lift . fold_stmt, |_span| SmallVector :: zero( ) ;
70+ }
71+
3872// this function is called to detect use of feature-gated or invalid attributes
3973// on macro invoations since they will not be detected after macro expansion
4074fn check_attributes ( attrs : & [ ast:: Attribute ] , fld : & MacroExpander ) {
@@ -59,9 +93,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
5993 // Assert that we drop any macro attributes on the floor here
6094 drop ( attrs) ;
6195
62- let expanded_expr = match expand_mac_invoc ( mac, span,
63- |r| r. make_expr ( ) ,
64- mark_expr, fld) {
96+ let expanded_expr = match expand_mac_invoc ( mac, span, fld) {
6597 Some ( expr) => expr,
6698 None => {
6799 return DummyResult :: raw_expr ( span) ;
@@ -182,19 +214,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
182214 } ) ;
183215}
184216
185- /// Expand a (not-ident-style) macro invocation. Returns the result
186- /// of expansion and the mark which must be applied to the result.
187- /// Our current interface doesn't allow us to apply the mark to the
188- /// result until after calling make_expr, make_items, etc.
189- fn expand_mac_invoc < T , F , G > ( mac : ast:: Mac ,
190- span : codemap:: Span ,
191- parse_thunk : F ,
192- mark_thunk : G ,
193- fld : & mut MacroExpander )
194- -> Option < T > where
195- F : for < ' a > FnOnce ( Box < MacResult +' a > ) -> Option < T > ,
196- G : FnOnce ( T , Mrk ) -> T ,
197- {
217+ /// Expand a (not-ident-style) macro invocation. Returns the result of expansion.
218+ fn expand_mac_invoc < T : MacroGenerable > ( mac : ast:: Mac , span : Span , fld : & mut MacroExpander )
219+ -> Option < T > {
198220 // it would almost certainly be cleaner to pass the whole
199221 // macro invocation in, rather than pulling it apart and
200222 // marking the tts and the ctxt separately. This also goes
@@ -245,7 +267,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
245267 let expanded = expandfun. expand ( fld. cx ,
246268 mac_span,
247269 & marked_before[ ..] ) ;
248- parse_thunk ( expanded)
270+ T :: make_with ( expanded)
249271 } ;
250272 let parsed = match opt_parsed {
251273 Some ( e) => e,
@@ -258,7 +280,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
258280 return None ;
259281 }
260282 } ;
261- Some ( mark_thunk ( parsed, fm ) )
283+ Some ( parsed. fold_with ( & mut Marker { mark : fm } ) )
262284 }
263285 _ => {
264286 fld. cx . span_err (
@@ -523,11 +545,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
523545 // Assert that we drop any macro attributes on the floor here
524546 drop ( attrs) ;
525547
526- let maybe_new_items =
527- expand_mac_invoc ( mac. unwrap ( ) , stmt. span ,
528- |r| r. make_stmts ( ) ,
529- |stmts, mark| stmts. move_map ( |m| mark_stmt ( m, mark) ) ,
530- fld) ;
548+ let maybe_new_items: Option < SmallVector < ast:: Stmt > > =
549+ expand_mac_invoc ( mac. unwrap ( ) , stmt. span , fld) ;
531550
532551 let mut fully_expanded = match maybe_new_items {
533552 Some ( stmts) => {
@@ -759,6 +778,7 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
759778 PatKind :: Mac ( mac) => ( mac. node . path , mac. node . tts ) ,
760779 _ => unreachable ! ( )
761780 } ;
781+
762782 if pth. segments . len ( ) > 1 {
763783 fld. cx . span_err ( pth. span , "expected macro name without module separators" ) ;
764784 return DummyResult :: raw_pat ( span) ;
@@ -1079,11 +1099,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
10791099 ast:: ImplItemKind :: Macro ( mac) => {
10801100 check_attributes ( & ii. attrs , fld) ;
10811101
1082- let maybe_new_items =
1083- expand_mac_invoc ( mac, ii. span ,
1084- |r| r. make_impl_items ( ) ,
1085- |meths, mark| meths. move_map ( |m| mark_impl_item ( m, mark) ) ,
1086- fld) ;
1102+ let maybe_new_items: Option < SmallVector < ast:: ImplItem > > =
1103+ expand_mac_invoc ( mac, ii. span , fld) ;
10871104
10881105 match maybe_new_items {
10891106 Some ( impl_items) => {
@@ -1139,10 +1156,7 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
11391156 let t = match t. node . clone ( ) {
11401157 ast:: TyKind :: Mac ( mac) => {
11411158 if fld. cx . ecfg . features . unwrap ( ) . type_macros {
1142- let expanded_ty = match expand_mac_invoc ( mac, t. span ,
1143- |r| r. make_ty ( ) ,
1144- mark_ty,
1145- fld) {
1159+ let expanded_ty = match expand_mac_invoc ( mac, t. span , fld) {
11461160 Some ( ty) => ty,
11471161 None => {
11481162 return DummyResult :: raw_ty ( t. span ) ;
@@ -1426,38 +1440,17 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
14261440 noop_fold_tts ( tts, & mut Marker { mark : m} )
14271441}
14281442
1429- // apply a given mark to the given expr. Used following the expansion of a macro.
1430- fn mark_expr ( expr : P < ast:: Expr > , m : Mrk ) -> P < ast:: Expr > {
1431- Marker { mark : m} . fold_expr ( expr)
1432- }
1433-
14341443// apply a given mark to the given pattern. Used following the expansion of a macro.
14351444fn mark_pat ( pat : P < ast:: Pat > , m : Mrk ) -> P < ast:: Pat > {
14361445 Marker { mark : m} . fold_pat ( pat)
14371446}
14381447
1439- // apply a given mark to the given stmt. Used following the expansion of a macro.
1440- fn mark_stmt ( stmt : ast:: Stmt , m : Mrk ) -> ast:: Stmt {
1441- Marker { mark : m} . fold_stmt ( stmt)
1442- . expect_one ( "marking a stmt didn't return exactly one stmt" )
1443- }
1444-
14451448// apply a given mark to the given item. Used following the expansion of a macro.
14461449fn mark_item ( expr : P < ast:: Item > , m : Mrk ) -> P < ast:: Item > {
14471450 Marker { mark : m} . fold_item ( expr)
14481451 . expect_one ( "marking an item didn't return exactly one item" )
14491452}
14501453
1451- // apply a given mark to the given item. Used following the expansion of a macro.
1452- fn mark_impl_item ( ii : ast:: ImplItem , m : Mrk ) -> ast:: ImplItem {
1453- Marker { mark : m} . fold_impl_item ( ii)
1454- . expect_one ( "marking an impl item didn't return exactly one impl item" )
1455- }
1456-
1457- fn mark_ty ( ty : P < ast:: Ty > , m : Mrk ) -> P < ast:: Ty > {
1458- Marker { mark : m } . fold_ty ( ty)
1459- }
1460-
14611454/// Check that there are no macro invocations left in the AST:
14621455pub fn check_for_macros ( sess : & parse:: ParseSess , krate : & ast:: Crate ) {
14631456 visit:: walk_crate ( & mut MacroExterminator { sess : sess} , krate) ;
0 commit comments