diff options
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 42 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 2 |
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)] |
157 | mod tests; \ No newline at end of file | 157 | mod 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 | ||
86 | impl Bindings { | 86 | impl 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 | ||