aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs152
1 files changed, 123 insertions, 29 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index d5189b537..4b007647c 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -81,9 +81,29 @@ struct Bindings {
81enum Binding { 81enum Binding {
82 Simple(tt::TokenTree), 82 Simple(tt::TokenTree),
83 Nested(Vec<Binding>), 83 Nested(Vec<Binding>),
84 Empty,
84} 85}
85 86
86impl Bindings { 87impl Bindings {
88 fn push_optional(&mut self, name: &SmolStr) {
89 // FIXME: Do we have a better way to represent an empty token ?
90 // Insert an empty subtree for empty token
91 self.inner.insert(
92 name.clone(),
93 Binding::Simple(
94 tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(),
95 ),
96 );
97 }
98
99 fn push_empty(&mut self, name: &SmolStr) {
100 self.inner.insert(name.clone(), Binding::Empty);
101 }
102
103 fn contains(&self, name: &SmolStr) -> bool {
104 self.inner.contains_key(name)
105 }
106
87 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> { 107 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> {
88 let mut b = self 108 let mut b = self
89 .inner 109 .inner
@@ -96,6 +116,12 @@ impl Bindings {
96 "could not find nested binding `{}`", 116 "could not find nested binding `{}`",
97 name 117 name
98 )))?, 118 )))?,
119 Binding::Empty => {
120 return Err(ExpandError::BindingError(format!(
121 "could not find empty binding `{}`",
122 name
123 )))
124 }
99 }; 125 };
100 } 126 }
101 match b { 127 match b {
@@ -104,16 +130,26 @@ impl Bindings {
104 "expected simple binding, found nested binding `{}`", 130 "expected simple binding, found nested binding `{}`",
105 name 131 name
106 ))), 132 ))),
133 Binding::Empty => Err(ExpandError::BindingError(format!(
134 "expected simple binding, found empty binding `{}`",
135 name
136 ))),
107 } 137 }
108 } 138 }
109 139
110 fn push_nested(&mut self, nested: Bindings) -> Result<(), ExpandError> { 140 fn push_nested(&mut self, idx: usize, nested: Bindings) -> Result<(), ExpandError> {
111 for (key, value) in nested.inner { 141 for (key, value) in nested.inner {
112 if !self.inner.contains_key(&key) { 142 if !self.inner.contains_key(&key) {
113 self.inner.insert(key.clone(), Binding::Nested(Vec::new())); 143 self.inner.insert(key.clone(), Binding::Nested(Vec::new()));
114 } 144 }
115 match self.inner.get_mut(&key) { 145 match self.inner.get_mut(&key) {
116 Some(Binding::Nested(it)) => it.push(value), 146 Some(Binding::Nested(it)) => {
147 // insert empty nested bindings before this one
148 while it.len() < idx {
149 it.push(Binding::Nested(vec![]));
150 }
151 it.push(value);
152 }
117 _ => { 153 _ => {
118 return Err(ExpandError::BindingError(format!( 154 return Err(ExpandError::BindingError(format!(
119 "could not find binding `{}`", 155 "could not find binding `{}`",
@@ -130,6 +166,24 @@ impl Bindings {
130 } 166 }
131} 167}
132 168
169fn collect_vars(subtree: &crate::Subtree) -> Vec<SmolStr> {
170 let mut res = vec![];
171
172 for tkn in subtree.token_trees.iter() {
173 match tkn {
174 crate::TokenTree::Leaf(crate::Leaf::Var(crate::Var { text, .. })) => {
175 res.push(text.clone());
176 }
177 crate::TokenTree::Subtree(subtree) => {
178 res.extend(collect_vars(subtree));
179 }
180 _ => {}
181 }
182 }
183
184 res
185}
186
133fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, ExpandError> { 187fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, ExpandError> {
134 let mut res = Bindings::default(); 188 let mut res = Bindings::default();
135 for pat in pattern.token_trees.iter() { 189 for pat in pattern.token_trees.iter() {
@@ -178,10 +232,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
178 input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone(); 232 input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone();
179 res.inner.insert(text.clone(), Binding::Simple(meta.into())); 233 res.inner.insert(text.clone(), Binding::Simple(meta.into()));
180 } 234 }
181 // FIXME:
182 // Enable followiing code when everything is fixed
183 // At least we can dogfood itself to not stackoverflow
184 //
185 "tt" => { 235 "tt" => {
186 let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); 236 let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone();
187 res.inner.insert(text.clone(), Binding::Simple(token.into())); 237 res.inner.insert(text.clone(), Binding::Simple(token.into()));
@@ -206,8 +256,13 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
206 ); 256 );
207 } 257 }
208 "vis" => { 258 "vis" => {
209 let vis = input.eat_vis().ok_or(ExpandError::UnexpectedToken)?.clone(); 259 // `vis` is optional
210 res.inner.insert(text.clone(), Binding::Simple(vis.into())); 260 if let Some(vis) = input.try_eat_vis() {
261 let vis = vis.clone();
262 res.inner.insert(text.clone(), Binding::Simple(vis.into()));
263 } else {
264 res.push_optional(&text);
265 }
211 } 266 }
212 267
213 _ => return Err(ExpandError::UnexpectedToken), 268 _ => return Err(ExpandError::UnexpectedToken),
@@ -236,7 +291,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
236 loop { 291 loop {
237 match match_lhs(subtree, input) { 292 match match_lhs(subtree, input) {
238 Ok(nested) => { 293 Ok(nested) => {
239 counter += 1;
240 limit -= 1; 294 limit -= 1;
241 if limit == 0 { 295 if limit == 0 {
242 log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator); 296 log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator);
@@ -244,7 +298,8 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
244 } 298 }
245 299
246 memento = input.save(); 300 memento = input.save();
247 res.push_nested(nested)?; 301 res.push_nested(counter, nested)?;
302 counter += 1;
248 if counter == 1 { 303 if counter == 1 {
249 if let crate::RepeatKind::ZeroOrOne = kind { 304 if let crate::RepeatKind::ZeroOrOne = kind {
250 break; 305 break;
@@ -252,20 +307,9 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
252 } 307 }
253 308
254 if let Some(separator) = separator { 309 if let Some(separator) = separator {
255 use crate::Separator::*;
256
257 if !input 310 if !input
258 .eat_seperator() 311 .eat_seperator()
259 .map(|sep| match (sep, separator) { 312 .map(|sep| sep == *separator)
260 (Ident(ref a), Ident(ref b)) => a.text == b.text,
261 (Literal(ref a), Literal(ref b)) => a.text == b.text,
262 (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => {
263 let a_iter = a.iter().map(|a| a.char);
264 let b_iter = b.iter().map(|b| b.char);
265 a_iter.eq(b_iter)
266 }
267 _ => false,
268 })
269 .unwrap_or(false) 313 .unwrap_or(false)
270 { 314 {
271 input.rollback(memento); 315 input.rollback(memento);
@@ -284,6 +328,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
284 crate::RepeatKind::OneOrMore if counter == 0 => { 328 crate::RepeatKind::OneOrMore if counter == 0 => {
285 return Err(ExpandError::UnexpectedToken); 329 return Err(ExpandError::UnexpectedToken);
286 } 330 }
331 _ if counter == 0 => {
332 // Collect all empty variables in subtrees
333 collect_vars(subtree).iter().for_each(|s| res.push_empty(s));
334 }
287 _ => {} 335 _ => {}
288 } 336 }
289 } 337 }
@@ -322,6 +370,14 @@ fn expand_subtree(
322 .token_trees 370 .token_trees
323 .iter() 371 .iter()
324 .map(|it| expand_tt(it, ctx)) 372 .map(|it| expand_tt(it, ctx))
373 .filter(|it| {
374 // Filter empty subtree
375 if let Ok(tt::TokenTree::Subtree(subtree)) = it {
376 subtree.delimiter != tt::Delimiter::None || !subtree.token_trees.is_empty()
377 } else {
378 true
379 }
380 })
325 .collect::<Result<Vec<_>, ExpandError>>()?; 381 .collect::<Result<Vec<_>, ExpandError>>()?;
326 382
327 Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) 383 Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
@@ -356,14 +412,23 @@ fn expand_tt(
356 let mut has_seps = 0; 412 let mut has_seps = 0;
357 let mut counter = 0; 413 let mut counter = 0;
358 414
415 // We store the old var expanded value, and restore it later
416 // It is because before this `$repeat`,
417 // it is possible some variables already expanad in the same subtree
418 //
419 // `some_var_expanded` keep check if the deeper subtree has expanded variables
359 let mut some_var_expanded = false; 420 let mut some_var_expanded = false;
421 let old_var_expanded = ctx.var_expanded;
360 ctx.var_expanded = false; 422 ctx.var_expanded = false;
361 423
362 while let Ok(t) = expand_subtree(&repeat.subtree, ctx) { 424 while let Ok(t) = expand_subtree(&repeat.subtree, ctx) {
363 // if no var expaned in the child, we count it as a fail 425 // if no var expanded in the child, we count it as a fail
364 if !ctx.var_expanded { 426 if !ctx.var_expanded {
365 break; 427 break;
366 } 428 }
429
430 // Reset `ctx.var_expandeded` to see if there is other expanded variable
431 // in the next matching
367 some_var_expanded = true; 432 some_var_expanded = true;
368 ctx.var_expanded = false; 433 ctx.var_expanded = false;
369 434
@@ -407,7 +472,8 @@ fn expand_tt(
407 } 472 }
408 } 473 }
409 474
410 ctx.var_expanded = some_var_expanded; 475 // Restore the `var_expanded` by combining old one and the new one
476 ctx.var_expanded = some_var_expanded || old_var_expanded;
411 477
412 ctx.nesting.pop().unwrap(); 478 ctx.nesting.pop().unwrap();
413 for _ in 0..has_seps { 479 for _ in 0..has_seps {
@@ -433,6 +499,33 @@ fn expand_tt(
433 // FIXME: Properly handle $crate token 499 // FIXME: Properly handle $crate token
434 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) 500 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
435 .into() 501 .into()
502 } else if !ctx.bindings.contains(&v.text) {
503 // Note that it is possible to have a `$var` inside a macro which is not bound.
504 // For example:
505 // ```
506 // macro_rules! foo {
507 // ($a:ident, $b:ident, $c:tt) => {
508 // macro_rules! bar {
509 // ($bi:ident) => {
510 // fn $bi() -> u8 {$c}
511 // }
512 // }
513 // }
514 // ```
515 // We just treat it a normal tokens
516 tt::Subtree {
517 delimiter: tt::Delimiter::None,
518 token_trees: vec![
519 tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone })
520 .into(),
521 tt::Leaf::from(tt::Ident {
522 text: v.text.clone(),
523 id: TokenId::unspecified(),
524 })
525 .into(),
526 ],
527 }
528 .into()
436 } else { 529 } else {
437 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); 530 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
438 ctx.var_expanded = true; 531 ctx.var_expanded = true;
@@ -459,11 +552,12 @@ mod tests {
459 552
460 #[test] 553 #[test]
461 fn test_expand_rule() { 554 fn test_expand_rule() {
462 assert_err( 555 // FIXME: The missing $var check should be in parsing phase
463 "($i:ident) => ($j)", 556 // assert_err(
464 "foo!{a}", 557 // "($i:ident) => ($j)",
465 ExpandError::BindingError(String::from("could not find binding `j`")), 558 // "foo!{a}",
466 ); 559 // ExpandError::BindingError(String::from("could not find binding `j`")),
560 // );
467 561
468 assert_err( 562 assert_err(
469 "($($i:ident);*) => ($i)", 563 "($($i:ident);*) => ($i)",