From 31909cc7d77fea5e08aaa9fd149338b243ec600f Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 3 May 2019 23:23:21 +0800 Subject: By pass unbind $var while mbe expanding --- crates/ra_mbe/src/lib.rs | 2 +- crates/ra_mbe/src/mbe_expander.rs | 42 ++++++++++++++++++++++++++++++++++----- 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 { } #[cfg(test)] -mod tests; \ No newline at end of file +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 { } impl Bindings { + fn contains(&self, name: &SmolStr) -> bool { + self.inner.contains_key(name) + } + fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> { let mut b = self .inner @@ -458,6 +462,33 @@ fn expand_tt( // FIXME: Properly handle $crate token tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) .into() + } else if !ctx.bindings.contains(&v.text) { + // Note that it is possible to have a `$var` inside a macro which is not bound. + // For example: + // ``` + // macro_rules! foo { + // ($a:ident, $b:ident, $c:tt) => { + // macro_rules! bar { + // ($bi:ident) => { + // fn $bi() -> u8 {$c} + // } + // } + // } + // ``` + // We just treat it a normal tokens + tt::Subtree { + delimiter: tt::Delimiter::None, + token_trees: vec![ + tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }) + .into(), + tt::Leaf::from(tt::Ident { + text: v.text.clone(), + id: TokenId::unspecified(), + }) + .into(), + ], + } + .into() } else { let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); ctx.var_expanded = true; @@ -484,11 +515,12 @@ mod tests { #[test] fn test_expand_rule() { - assert_err( - "($i:ident) => ($j)", - "foo!{a}", - ExpandError::BindingError(String::from("could not find binding `j`")), - ); + // FIXME: The missing $var check should be in parsing phase + // assert_err( + // "($i:ident) => ($j)", + // "foo!{a}", + // ExpandError::BindingError(String::from("could not find binding `j`")), + // ); assert_err( "($($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 { MacroKind::Items, &rules, r#"foo!(x,y, 1);"#, - r#"macro_rules ! bar {(bi : ident) => {fn bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, + r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, ); } -- cgit v1.2.3