@@ -24,6 +24,7 @@ mod subtree_source;
24
24
mod subtree_parser;
25
25
26
26
use ra_syntax:: SmolStr ;
27
+ use smallvec:: SmallVec ;
27
28
28
29
pub use tt:: { Delimiter , Punct } ;
29
30
@@ -98,11 +99,18 @@ pub(crate) struct Subtree {
98
99
pub ( crate ) token_trees : Vec < TokenTree > ,
99
100
}
100
101
102
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
103
+ pub ( crate ) enum Separator {
104
+ Literal ( tt:: Literal ) ,
105
+ Ident ( tt:: Ident ) ,
106
+ Puncts ( SmallVec < [ tt:: Punct ; 3 ] > ) ,
107
+ }
108
+
101
109
#[ derive( Clone , Debug , PartialEq , Eq ) ]
102
110
pub ( crate ) struct Repeat {
103
111
pub ( crate ) subtree : Subtree ,
104
112
pub ( crate ) kind : RepeatKind ,
105
- pub ( crate ) separator : Option < char > ,
113
+ pub ( crate ) separator : Option < Separator > ,
106
114
}
107
115
108
116
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -175,8 +183,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
175
183
let expansion = rules. expand ( & invocation_tt) . unwrap ( ) ;
176
184
assert_eq ! (
177
185
expansion. to_string( ) ,
178
- "impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}} \
179
- impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}}"
186
+ "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
187
+ impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
180
188
)
181
189
}
182
190
@@ -384,7 +392,7 @@ impl_froms!(TokenTree: Leaf, Subtree);
384
392
"# ,
385
393
) ;
386
394
387
- assert_expansion ( & rules, "foo! { foo, bar }" , "fn baz {foo () ; bar () ; }" ) ;
395
+ assert_expansion ( & rules, "foo! { foo, bar }" , "fn baz {foo () ;bar ()}" ) ;
388
396
}
389
397
390
398
#[ test]
@@ -416,6 +424,42 @@ impl_froms!(TokenTree: Leaf, Subtree);
416
424
assert_expansion ( & rules, "foo! {fn baz {a b} }" , "fn baz () {a () ; b () ;}" ) ;
417
425
}
418
426
427
+ #[ test]
428
+ fn test_match_group_with_multichar_sep ( ) {
429
+ let rules = create_rules (
430
+ r#"
431
+ macro_rules! foo {
432
+ (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
433
+ }"# ,
434
+ ) ;
435
+
436
+ assert_expansion ( & rules, "foo! (fn baz {true true} )" , "fn baz () -> bool {true &&true}" ) ;
437
+ }
438
+
439
+ #[ test]
440
+ fn test_match_group_zero_match ( ) {
441
+ let rules = create_rules (
442
+ r#"
443
+ macro_rules! foo {
444
+ ( $($i:ident)* ) => ();
445
+ }"# ,
446
+ ) ;
447
+
448
+ assert_expansion ( & rules, "foo! ()" , "" ) ;
449
+ }
450
+
451
+ #[ test]
452
+ fn test_match_group_in_group ( ) {
453
+ let rules = create_rules (
454
+ r#"
455
+ macro_rules! foo {
456
+ { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* );
457
+ }"# ,
458
+ ) ;
459
+
460
+ assert_expansion ( & rules, "foo! ( (a b) )" , "(a b)" ) ;
461
+ }
462
+
419
463
#[ test]
420
464
fn test_expand_to_item_list ( ) {
421
465
let rules = create_rules (
@@ -597,7 +641,7 @@ MACRO_ITEMS@[0; 40)
597
641
assert_expansion (
598
642
& rules,
599
643
"foo! { bar::<u8>::baz::<u8> }" ,
600
- "fn foo () {let a = bar :: < u8 > :: baz :: < u8 > ;}" ,
644
+ "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}" ,
601
645
) ;
602
646
}
603
647
@@ -891,7 +935,7 @@ MACRO_ITEMS@[0; 40)
891
935
}
892
936
"# ,
893
937
) ;
894
- assert_expansion ( & rules, r#"foo!{'a}"# , r#"struct Ref < 'a > {s : & 'a str}"# ) ;
938
+ assert_expansion ( & rules, r#"foo!{'a}"# , r#"struct Ref <'a > {s : &'a str}"# ) ;
895
939
}
896
940
897
941
#[ test]
@@ -1063,7 +1107,165 @@ macro_rules! int_base {
1063
1107
) ;
1064
1108
1065
1109
assert_expansion ( & rules, r#" int_base!{Binary for isize as usize -> Binary}"# ,
1066
- "# [stable (feature = \" rust1\" , since = \" 1.0.0\" )] impl fmt :: Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \' _ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
1110
+ "# [stable (feature = \" rust1\" , since = \" 1.0.0\" )] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \' _ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
1111
+ ) ;
1112
+ }
1113
+
1114
+ #[ test]
1115
+ fn test_generate_pattern_iterators ( ) {
1116
+ // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
1117
+ let rules = create_rules (
1118
+ r#"
1119
+ macro_rules! generate_pattern_iterators {
1120
+ { double ended; with $(#[$common_stability_attribute:meta])*,
1121
+ $forward_iterator:ident,
1122
+ $reverse_iterator:ident, $iterty:ty
1123
+ } => {
1124
+ fn foo(){}
1125
+ }
1126
+ }
1127
+ "# ,
1128
+ ) ;
1129
+
1130
+ assert_expansion ( & rules, r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str )"# ,
1131
+ "fn foo () {}" ) ;
1132
+ }
1133
+
1134
+ #[ test]
1135
+ fn test_impl_fn_for_zst ( ) {
1136
+ // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
1137
+ let rules = create_rules (
1138
+ r#"
1139
+ macro_rules! impl_fn_for_zst {
1140
+ { $( $( #[$attr: meta] )*
1141
+ struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
1142
+ |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
1143
+ $body: block; )+
1144
+ } => {
1145
+ $(
1146
+ $( #[$attr] )*
1147
+ struct $Name;
1148
+
1149
+ impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
1150
+ #[inline]
1151
+ extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
1152
+ $body
1153
+ }
1154
+ }
1155
+
1156
+ impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
1157
+ #[inline]
1158
+ extern "rust-call" fn call_mut(
1159
+ &mut self,
1160
+ ($( $arg, )*): ($( $ArgTy, )*)
1161
+ ) -> $ReturnTy {
1162
+ Fn::call(&*self, ($( $arg, )*))
1163
+ }
1164
+ }
1165
+
1166
+ impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
1167
+ type Output = $ReturnTy;
1168
+
1169
+ #[inline]
1170
+ extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
1171
+ Fn::call(&self, ($( $arg, )*))
1172
+ }
1173
+ }
1174
+ )+
1175
+ }
1176
+ }
1177
+ }
1178
+ "# ,
1179
+ ) ;
1180
+
1181
+ assert_expansion ( & rules, r#"
1182
+ impl_fn_for_zst ! {
1183
+ # [ derive ( Clone ) ]
1184
+ struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug {
1185
+ c . escape_debug_ext ( false )
1186
+ } ;
1187
+
1188
+ # [ derive ( Clone ) ]
1189
+ struct CharEscapeUnicode impl Fn = | c : char | -> char :: EscapeUnicode {
1190
+ c . escape_unicode ( )
1191
+ } ;
1192
+ # [ derive ( Clone ) ]
1193
+ struct CharEscapeDefault impl Fn = | c : char | -> char :: EscapeDefault {
1194
+ c . escape_default ( )
1195
+ } ;
1196
+ }
1197
+ "# ,
1198
+ "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \" rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \" rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \" rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \" rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \" rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \" rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \" rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \" rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \" rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}" ) ;
1199
+ }
1200
+
1201
+ #[ test]
1202
+ fn test_impl_nonzero_fmt ( ) {
1203
+ // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
1204
+ let rules = create_rules (
1205
+ r#"
1206
+ macro_rules! impl_nonzero_fmt {
1207
+ ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
1208
+ fn foo() {}
1209
+ }
1210
+ }
1211
+ "# ,
1067
1212
) ;
1213
+
1214
+ assert_expansion ( & rules, r#"impl_nonzero_fmt ! { # [ stable ( feature = "nonzero" , since = "1.28.0" ) ] ( Debug , Display , Binary , Octal , LowerHex , UpperHex ) for NonZeroU8 }"# ,
1215
+ "fn foo () {}" ) ;
1216
+ }
1217
+
1218
+ #[ test]
1219
+ fn test_cfg_if_items ( ) {
1220
+ // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
1221
+ let rules = create_rules (
1222
+ r#"
1223
+ macro_rules! __cfg_if_items {
1224
+ (($($not:meta,)*) ; ) => {};
1225
+ (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
1226
+ __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
1227
+ }
1228
+ }
1229
+ "# ,
1230
+ ) ;
1231
+
1232
+ assert_expansion ( & rules, r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"# ,
1233
+ "__cfg_if_items ! {(rustdoc , ) ; }" ) ;
1234
+ }
1235
+
1236
+ #[ test]
1237
+ fn test_cfg_if_main ( ) {
1238
+ // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
1239
+ let rules = create_rules (
1240
+ r#"
1241
+ macro_rules! cfg_if {
1242
+ ($(
1243
+ if #[cfg($($meta:meta),*)] { $($it:item)* }
1244
+ ) else * else {
1245
+ $($it2:item)*
1246
+ }) => {
1247
+ __cfg_if_items! {
1248
+ () ;
1249
+ $( ( ($($meta),*) ($($it)*) ), )*
1250
+ ( () ($($it2)*) ),
1251
+ }
1252
+ }
1253
+ }
1254
+ "# ,
1255
+ ) ;
1256
+
1257
+ assert_expansion ( & rules, r#"
1258
+ cfg_if ! {
1259
+ if # [ cfg ( target_env = "msvc" ) ] {
1260
+ // no extra unwinder support needed
1261
+ } else if # [ cfg ( all ( target_arch = "wasm32" , not ( target_os = "emscripten" ) ) ) ] {
1262
+ // no unwinder on the system!
1263
+ } else {
1264
+ mod libunwind ;
1265
+ pub use libunwind :: * ;
1266
+ }
1267
+ }
1268
+ "# ,
1269
+ "__cfg_if_items ! {() ; (() (mod libunwind ; pub use libunwind :: * ;)) ,}" ) ;
1068
1270
}
1069
1271
}
0 commit comments