aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-03 13:51:07 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-03 13:51:07 +0100
commite593d4ac73497f01d577a88ff1a0d57f63734dbf (patch)
tree03532b56d9300d307986e1a6bc6dddf8c30e7621
parent9901f3e45efebafbd0e9f53951346f171792b169 (diff)
parent11d6a1449de1ae4284fe73d9955d29ae6eea2356 (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.rs22
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs45
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)]
103pub(crate) enum Separator { 103pub(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.
110impl 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)]
110pub(crate) struct Repeat { 128pub(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 {