aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2019-05-03 16:23:21 +0100
committerEdwin Cheng <[email protected]>2019-05-03 16:23:21 +0100
commit31909cc7d77fea5e08aaa9fd149338b243ec600f (patch)
tree56c826ab4dd6cc5f531af919f91184e3aa50d248 /crates/ra_mbe
parente8e46100d6c2ae617e1321bb01ce5a2f3cb37c6a (diff)
By pass unbind $var while mbe expanding
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r--crates/ra_mbe/src/lib.rs2
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs42
-rw-r--r--crates/ra_mbe/src/tests.rs2
3 files changed, 39 insertions, 7 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 9afc33093..c146252a4 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -154,4 +154,4 @@ pub(crate) struct Var {
154} 154}
155 155
156#[cfg(test)] 156#[cfg(test)]
157mod tests; \ No newline at end of file 157mod tests;
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 1453a106d..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
@@ -458,6 +462,33 @@ fn expand_tt(
458 // FIXME: Properly handle $crate token 462 // FIXME: Properly handle $crate token
459 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) 463 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
460 .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()
461 } else { 492 } else {
462 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); 493 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
463 ctx.var_expanded = true; 494 ctx.var_expanded = true;
@@ -484,11 +515,12 @@ mod tests {
484 515
485 #[test] 516 #[test]
486 fn test_expand_rule() { 517 fn test_expand_rule() {
487 assert_err( 518 // FIXME: The missing $var check should be in parsing phase
488 "($i:ident) => ($j)", 519 // assert_err(
489 "foo!{a}", 520 // "($i:ident) => ($j)",
490 ExpandError::BindingError(String::from("could not find binding `j`")), 521 // "foo!{a}",
491 ); 522 // ExpandError::BindingError(String::from("could not find binding `j`")),
523 // );
492 524
493 assert_err( 525 assert_err(
494 "($($i:ident);*) => ($i)", 526 "($($i:ident);*) => ($i)",
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index b81e6fcc9..cdbd4dd1c 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -952,7 +952,7 @@ macro_rules! foo {
952 MacroKind::Items, 952 MacroKind::Items,
953 &rules, 953 &rules,
954 r#"foo!(x,y, 1);"#, 954 r#"foo!(x,y, 1);"#,
955 r#"macro_rules ! bar {(bi : ident) => {fn bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, 955 r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
956 ); 956 );
957} 957}
958 958