aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-03 16:36:19 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-03 16:36:19 +0100
commit26b499811489f72ad5176d68d40c9a0748620417 (patch)
tree56c826ab4dd6cc5f531af919f91184e3aa50d248 /crates/ra_mbe/src/mbe_expander.rs
parentb29f442c8b8601feec4dbc49f121801b153d83e1 (diff)
parent31909cc7d77fea5e08aaa9fd149338b243ec600f (diff)
Merge #1228
1228: Add inner macro checker in mbe r=matklad a=edwin0cheng This PR do the following things: * Add an inner macro checker for allowing defining mbe in mbe. (It is a adhoc solution, we could eliminate it after we have a better mbe parser) * Move all tests to an tests modules * Filter empty tree while expanding mbe. This is the final PR extracting from #1219 Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs50
1 files changed, 45 insertions, 5 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 361b1e404..8f8a79855 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -84,6 +84,10 @@ enum Binding {
84} 84}
85 85
86impl Bindings { 86impl Bindings {
87 fn contains(&self, name: &SmolStr) -> bool {
88 self.inner.contains_key(name)
89 }
90
87 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> { 91 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> {
88 let mut b = self 92 let mut b = self
89 .inner 93 .inner
@@ -329,6 +333,14 @@ fn expand_subtree(
329 .token_trees 333 .token_trees
330 .iter() 334 .iter()
331 .map(|it| expand_tt(it, ctx)) 335 .map(|it| expand_tt(it, ctx))
336 .filter(|it| {
337 // Filter empty subtree
338 if let Ok(tt::TokenTree::Subtree(subtree)) = it {
339 subtree.delimiter != tt::Delimiter::None || !subtree.token_trees.is_empty()
340 } else {
341 true
342 }
343 })
332 .collect::<Result<Vec<_>, ExpandError>>()?; 344 .collect::<Result<Vec<_>, ExpandError>>()?;
333 345
334 Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) 346 Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
@@ -450,6 +462,33 @@ fn expand_tt(
450 // FIXME: Properly handle $crate token 462 // FIXME: Properly handle $crate token
451 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) 463 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
452 .into() 464 .into()
465 } else if !ctx.bindings.contains(&v.text) {
466 // Note that it is possible to have a `$var` inside a macro which is not bound.
467 // For example:
468 // ```
469 // macro_rules! foo {
470 // ($a:ident, $b:ident, $c:tt) => {
471 // macro_rules! bar {
472 // ($bi:ident) => {
473 // fn $bi() -> u8 {$c}
474 // }
475 // }
476 // }
477 // ```
478 // We just treat it a normal tokens
479 tt::Subtree {
480 delimiter: tt::Delimiter::None,
481 token_trees: vec![
482 tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone })
483 .into(),
484 tt::Leaf::from(tt::Ident {
485 text: v.text.clone(),
486 id: TokenId::unspecified(),
487 })
488 .into(),
489 ],
490 }
491 .into()
453 } else { 492 } else {
454 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); 493 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
455 ctx.var_expanded = true; 494 ctx.var_expanded = true;
@@ -476,11 +515,12 @@ mod tests {
476 515
477 #[test] 516 #[test]
478 fn test_expand_rule() { 517 fn test_expand_rule() {
479 assert_err( 518 // FIXME: The missing $var check should be in parsing phase
480 "($i:ident) => ($j)", 519 // assert_err(
481 "foo!{a}", 520 // "($i:ident) => ($j)",
482 ExpandError::BindingError(String::from("could not find binding `j`")), 521 // "foo!{a}",
483 ); 522 // ExpandError::BindingError(String::from("could not find binding `j`")),
523 // );
484 524
485 assert_err( 525 assert_err(
486 "($($i:ident);*) => ($i)", 526 "($($i:ident);*) => ($i)",