@@ -35,6 +35,40 @@ use std_inject;
35
35
use std:: collections:: HashSet ;
36
36
use std:: env;
37
37
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
+
38
72
// this function is called to detect use of feature-gated or invalid attributes
39
73
// on macro invoations since they will not be detected after macro expansion
40
74
fn 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> {
59
93
// Assert that we drop any macro attributes on the floor here
60
94
drop ( attrs) ;
61
95
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) {
65
97
Some ( expr) => expr,
66
98
None => {
67
99
return DummyResult :: raw_expr ( span) ;
@@ -182,19 +214,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
182
214
} ) ;
183
215
}
184
216
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 > {
198
220
// it would almost certainly be cleaner to pass the whole
199
221
// macro invocation in, rather than pulling it apart and
200
222
// marking the tts and the ctxt separately. This also goes
@@ -245,7 +267,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
245
267
let expanded = expandfun. expand ( fld. cx ,
246
268
mac_span,
247
269
& marked_before[ ..] ) ;
248
- parse_thunk ( expanded)
270
+ T :: make_with ( expanded)
249
271
} ;
250
272
let parsed = match opt_parsed {
251
273
Some ( e) => e,
@@ -258,7 +280,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
258
280
return None ;
259
281
}
260
282
} ;
261
- Some ( mark_thunk ( parsed, fm ) )
283
+ Some ( parsed. fold_with ( & mut Marker { mark : fm } ) )
262
284
}
263
285
_ => {
264
286
fld. cx . span_err (
@@ -523,11 +545,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
523
545
// Assert that we drop any macro attributes on the floor here
524
546
drop ( attrs) ;
525
547
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) ;
531
550
532
551
let mut fully_expanded = match maybe_new_items {
533
552
Some ( stmts) => {
@@ -759,6 +778,7 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
759
778
PatKind :: Mac ( mac) => ( mac. node . path , mac. node . tts ) ,
760
779
_ => unreachable ! ( )
761
780
} ;
781
+
762
782
if pth. segments . len ( ) > 1 {
763
783
fld. cx . span_err ( pth. span , "expected macro name without module separators" ) ;
764
784
return DummyResult :: raw_pat ( span) ;
@@ -1079,11 +1099,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
1079
1099
ast:: ImplItemKind :: Macro ( mac) => {
1080
1100
check_attributes ( & ii. attrs , fld) ;
1081
1101
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) ;
1087
1104
1088
1105
match maybe_new_items {
1089
1106
Some ( impl_items) => {
@@ -1139,10 +1156,7 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
1139
1156
let t = match t. node . clone ( ) {
1140
1157
ast:: TyKind :: Mac ( mac) => {
1141
1158
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) {
1146
1160
Some ( ty) => ty,
1147
1161
None => {
1148
1162
return DummyResult :: raw_ty ( t. span ) ;
@@ -1426,38 +1440,17 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
1426
1440
noop_fold_tts ( tts, & mut Marker { mark : m} )
1427
1441
}
1428
1442
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
-
1434
1443
// apply a given mark to the given pattern. Used following the expansion of a macro.
1435
1444
fn mark_pat ( pat : P < ast:: Pat > , m : Mrk ) -> P < ast:: Pat > {
1436
1445
Marker { mark : m} . fold_pat ( pat)
1437
1446
}
1438
1447
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
-
1445
1448
// apply a given mark to the given item. Used following the expansion of a macro.
1446
1449
fn mark_item ( expr : P < ast:: Item > , m : Mrk ) -> P < ast:: Item > {
1447
1450
Marker { mark : m} . fold_item ( expr)
1448
1451
. expect_one ( "marking an item didn't return exactly one item" )
1449
1452
}
1450
1453
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
-
1461
1454
/// Check that there are no macro invocations left in the AST:
1462
1455
pub fn check_for_macros ( sess : & parse:: ParseSess , krate : & ast:: Crate ) {
1463
1456
visit:: walk_crate ( & mut MacroExterminator { sess : sess} , krate) ;
0 commit comments