From 1446d620c5a8865708b238550e4c0457577a0cd1 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Thu, 2 May 2019 23:23:14 +0800 Subject: Add empty bindings and some refactoring --- crates/ra_mbe/src/lib.rs | 20 +++++++++++++++++- crates/ra_mbe/src/mbe_expander.rs | 43 ++++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index be9ea3ebb..08bb89a6a 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs @@ -99,13 +99,31 @@ pub(crate) struct Subtree { pub(crate) token_trees: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Eq)] pub(crate) enum Separator { Literal(tt::Literal), Ident(tt::Ident), Puncts(SmallVec<[tt::Punct; 3]>), } +// Note that when we compare a Separator, we just care about its textual value. +impl PartialEq for crate::Separator { + fn eq(&self, other: &crate::Separator) -> bool { + use crate::Separator::*; + + match (self, other) { + (Ident(ref a), Ident(ref b)) => a == b, + (Literal(ref a), Literal(ref b)) => a == b, + (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => { + let a_iter = a.iter().map(|a| a.char); + let b_iter = b.iter().map(|b| b.char); + a_iter.eq(b_iter) + } + _ => false, + } + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct Repeat { pub(crate) subtree: Subtree, diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 1b579f319..087a0cd63 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs @@ -107,13 +107,19 @@ impl Bindings { } } - fn push_nested(&mut self, nested: Bindings) -> Result<(), ExpandError> { + fn push_nested(&mut self, idx: usize, nested: Bindings) -> Result<(), ExpandError> { for (key, value) in nested.inner { if !self.inner.contains_key(&key) { self.inner.insert(key.clone(), Binding::Nested(Vec::new())); } match self.inner.get_mut(&key) { - Some(Binding::Nested(it)) => it.push(value), + Some(Binding::Nested(it)) => { + // insert empty nested bindings before this one + while it.len() < idx { + it.push(Binding::Nested(vec![])); + } + it.push(value); + } _ => { return Err(ExpandError::BindingError(format!( "could not find binding `{}`", @@ -178,10 +184,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result { let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); res.inner.insert(text.clone(), Binding::Simple(token.into())); @@ -252,7 +254,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result { - counter += 1; limit -= 1; if limit == 0 { log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator); @@ -260,7 +261,8 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result Result a.text == b.text, - (Literal(ref a), Literal(ref b)) => a.text == b.text, - (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => { - let a_iter = a.iter().map(|a| a.char); - let b_iter = b.iter().map(|b| b.char); - a_iter.eq(b_iter) - } - _ => false, - }) + .map(|sep| sep == *separator) .unwrap_or(false) { input.rollback(memento); @@ -372,7 +363,13 @@ fn expand_tt( let mut has_seps = 0; let mut counter = 0; + // We store the old var expaned value, and restore it later + // It is because before this `$repeat`, + // it is possible some variables already expanad in the same subtree + // + // `some_var_expanded` keep check if the deeper subtree has expanded variables let mut some_var_expanded = false; + let old_var_expanded = ctx.var_expanded; ctx.var_expanded = false; while let Ok(t) = expand_subtree(&repeat.subtree, ctx) { @@ -380,6 +377,9 @@ fn expand_tt( if !ctx.var_expanded { break; } + + // Reset `ctx.var_expaneded` to see if there is other expaned variable + // in the next matching some_var_expanded = true; ctx.var_expanded = false; @@ -423,7 +423,8 @@ fn expand_tt( } } - ctx.var_expanded = some_var_expanded; + // Restore the `var_expanded` by combining old one and the new one + ctx.var_expanded = some_var_expanded || old_var_expanded; ctx.nesting.pop().unwrap(); for _ in 0..has_seps { -- cgit v1.2.3