diff options
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 66ea76698..00fb09a3b 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -221,11 +221,13 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
221 | } | 221 | } |
222 | _ => return Err(ExpandError::UnexpectedToken), | 222 | _ => return Err(ExpandError::UnexpectedToken), |
223 | }, | 223 | }, |
224 | crate::TokenTree::Repeat(crate::Repeat { subtree, kind: _, separator }) => { | 224 | crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { |
225 | // Dirty hack to make macro-expansion terminate. | 225 | // Dirty hack to make macro-expansion terminate. |
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 | while let Ok(nested) = match_lhs(subtree, input) { | 229 | while let Ok(nested) = match_lhs(subtree, input) { |
230 | counter += 1; | ||
229 | limit -= 1; | 231 | limit -= 1; |
230 | if limit == 0 { | 232 | if limit == 0 { |
231 | break; | 233 | break; |
@@ -239,6 +241,17 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
239 | } | 241 | } |
240 | } | 242 | } |
241 | } | 243 | } |
244 | |||
245 | match kind { | ||
246 | crate::RepeatKind::OneOrMore if counter == 0 => { | ||
247 | return Err(ExpandError::UnexpectedToken); | ||
248 | } | ||
249 | crate::RepeatKind::ZeroOrOne if counter > 1 => { | ||
250 | return Err(ExpandError::UnexpectedToken); | ||
251 | } | ||
252 | |||
253 | _ => {} | ||
254 | } | ||
242 | } | 255 | } |
243 | crate::TokenTree::Subtree(subtree) => { | 256 | crate::TokenTree::Subtree(subtree) => { |
244 | let input_subtree = | 257 | let input_subtree = |
@@ -274,6 +287,20 @@ fn expand_subtree( | |||
274 | Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) | 287 | Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) |
275 | } | 288 | } |
276 | 289 | ||
290 | /// Reduce single token subtree to single token | ||
291 | /// In `tt` matcher case, all tt tokens will be braced by a Delimiter::None | ||
292 | /// which makes all sort of problems. | ||
293 | fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree { | ||
294 | if subtree.delimiter != tt::Delimiter::None || subtree.token_trees.len() != 1 { | ||
295 | return subtree.into(); | ||
296 | } | ||
297 | |||
298 | match subtree.token_trees.pop().unwrap() { | ||
299 | tt::TokenTree::Subtree(subtree) => reduce_single_token(subtree), | ||
300 | tt::TokenTree::Leaf(token) => token.into(), | ||
301 | } | ||
302 | } | ||
303 | |||
277 | fn expand_tt( | 304 | fn expand_tt( |
278 | template: &crate::TokenTree, | 305 | template: &crate::TokenTree, |
279 | bindings: &Bindings, | 306 | bindings: &Bindings, |
@@ -282,11 +309,13 @@ fn expand_tt( | |||
282 | let res: tt::TokenTree = match template { | 309 | let res: tt::TokenTree = match template { |
283 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(), | 310 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(), |
284 | crate::TokenTree::Repeat(repeat) => { | 311 | crate::TokenTree::Repeat(repeat) => { |
285 | let mut token_trees = Vec::new(); | 312 | let mut token_trees: Vec<tt::TokenTree> = Vec::new(); |
286 | nesting.push(0); | 313 | nesting.push(0); |
287 | // Dirty hack to make macro-expansion terminate. | 314 | // Dirty hack to make macro-expansion terminate. |
288 | // This should be replaced by a propper macro-by-example implementation | 315 | // This should be replaced by a propper macro-by-example implementation |
289 | let mut limit = 128; | 316 | let mut limit = 128; |
317 | let mut has_sep = false; | ||
318 | |||
290 | while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) { | 319 | while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) { |
291 | limit -= 1; | 320 | limit -= 1; |
292 | if limit == 0 { | 321 | if limit == 0 { |
@@ -294,10 +323,26 @@ fn expand_tt( | |||
294 | } | 323 | } |
295 | let idx = nesting.pop().unwrap(); | 324 | let idx = nesting.pop().unwrap(); |
296 | nesting.push(idx + 1); | 325 | nesting.push(idx + 1); |
297 | token_trees.push(t.into()) | 326 | token_trees.push(reduce_single_token(t).into()); |
327 | |||
328 | if let Some(sep) = repeat.separator { | ||
329 | let punct = | ||
330 | tt::Leaf::from(tt::Punct { char: sep, spacing: tt::Spacing::Alone }); | ||
331 | token_trees.push(punct.into()); | ||
332 | has_sep = true; | ||
333 | } | ||
298 | } | 334 | } |
299 | nesting.pop().unwrap(); | 335 | nesting.pop().unwrap(); |
300 | tt::Subtree { token_trees, delimiter: tt::Delimiter::None }.into() | 336 | |
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(); | ||
341 | } | ||
342 | |||
343 | // Check if it is a singel token subtree without any delimiter | ||
344 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | ||
345 | reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) | ||
301 | } | 346 | } |
302 | crate::TokenTree::Leaf(leaf) => match leaf { | 347 | crate::TokenTree::Leaf(leaf) => match leaf { |
303 | crate::Leaf::Ident(ident) => { | 348 | crate::Leaf::Ident(ident) => { |
@@ -311,7 +356,13 @@ fn expand_tt( | |||
311 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) | 356 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) |
312 | .into() | 357 | .into() |
313 | } else { | 358 | } else { |
314 | bindings.get(&v.text, nesting)?.clone() | 359 | let tkn = bindings.get(&v.text, nesting)?.clone(); |
360 | |||
361 | if let tt::TokenTree::Subtree(subtree) = tkn { | ||
362 | reduce_single_token(subtree) | ||
363 | } else { | ||
364 | tkn | ||
365 | } | ||
315 | } | 366 | } |
316 | } | 367 | } |
317 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), | 368 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), |