aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander.rs
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2019-04-25 16:12:57 +0100
committerEdwin Cheng <[email protected]>2019-04-25 19:03:56 +0100
commitc55a2dbc1de8ba42df57b70f652eb6a0c0bbc9f6 (patch)
tree082cbca15c8af95ea0be73319a9ac00e45ba5cf1 /crates/ra_mbe/src/mbe_expander.rs
parent299d97b6d98cec673ff056c188ac45a17febc7d4 (diff)
Fix more bugs
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs69
1 files changed, 54 insertions, 15 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 7411dd8b1..d5189b537 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -21,7 +21,10 @@ fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Result<tt::Subtree, E
21 if !input.is_eof() { 21 if !input.is_eof() {
22 return Err(ExpandError::UnexpectedToken); 22 return Err(ExpandError::UnexpectedToken);
23 } 23 }
24 expand_subtree(&rule.rhs, &bindings, &mut Vec::new()) 24
25 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false };
26
27 expand_subtree(&rule.rhs, &mut ctx)
25} 28}
26 29
27/// The actual algorithm for expansion is not too hard, but is pretty tricky. 30/// The actual algorithm for expansion is not too hard, but is pretty tricky.
@@ -225,7 +228,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
225 crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { 228 crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => {
226 // Dirty hack to make macro-expansion terminate. 229 // Dirty hack to make macro-expansion terminate.
227 // This should be replaced by a propper macro-by-example implementation 230 // This should be replaced by a propper macro-by-example implementation
228 let mut limit = 128; 231 let mut limit = 65536;
229 let mut counter = 0; 232 let mut counter = 0;
230 233
231 let mut memento = input.save(); 234 let mut memento = input.save();
@@ -236,6 +239,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
236 counter += 1; 239 counter += 1;
237 limit -= 1; 240 limit -= 1;
238 if limit == 0 { 241 if limit == 0 {
242 log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator);
239 break; 243 break;
240 } 244 }
241 245
@@ -303,15 +307,21 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
303 Ok(res) 307 Ok(res)
304} 308}
305 309
310#[derive(Debug)]
311struct ExpandCtx<'a> {
312 bindings: &'a Bindings,
313 nesting: Vec<usize>,
314 var_expanded: bool,
315}
316
306fn expand_subtree( 317fn expand_subtree(
307 template: &crate::Subtree, 318 template: &crate::Subtree,
308 bindings: &Bindings, 319 ctx: &mut ExpandCtx,
309 nesting: &mut Vec<usize>,
310) -> Result<tt::Subtree, ExpandError> { 320) -> Result<tt::Subtree, ExpandError> {
311 let token_trees = template 321 let token_trees = template
312 .token_trees 322 .token_trees
313 .iter() 323 .iter()
314 .map(|it| expand_tt(it, bindings, nesting)) 324 .map(|it| expand_tt(it, ctx))
315 .collect::<Result<Vec<_>, ExpandError>>()?; 325 .collect::<Result<Vec<_>, ExpandError>>()?;
316 326
317 Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) 327 Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
@@ -333,26 +343,43 @@ fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree {
333 343
334fn expand_tt( 344fn expand_tt(
335 template: &crate::TokenTree, 345 template: &crate::TokenTree,
336 bindings: &Bindings, 346 ctx: &mut ExpandCtx,
337 nesting: &mut Vec<usize>,
338) -> Result<tt::TokenTree, ExpandError> { 347) -> Result<tt::TokenTree, ExpandError> {
339 let res: tt::TokenTree = match template { 348 let res: tt::TokenTree = match template {
340 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(), 349 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(),
341 crate::TokenTree::Repeat(repeat) => { 350 crate::TokenTree::Repeat(repeat) => {
342 let mut token_trees: Vec<tt::TokenTree> = Vec::new(); 351 let mut token_trees: Vec<tt::TokenTree> = Vec::new();
343 nesting.push(0); 352 ctx.nesting.push(0);
344 // Dirty hack to make macro-expansion terminate. 353 // Dirty hack to make macro-expansion terminate.
345 // This should be replaced by a propper macro-by-example implementation 354 // This should be replaced by a propper macro-by-example implementation
346 let mut limit = 128; 355 let mut limit = 65536;
347 let mut has_seps = 0; 356 let mut has_seps = 0;
357 let mut counter = 0;
358
359 let mut some_var_expanded = false;
360 ctx.var_expanded = false;
361
362 while let Ok(t) = expand_subtree(&repeat.subtree, ctx) {
363 // if no var expaned in the child, we count it as a fail
364 if !ctx.var_expanded {
365 break;
366 }
367 some_var_expanded = true;
368 ctx.var_expanded = false;
348 369
349 while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) { 370 counter += 1;
350 limit -= 1; 371 limit -= 1;
351 if limit == 0 { 372 if limit == 0 {
373 log::warn!(
374 "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}",
375 template,
376 ctx
377 );
352 break; 378 break;
353 } 379 }
354 let idx = nesting.pop().unwrap(); 380
355 nesting.push(idx + 1); 381 let idx = ctx.nesting.pop().unwrap();
382 ctx.nesting.push(idx + 1);
356 token_trees.push(reduce_single_token(t).into()); 383 token_trees.push(reduce_single_token(t).into());
357 384
358 if let Some(ref sep) = repeat.separator { 385 if let Some(ref sep) = repeat.separator {
@@ -374,12 +401,23 @@ fn expand_tt(
374 } 401 }
375 } 402 }
376 } 403 }
404
405 if let crate::RepeatKind::ZeroOrOne = repeat.kind {
406 break;
407 }
377 } 408 }
378 nesting.pop().unwrap(); 409
410 ctx.var_expanded = some_var_expanded;
411
412 ctx.nesting.pop().unwrap();
379 for _ in 0..has_seps { 413 for _ in 0..has_seps {
380 token_trees.pop(); 414 token_trees.pop();
381 } 415 }
382 416
417 if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 {
418 return Err(ExpandError::UnexpectedToken);
419 }
420
383 // Check if it is a singel token subtree without any delimiter 421 // Check if it is a singel token subtree without any delimiter
384 // e.g {Delimiter:None> ['>'] /Delimiter:None>} 422 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
385 reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) 423 reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None })
@@ -396,7 +434,8 @@ fn expand_tt(
396 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) 434 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
397 .into() 435 .into()
398 } else { 436 } else {
399 let tkn = bindings.get(&v.text, nesting)?.clone(); 437 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
438 ctx.var_expanded = true;
400 439
401 if let tt::TokenTree::Subtree(subtree) = tkn { 440 if let tt::TokenTree::Subtree(subtree) = tkn {
402 reduce_single_token(subtree) 441 reduce_single_token(subtree)