aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/lib.rs')
-rw-r--r--crates/ra_mbe/src/lib.rs216
1 files changed, 209 insertions, 7 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index eedc0c5dd..7817232d6 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -24,6 +24,7 @@ mod subtree_source;
24mod subtree_parser; 24mod subtree_parser;
25 25
26use ra_syntax::SmolStr; 26use ra_syntax::SmolStr;
27use smallvec::SmallVec;
27 28
28pub use tt::{Delimiter, Punct}; 29pub use tt::{Delimiter, Punct};
29 30
@@ -99,10 +100,17 @@ pub(crate) struct Subtree {
99} 100}
100 101
101#[derive(Clone, Debug, PartialEq, Eq)] 102#[derive(Clone, Debug, PartialEq, Eq)]
103pub(crate) enum Separator {
104 Literal(tt::Literal),
105 Ident(tt::Ident),
106 Puncts(SmallVec<[tt::Punct; 3]>),
107}
108
109#[derive(Clone, Debug, PartialEq, Eq)]
102pub(crate) struct Repeat { 110pub(crate) struct Repeat {
103 pub(crate) subtree: Subtree, 111 pub(crate) subtree: Subtree,
104 pub(crate) kind: RepeatKind, 112 pub(crate) kind: RepeatKind,
105 pub(crate) separator: Option<char>, 113 pub(crate) separator: Option<Separator>,
106} 114}
107 115
108#[derive(Clone, Debug, PartialEq, Eq)] 116#[derive(Clone, Debug, PartialEq, Eq)]
@@ -175,8 +183,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
175 let expansion = rules.expand(&invocation_tt).unwrap(); 183 let expansion = rules.expand(&invocation_tt).unwrap();
176 assert_eq!( 184 assert_eq!(
177 expansion.to_string(), 185 expansion.to_string(),
178 "impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}} \ 186 "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)}}" 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 #[test] 398 #[test]
@@ -417,6 +425,42 @@ impl_froms!(TokenTree: Leaf, Subtree);
417 } 425 }
418 426
419 #[test] 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
463 #[test]
420 fn test_expand_to_item_list() { 464 fn test_expand_to_item_list() {
421 let rules = create_rules( 465 let rules = create_rules(
422 " 466 "
@@ -597,7 +641,7 @@ MACRO_ITEMS@[0; 40)
597 assert_expansion( 641 assert_expansion(
598 &rules, 642 &rules,
599 "foo! { bar::<u8>::baz::<u8> }", 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 #[test] 941 #[test]
@@ -1063,7 +1107,165 @@ macro_rules! int_base {
1063 ); 1107 );
1064 1108
1065 assert_expansion(&rules, r#" int_base!{Binary for isize as usize -> Binary}"#, 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#"
1119macro_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#"
1139macro_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#"
1182impl_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#"
1258cfg_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}