diff options
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 258 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 57 | ||||
-rw-r--r-- | crates/ra_mbe/src/tt_cursor.rs | 13 |
3 files changed, 304 insertions, 24 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index eedc0c5dd..d7b18dd0f 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -384,7 +384,7 @@ impl_froms!(TokenTree: Leaf, Subtree); | |||
384 | "#, | 384 | "#, |
385 | ); | 385 | ); |
386 | 386 | ||
387 | assert_expansion(&rules, "foo! { foo, bar }", "fn baz {foo () ; bar () ;}"); | 387 | assert_expansion(&rules, "foo! { foo, bar }", "fn baz {foo () ; bar ()}"); |
388 | } | 388 | } |
389 | 389 | ||
390 | #[test] | 390 | #[test] |
@@ -1066,4 +1066,260 @@ macro_rules! int_base { | |||
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)}}" | 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)}}" |
1067 | ); | 1067 | ); |
1068 | } | 1068 | } |
1069 | |||
1070 | #[test] | ||
1071 | fn test_generate_pattern_iterators() { | ||
1072 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs | ||
1073 | let rules = create_rules( | ||
1074 | r#" | ||
1075 | macro_rules! generate_pattern_iterators { | ||
1076 | { double ended; with $(#[$common_stability_attribute:meta])*, | ||
1077 | $forward_iterator:ident, | ||
1078 | $reverse_iterator:ident, $iterty:ty | ||
1079 | } => { | ||
1080 | fn foo(){} | ||
1081 | } | ||
1082 | } | ||
1083 | "#, | ||
1084 | ); | ||
1085 | |||
1086 | assert_expansion(&rules, r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str )"#, | ||
1087 | "fn foo () {}"); | ||
1088 | } | ||
1089 | |||
1090 | #[test] | ||
1091 | fn test_impl_fn_for_zst() { | ||
1092 | // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs | ||
1093 | let rules = create_rules( | ||
1094 | r#" | ||
1095 | macro_rules! impl_fn_for_zst { | ||
1096 | { $( $( #[$attr: meta] )* | ||
1097 | struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = | ||
1098 | |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty | ||
1099 | $body: block; )+ | ||
1100 | } => { | ||
1101 | fn foo(){} | ||
1102 | } | ||
1103 | } | ||
1104 | "#, | ||
1105 | ); | ||
1106 | |||
1107 | assert_expansion(&rules, r#" | ||
1108 | impl_fn_for_zst ! { | ||
1109 | # [ derive ( Clone ) ] | ||
1110 | struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug { | ||
1111 | c . escape_debug_ext ( false ) | ||
1112 | } ; | ||
1113 | |||
1114 | # [ derive ( Clone ) ] | ||
1115 | struct CharEscapeUnicode impl Fn = | c : char | -> char :: EscapeUnicode { | ||
1116 | c . escape_unicode ( ) | ||
1117 | } ; | ||
1118 | # [ derive ( Clone ) ] | ||
1119 | struct CharEscapeDefault impl Fn = | c : char | -> char :: EscapeDefault { | ||
1120 | c . escape_default ( ) | ||
1121 | } ; | ||
1122 | } | ||
1123 | "#, | ||
1124 | "fn foo () {}"); | ||
1125 | } | ||
1126 | |||
1127 | #[test] | ||
1128 | fn test_impl_nonzero_fmt() { | ||
1129 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 | ||
1130 | let rules = create_rules( | ||
1131 | r#" | ||
1132 | macro_rules! impl_nonzero_fmt { | ||
1133 | ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { | ||
1134 | fn foo() {} | ||
1135 | } | ||
1136 | } | ||
1137 | "#, | ||
1138 | ); | ||
1139 | |||
1140 | assert_expansion(&rules, r#"impl_nonzero_fmt ! { # [ stable ( feature = "nonzero" , since = "1.28.0" ) ] ( Debug , Display , Binary , Octal , LowerHex , UpperHex ) for NonZeroU8 }"#, | ||
1141 | "fn foo () {}"); | ||
1142 | } | ||
1143 | |||
1144 | #[test] | ||
1145 | fn test_tuple_impls() { | ||
1146 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 | ||
1147 | let rules = create_rules( | ||
1148 | r#" | ||
1149 | macro_rules! tuple_impls { | ||
1150 | ($( | ||
1151 | $Tuple:ident { | ||
1152 | $(($idx:tt) -> $T:ident)+ | ||
1153 | } | ||
1154 | )+) => { | ||
1155 | $( | ||
1156 | #[stable(feature = "rust1", since = "1.0.0")] | ||
1157 | impl<$($T:PartialEq),+> PartialEq for ($($T,)+) where last_type!($($T,)+): ?Sized { | ||
1158 | #[inline] | ||
1159 | fn eq(&self, other: &($($T,)+)) -> bool { | ||
1160 | $(self.$idx == other.$idx)&&+ | ||
1161 | } | ||
1162 | #[inline] | ||
1163 | fn ne(&self, other: &($($T,)+)) -> bool { | ||
1164 | $(self.$idx != other.$idx)||+ | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | #[stable(feature = "rust1", since = "1.0.0")] | ||
1169 | impl<$($T:Eq),+> Eq for ($($T,)+) where last_type!($($T,)+): ?Sized {} | ||
1170 | |||
1171 | #[stable(feature = "rust1", since = "1.0.0")] | ||
1172 | impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) | ||
1173 | where last_type!($($T,)+): ?Sized { | ||
1174 | #[inline] | ||
1175 | fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> { | ||
1176 | lexical_partial_cmp!($(self.$idx, other.$idx),+) | ||
1177 | } | ||
1178 | #[inline] | ||
1179 | fn lt(&self, other: &($($T,)+)) -> bool { | ||
1180 | lexical_ord!(lt, $(self.$idx, other.$idx),+) | ||
1181 | } | ||
1182 | #[inline] | ||
1183 | fn le(&self, other: &($($T,)+)) -> bool { | ||
1184 | lexical_ord!(le, $(self.$idx, other.$idx),+) | ||
1185 | } | ||
1186 | #[inline] | ||
1187 | fn ge(&self, other: &($($T,)+)) -> bool { | ||
1188 | lexical_ord!(ge, $(self.$idx, other.$idx),+) | ||
1189 | } | ||
1190 | #[inline] | ||
1191 | fn gt(&self, other: &($($T,)+)) -> bool { | ||
1192 | lexical_ord!(gt, $(self.$idx, other.$idx),+) | ||
1193 | } | ||
1194 | } | ||
1195 | |||
1196 | #[stable(feature = "rust1", since = "1.0.0")] | ||
1197 | impl<$($T:Ord),+> Ord for ($($T,)+) where last_type!($($T,)+): ?Sized { | ||
1198 | #[inline] | ||
1199 | fn cmp(&self, other: &($($T,)+)) -> Ordering { | ||
1200 | lexical_cmp!($(self.$idx, other.$idx),+) | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | #[stable(feature = "rust1", since = "1.0.0")] | ||
1205 | impl<$($T:Default),+> Default for ($($T,)+) { | ||
1206 | #[inline] | ||
1207 | fn default() -> ($($T,)+) { | ||
1208 | ($({ let x: $T = Default::default(); x},)+) | ||
1209 | } | ||
1210 | } | ||
1211 | )+ | ||
1212 | } | ||
1213 | }"#, | ||
1214 | ); | ||
1215 | |||
1216 | assert_expansion( | ||
1217 | &rules, | ||
1218 | r#"tuple_impls ! { | ||
1219 | Tuple1 { | ||
1220 | ( 0 ) -> A | ||
1221 | } | ||
1222 | Tuple2 { | ||
1223 | ( 0 ) -> A | ||
1224 | ( 1 ) -> B | ||
1225 | } | ||
1226 | Tuple3 { | ||
1227 | ( 0 ) -> A | ||
1228 | ( 1 ) -> B | ||
1229 | ( 2 ) -> C | ||
1230 | } | ||
1231 | Tuple4 { | ||
1232 | ( 0 ) -> A | ||
1233 | ( 1 ) -> B | ||
1234 | ( 2 ) -> C | ||
1235 | ( 3 ) -> D | ||
1236 | } | ||
1237 | Tuple5 { | ||
1238 | ( 0 ) -> A | ||
1239 | ( 1 ) -> B | ||
1240 | ( 2 ) -> C | ||
1241 | ( 3 ) -> D | ||
1242 | ( 4 ) -> E | ||
1243 | } | ||
1244 | Tuple6 { | ||
1245 | ( 0 ) -> A | ||
1246 | ( 1 ) -> B | ||
1247 | ( 2 ) -> C | ||
1248 | ( 3 ) -> D | ||
1249 | ( 4 ) -> E | ||
1250 | ( 5 ) -> F | ||
1251 | } | ||
1252 | Tuple7 { | ||
1253 | ( 0 ) -> A | ||
1254 | ( 1 ) -> B | ||
1255 | ( 2 ) -> C | ||
1256 | ( 3 ) -> D | ||
1257 | ( 4 ) -> E | ||
1258 | ( 5 ) -> F | ||
1259 | ( 6 ) -> G | ||
1260 | } | ||
1261 | Tuple8 { | ||
1262 | ( 0 ) -> A | ||
1263 | ( 1 ) -> B | ||
1264 | ( 2 ) -> C | ||
1265 | ( 3 ) -> D | ||
1266 | ( 4 ) -> E | ||
1267 | ( 5 ) -> F | ||
1268 | ( 6 ) -> G | ||
1269 | ( 7 ) -> H | ||
1270 | } | ||
1271 | Tuple9 { | ||
1272 | ( 0 ) -> A | ||
1273 | ( 1 ) -> B | ||
1274 | ( 2 ) -> C | ||
1275 | ( 3 ) -> D | ||
1276 | ( 4 ) -> E | ||
1277 | ( 5 ) -> F | ||
1278 | ( 6 ) -> G | ||
1279 | ( 7 ) -> H | ||
1280 | ( 8 ) -> I | ||
1281 | } | ||
1282 | Tuple10 { | ||
1283 | ( 0 ) -> A | ||
1284 | ( 1 ) -> B | ||
1285 | ( 2 ) -> C | ||
1286 | ( 3 ) -> D | ||
1287 | ( 4 ) -> E | ||
1288 | ( 5 ) -> F | ||
1289 | ( 6 ) -> G | ||
1290 | ( 7 ) -> H | ||
1291 | ( 8 ) -> I | ||
1292 | ( 9 ) -> J | ||
1293 | } | ||
1294 | Tuple11 { | ||
1295 | ( 0 ) -> A | ||
1296 | ( 1 ) -> B | ||
1297 | ( 2 ) -> C | ||
1298 | ( 3 ) -> D | ||
1299 | ( 4 ) -> E | ||
1300 | ( 5 ) -> F | ||
1301 | ( 6 ) -> G | ||
1302 | ( 7 ) -> H | ||
1303 | ( 8 ) -> I | ||
1304 | ( 9 ) -> J | ||
1305 | ( 10 ) -> K | ||
1306 | } | ||
1307 | Tuple12 { | ||
1308 | ( 0 ) -> A | ||
1309 | ( 1 ) -> B | ||
1310 | ( 2 ) -> C | ||
1311 | ( 3 ) -> D | ||
1312 | ( 4 ) -> E | ||
1313 | ( 5 ) -> F | ||
1314 | ( 6 ) -> G | ||
1315 | ( 7 ) -> H | ||
1316 | ( 8 ) -> I | ||
1317 | ( 9 ) -> J | ||
1318 | ( 10 ) -> K | ||
1319 | ( 11 ) -> L | ||
1320 | } | ||
1321 | }"#, | ||
1322 | "fn foo () {}", | ||
1323 | ); | ||
1324 | } | ||
1069 | } | 1325 | } |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 00fb09a3b..91b6db522 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -179,10 +179,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
179 | // Enable followiing code when everything is fixed | 179 | // Enable followiing code when everything is fixed |
180 | // At least we can dogfood itself to not stackoverflow | 180 | // At least we can dogfood itself to not stackoverflow |
181 | // | 181 | // |
182 | // "tt" => { | 182 | "tt" => { |
183 | // let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); | 183 | let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); |
184 | // res.inner.insert(text.clone(), Binding::Simple(token.into())); | 184 | res.inner.insert(text.clone(), Binding::Simple(token.into())); |
185 | // } | 185 | } |
186 | "item" => { | 186 | "item" => { |
187 | let item = | 187 | let item = |
188 | input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); | 188 | input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); |
@@ -226,18 +226,36 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
226 | // This should be replaced by a propper macro-by-example implementation | 226 | // This should be replaced by a propper macro-by-example implementation |
227 | let mut limit = 128; | 227 | let mut limit = 128; |
228 | let mut counter = 0; | 228 | let mut counter = 0; |
229 | while let Ok(nested) = match_lhs(subtree, input) { | 229 | |
230 | counter += 1; | 230 | let mut memento = input.save(); |
231 | limit -= 1; | 231 | |
232 | if limit == 0 { | 232 | loop { |
233 | break; | 233 | match match_lhs(subtree, input) { |
234 | } | 234 | Ok(nested) => { |
235 | res.push_nested(nested)?; | 235 | counter += 1; |
236 | if let Some(separator) = *separator { | 236 | limit -= 1; |
237 | if !input.is_eof() { | 237 | if limit == 0 { |
238 | if input.eat_punct().map(|p| p.char) != Some(separator) { | 238 | break; |
239 | return Err(ExpandError::UnexpectedToken); | ||
240 | } | 239 | } |
240 | |||
241 | memento = input.save(); | ||
242 | res.push_nested(nested)?; | ||
243 | if counter == 1 { | ||
244 | if let crate::RepeatKind::ZeroOrOne = kind { | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | if let Some(separator) = *separator { | ||
250 | if input.eat_punct().map(|p| p.char) != Some(separator) { | ||
251 | input.rollback(memento); | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | Err(_) => { | ||
257 | input.rollback(memento); | ||
258 | break; | ||
241 | } | 259 | } |
242 | } | 260 | } |
243 | } | 261 | } |
@@ -246,10 +264,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
246 | crate::RepeatKind::OneOrMore if counter == 0 => { | 264 | crate::RepeatKind::OneOrMore if counter == 0 => { |
247 | return Err(ExpandError::UnexpectedToken); | 265 | return Err(ExpandError::UnexpectedToken); |
248 | } | 266 | } |
249 | crate::RepeatKind::ZeroOrOne if counter > 1 => { | ||
250 | return Err(ExpandError::UnexpectedToken); | ||
251 | } | ||
252 | |||
253 | _ => {} | 267 | _ => {} |
254 | } | 268 | } |
255 | } | 269 | } |
@@ -333,10 +347,7 @@ fn expand_tt( | |||
333 | } | 347 | } |
334 | } | 348 | } |
335 | nesting.pop().unwrap(); | 349 | nesting.pop().unwrap(); |
336 | 350 | if has_sep { | |
337 | // Dirty hack for remove the last sep | ||
338 | // if it is a "," undo the push | ||
339 | if has_sep && repeat.separator.unwrap() == ',' { | ||
340 | token_trees.pop(); | 351 | token_trees.pop(); |
341 | } | 352 | } |
342 | 353 | ||
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs index 741b5ea1c..87bcf8b0d 100644 --- a/crates/ra_mbe/src/tt_cursor.rs +++ b/crates/ra_mbe/src/tt_cursor.rs | |||
@@ -7,6 +7,10 @@ pub(crate) struct TtCursor<'a> { | |||
7 | pos: usize, | 7 | pos: usize, |
8 | } | 8 | } |
9 | 9 | ||
10 | pub(crate) struct TtCursorMemento { | ||
11 | pos: usize, | ||
12 | } | ||
13 | |||
10 | impl<'a> TtCursor<'a> { | 14 | impl<'a> TtCursor<'a> { |
11 | pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> { | 15 | pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> { |
12 | TtCursor { subtree, pos: 0 } | 16 | TtCursor { subtree, pos: 0 } |
@@ -157,4 +161,13 @@ impl<'a> TtCursor<'a> { | |||
157 | Err(ParseError::Expected(format!("`{}`", char))) | 161 | Err(ParseError::Expected(format!("`{}`", char))) |
158 | } | 162 | } |
159 | } | 163 | } |
164 | |||
165 | #[must_use] | ||
166 | pub(crate) fn save(&self) -> TtCursorMemento { | ||
167 | TtCursorMemento { pos: self.pos } | ||
168 | } | ||
169 | |||
170 | pub(crate) fn rollback(&mut self, memento: TtCursorMemento) { | ||
171 | self.pos = memento.pos; | ||
172 | } | ||
160 | } | 173 | } |