diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-03 13:51:07 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-03 13:51:07 +0100 |
commit | e593d4ac73497f01d577a88ff1a0d57f63734dbf (patch) | |
tree | 03532b56d9300d307986e1a6bc6dddf8c30e7621 | |
parent | 9901f3e45efebafbd0e9f53951346f171792b169 (diff) | |
parent | 11d6a1449de1ae4284fe73d9955d29ae6eea2356 (diff) |
Merge #1226
1226: Fix Bug in mbe on mismatching bindings count r=matklad a=edwin0cheng
This PR do the followings things:
1. Fixed a bug happened in following code by inserting empty bindings before a nested bindings:
```
macro_rules foo! {
($( ($($a:ident)* => $($b:ident))*))* => { ... }
}
foo!( ( => a) (b => ) )
```
2. Fixed a bug which forget to restore `var_expanded`.
3. Some cleanup
Co-authored-by: Edwin Cheng <[email protected]>
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 22 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 45 |
2 files changed, 43 insertions, 24 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index be9ea3ebb..ea2104b1c 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -99,13 +99,31 @@ pub(crate) struct Subtree { | |||
99 | pub(crate) token_trees: Vec<TokenTree>, | 99 | pub(crate) token_trees: Vec<TokenTree>, |
100 | } | 100 | } |
101 | 101 | ||
102 | #[derive(Clone, Debug, PartialEq, Eq)] | 102 | #[derive(Clone, Debug, Eq)] |
103 | pub(crate) enum Separator { | 103 | pub(crate) enum Separator { |
104 | Literal(tt::Literal), | 104 | Literal(tt::Literal), |
105 | Ident(tt::Ident), | 105 | Ident(tt::Ident), |
106 | Puncts(SmallVec<[tt::Punct; 3]>), | 106 | Puncts(SmallVec<[tt::Punct; 3]>), |
107 | } | 107 | } |
108 | 108 | ||
109 | // Note that when we compare a Separator, we just care about its textual value. | ||
110 | impl PartialEq for crate::Separator { | ||
111 | fn eq(&self, other: &crate::Separator) -> bool { | ||
112 | use crate::Separator::*; | ||
113 | |||
114 | match (self, other) { | ||
115 | (Ident(ref a), Ident(ref b)) => a.text == b.text, | ||
116 | (Literal(ref a), Literal(ref b)) => a.text == b.text, | ||
117 | (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => { | ||
118 | let a_iter = a.iter().map(|a| a.char); | ||
119 | let b_iter = b.iter().map(|b| b.char); | ||
120 | a_iter.eq(b_iter) | ||
121 | } | ||
122 | _ => false, | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
109 | #[derive(Clone, Debug, PartialEq, Eq)] | 127 | #[derive(Clone, Debug, PartialEq, Eq)] |
110 | pub(crate) struct Repeat { | 128 | pub(crate) struct Repeat { |
111 | pub(crate) subtree: Subtree, | 129 | pub(crate) subtree: Subtree, |
@@ -1270,6 +1288,6 @@ cfg_if ! { | |||
1270 | } | 1288 | } |
1271 | } | 1289 | } |
1272 | "#, | 1290 | "#, |
1273 | "__cfg_if_items ! {() ; (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); | 1291 | "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); |
1274 | } | 1292 | } |
1275 | } | 1293 | } |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 1b579f319..361b1e404 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -107,13 +107,19 @@ impl Bindings { | |||
107 | } | 107 | } |
108 | } | 108 | } |
109 | 109 | ||
110 | fn push_nested(&mut self, nested: Bindings) -> Result<(), ExpandError> { | 110 | fn push_nested(&mut self, idx: usize, nested: Bindings) -> Result<(), ExpandError> { |
111 | for (key, value) in nested.inner { | 111 | for (key, value) in nested.inner { |
112 | if !self.inner.contains_key(&key) { | 112 | if !self.inner.contains_key(&key) { |
113 | self.inner.insert(key.clone(), Binding::Nested(Vec::new())); | 113 | self.inner.insert(key.clone(), Binding::Nested(Vec::new())); |
114 | } | 114 | } |
115 | match self.inner.get_mut(&key) { | 115 | match self.inner.get_mut(&key) { |
116 | Some(Binding::Nested(it)) => it.push(value), | 116 | Some(Binding::Nested(it)) => { |
117 | // insert empty nested bindings before this one | ||
118 | while it.len() < idx { | ||
119 | it.push(Binding::Nested(vec![])); | ||
120 | } | ||
121 | it.push(value); | ||
122 | } | ||
117 | _ => { | 123 | _ => { |
118 | return Err(ExpandError::BindingError(format!( | 124 | return Err(ExpandError::BindingError(format!( |
119 | "could not find binding `{}`", | 125 | "could not find binding `{}`", |
@@ -178,10 +184,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
178 | input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone(); | 184 | input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone(); |
179 | res.inner.insert(text.clone(), Binding::Simple(meta.into())); | 185 | res.inner.insert(text.clone(), Binding::Simple(meta.into())); |
180 | } | 186 | } |
181 | // FIXME: | ||
182 | // Enable followiing code when everything is fixed | ||
183 | // At least we can dogfood itself to not stackoverflow | ||
184 | // | ||
185 | "tt" => { | 187 | "tt" => { |
186 | let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); | 188 | let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); |
187 | res.inner.insert(text.clone(), Binding::Simple(token.into())); | 189 | res.inner.insert(text.clone(), Binding::Simple(token.into())); |
@@ -252,7 +254,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
252 | loop { | 254 | loop { |
253 | match match_lhs(subtree, input) { | 255 | match match_lhs(subtree, input) { |
254 | Ok(nested) => { | 256 | Ok(nested) => { |
255 | counter += 1; | ||
256 | limit -= 1; | 257 | limit -= 1; |
257 | if limit == 0 { | 258 | if limit == 0 { |
258 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator); | 259 | 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<Bindings, | |||
260 | } | 261 | } |
261 | 262 | ||
262 | memento = input.save(); | 263 | memento = input.save(); |
263 | res.push_nested(nested)?; | 264 | res.push_nested(counter, nested)?; |
265 | counter += 1; | ||
264 | if counter == 1 { | 266 | if counter == 1 { |
265 | if let crate::RepeatKind::ZeroOrOne = kind { | 267 | if let crate::RepeatKind::ZeroOrOne = kind { |
266 | break; | 268 | break; |
@@ -268,20 +270,9 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
268 | } | 270 | } |
269 | 271 | ||
270 | if let Some(separator) = separator { | 272 | if let Some(separator) = separator { |
271 | use crate::Separator::*; | ||
272 | |||
273 | if !input | 273 | if !input |
274 | .eat_seperator() | 274 | .eat_seperator() |
275 | .map(|sep| match (sep, separator) { | 275 | .map(|sep| sep == *separator) |
276 | (Ident(ref a), Ident(ref b)) => a.text == b.text, | ||
277 | (Literal(ref a), Literal(ref b)) => a.text == b.text, | ||
278 | (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => { | ||
279 | let a_iter = a.iter().map(|a| a.char); | ||
280 | let b_iter = b.iter().map(|b| b.char); | ||
281 | a_iter.eq(b_iter) | ||
282 | } | ||
283 | _ => false, | ||
284 | }) | ||
285 | .unwrap_or(false) | 276 | .unwrap_or(false) |
286 | { | 277 | { |
287 | input.rollback(memento); | 278 | input.rollback(memento); |
@@ -372,14 +363,23 @@ fn expand_tt( | |||
372 | let mut has_seps = 0; | 363 | let mut has_seps = 0; |
373 | let mut counter = 0; | 364 | let mut counter = 0; |
374 | 365 | ||
366 | // We store the old var expanded value, and restore it later | ||
367 | // It is because before this `$repeat`, | ||
368 | // it is possible some variables already expanad in the same subtree | ||
369 | // | ||
370 | // `some_var_expanded` keep check if the deeper subtree has expanded variables | ||
375 | let mut some_var_expanded = false; | 371 | let mut some_var_expanded = false; |
372 | let old_var_expanded = ctx.var_expanded; | ||
376 | ctx.var_expanded = false; | 373 | ctx.var_expanded = false; |
377 | 374 | ||
378 | while let Ok(t) = expand_subtree(&repeat.subtree, ctx) { | 375 | while let Ok(t) = expand_subtree(&repeat.subtree, ctx) { |
379 | // if no var expaned in the child, we count it as a fail | 376 | // if no var expanded in the child, we count it as a fail |
380 | if !ctx.var_expanded { | 377 | if !ctx.var_expanded { |
381 | break; | 378 | break; |
382 | } | 379 | } |
380 | |||
381 | // Reset `ctx.var_expandeded` to see if there is other expanded variable | ||
382 | // in the next matching | ||
383 | some_var_expanded = true; | 383 | some_var_expanded = true; |
384 | ctx.var_expanded = false; | 384 | ctx.var_expanded = false; |
385 | 385 | ||
@@ -423,7 +423,8 @@ fn expand_tt( | |||
423 | } | 423 | } |
424 | } | 424 | } |
425 | 425 | ||
426 | ctx.var_expanded = some_var_expanded; | 426 | // Restore the `var_expanded` by combining old one and the new one |
427 | ctx.var_expanded = some_var_expanded || old_var_expanded; | ||
427 | 428 | ||
428 | ctx.nesting.pop().unwrap(); | 429 | ctx.nesting.pop().unwrap(); |
429 | for _ in 0..has_seps { | 430 | for _ in 0..has_seps { |