diff options
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 82 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 5 |
2 files changed, 35 insertions, 52 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 08b0519d2..78df96880 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -81,21 +81,26 @@ struct Bindings { | |||
81 | 81 | ||
82 | #[derive(Debug)] | 82 | #[derive(Debug)] |
83 | enum Binding { | 83 | enum Binding { |
84 | Simple(tt::TokenTree), | 84 | Fragment(Fragment), |
85 | Nested(Vec<Binding>), | 85 | Nested(Vec<Binding>), |
86 | Empty, | 86 | Empty, |
87 | } | 87 | } |
88 | 88 | ||
89 | #[derive(Debug, Clone)] | ||
90 | enum Fragment { | ||
91 | /// token fragments are just copy-pasted into the output | ||
92 | Tokens(tt::TokenTree), | ||
93 | /// Ast fragments are inserted with fake delimiters, so as to make things | ||
94 | /// like `$i * 2` where `$i = 1 + 1` work as expectd. | ||
95 | Ast(tt::TokenTree), | ||
96 | } | ||
97 | |||
89 | impl Bindings { | 98 | impl Bindings { |
90 | fn push_optional(&mut self, name: &SmolStr) { | 99 | fn push_optional(&mut self, name: &SmolStr) { |
91 | // FIXME: Do we have a better way to represent an empty token ? | 100 | // FIXME: Do we have a better way to represent an empty token ? |
92 | // Insert an empty subtree for empty token | 101 | // Insert an empty subtree for empty token |
93 | self.inner.insert( | 102 | let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(); |
94 | name.clone(), | 103 | self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); |
95 | Binding::Simple( | ||
96 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(), | ||
97 | ), | ||
98 | ); | ||
99 | } | 104 | } |
100 | 105 | ||
101 | fn push_empty(&mut self, name: &SmolStr) { | 106 | fn push_empty(&mut self, name: &SmolStr) { |
@@ -106,13 +111,13 @@ impl Bindings { | |||
106 | self.inner.contains_key(name) | 111 | self.inner.contains_key(name) |
107 | } | 112 | } |
108 | 113 | ||
109 | fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> { | 114 | fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&Fragment, ExpandError> { |
110 | let mut b = self.inner.get(name).ok_or_else(|| { | 115 | let mut b = self.inner.get(name).ok_or_else(|| { |
111 | ExpandError::BindingError(format!("could not find binding `{}`", name)) | 116 | ExpandError::BindingError(format!("could not find binding `{}`", name)) |
112 | })?; | 117 | })?; |
113 | for &idx in nesting.iter() { | 118 | for &idx in nesting.iter() { |
114 | b = match b { | 119 | b = match b { |
115 | Binding::Simple(_) => break, | 120 | Binding::Fragment(_) => break, |
116 | Binding::Nested(bs) => bs.get(idx).ok_or_else(|| { | 121 | Binding::Nested(bs) => bs.get(idx).ok_or_else(|| { |
117 | ExpandError::BindingError(format!("could not find nested binding `{}`", name)) | 122 | ExpandError::BindingError(format!("could not find nested binding `{}`", name)) |
118 | })?, | 123 | })?, |
@@ -125,7 +130,7 @@ impl Bindings { | |||
125 | }; | 130 | }; |
126 | } | 131 | } |
127 | match b { | 132 | match b { |
128 | Binding::Simple(it) => Ok(it), | 133 | Binding::Fragment(it) => Ok(it), |
129 | Binding::Nested(_) => Err(ExpandError::BindingError(format!( | 134 | Binding::Nested(_) => Err(ExpandError::BindingError(format!( |
130 | "expected simple binding, found nested binding `{}`", | 135 | "expected simple binding, found nested binding `{}`", |
131 | name | 136 | name |
@@ -195,8 +200,8 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
195 | crate::Leaf::Var(crate::Var { text, kind }) => { | 200 | crate::Leaf::Var(crate::Var { text, kind }) => { |
196 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; | 201 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; |
197 | match match_meta_var(kind.as_str(), input)? { | 202 | match match_meta_var(kind.as_str(), input)? { |
198 | Some(tt) => { | 203 | Some(fragment) => { |
199 | res.inner.insert(text.clone(), Binding::Simple(tt)); | 204 | res.inner.insert(text.clone(), Binding::Fragment(fragment)); |
200 | } | 205 | } |
201 | None => res.push_optional(text), | 206 | None => res.push_optional(text), |
202 | } | 207 | } |
@@ -292,7 +297,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
292 | Ok(res) | 297 | Ok(res) |
293 | } | 298 | } |
294 | 299 | ||
295 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTree>, ExpandError> { | 300 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, ExpandError> { |
296 | let fragment = match kind { | 301 | let fragment = match kind { |
297 | "path" => Path, | 302 | "path" => Path, |
298 | "expr" => Expr, | 303 | "expr" => Expr, |
@@ -303,7 +308,7 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTr | |||
303 | "meta" => MetaItem, | 308 | "meta" => MetaItem, |
304 | "item" => Item, | 309 | "item" => Item, |
305 | _ => { | 310 | _ => { |
306 | let binding = match kind { | 311 | let tt = match kind { |
307 | "ident" => { | 312 | "ident" => { |
308 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); | 313 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); |
309 | tt::Leaf::from(ident).into() | 314 | tt::Leaf::from(ident).into() |
@@ -321,11 +326,12 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTr | |||
321 | }, | 326 | }, |
322 | _ => return Err(ExpandError::UnexpectedToken), | 327 | _ => return Err(ExpandError::UnexpectedToken), |
323 | }; | 328 | }; |
324 | return Ok(Some(binding)); | 329 | return Ok(Some(Fragment::Tokens(tt))); |
325 | } | 330 | } |
326 | }; | 331 | }; |
327 | let binding = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; | 332 | let tt = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; |
328 | Ok(Some(binding)) | 333 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; |
334 | Ok(Some(fragment)) | ||
329 | } | 335 | } |
330 | 336 | ||
331 | #[derive(Debug)] | 337 | #[derive(Debug)] |
@@ -342,30 +348,13 @@ fn expand_subtree( | |||
342 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 348 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
343 | for tt in template.token_trees.iter() { | 349 | for tt in template.token_trees.iter() { |
344 | let tt = expand_tt(tt, ctx)?; | 350 | let tt = expand_tt(tt, ctx)?; |
345 | push_tt(&mut buf, tt); | 351 | push_fragment(&mut buf, tt); |
346 | } | 352 | } |
347 | 353 | ||
348 | Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf }) | 354 | Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf }) |
349 | } | 355 | } |
350 | 356 | ||
351 | /// Reduce single token subtree to single token | 357 | fn expand_tt(template: &crate::TokenTree, ctx: &mut ExpandCtx) -> Result<Fragment, ExpandError> { |
352 | /// In `tt` matcher case, all tt tokens will be braced by a Delimiter::None | ||
353 | /// which makes all sort of problems. | ||
354 | fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree { | ||
355 | if subtree.delimiter != tt::Delimiter::None || subtree.token_trees.len() != 1 { | ||
356 | return subtree.into(); | ||
357 | } | ||
358 | |||
359 | match subtree.token_trees.pop().unwrap() { | ||
360 | tt::TokenTree::Subtree(subtree) => reduce_single_token(subtree), | ||
361 | tt::TokenTree::Leaf(token) => token.into(), | ||
362 | } | ||
363 | } | ||
364 | |||
365 | fn expand_tt( | ||
366 | template: &crate::TokenTree, | ||
367 | ctx: &mut ExpandCtx, | ||
368 | ) -> Result<tt::TokenTree, ExpandError> { | ||
369 | let res: tt::TokenTree = match template { | 358 | let res: tt::TokenTree = match template { |
370 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), | 359 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), |
371 | crate::TokenTree::Repeat(repeat) => { | 360 | crate::TokenTree::Repeat(repeat) => { |
@@ -451,7 +440,7 @@ fn expand_tt( | |||
451 | 440 | ||
452 | // Check if it is a single token subtree without any delimiter | 441 | // Check if it is a single token subtree without any delimiter |
453 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | 442 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} |
454 | reduce_single_token(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }) | 443 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into() |
455 | } | 444 | } |
456 | crate::TokenTree::Leaf(leaf) => match leaf { | 445 | crate::TokenTree::Leaf(leaf) => match leaf { |
457 | crate::Leaf::Ident(ident) => { | 446 | crate::Leaf::Ident(ident) => { |
@@ -492,20 +481,15 @@ fn expand_tt( | |||
492 | } | 481 | } |
493 | .into() | 482 | .into() |
494 | } else { | 483 | } else { |
495 | let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); | 484 | let fragment = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); |
496 | ctx.var_expanded = true; | 485 | ctx.var_expanded = true; |
497 | 486 | return Ok(fragment); | |
498 | if let tt::TokenTree::Subtree(subtree) = tkn { | ||
499 | reduce_single_token(subtree) | ||
500 | } else { | ||
501 | tkn | ||
502 | } | ||
503 | } | 487 | } |
504 | } | 488 | } |
505 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), | 489 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), |
506 | }, | 490 | }, |
507 | }; | 491 | }; |
508 | Ok(res) | 492 | Ok(Fragment::Tokens(res)) |
509 | } | 493 | } |
510 | 494 | ||
511 | #[cfg(test)] | 495 | #[cfg(test)] |
@@ -579,10 +563,10 @@ mod tests { | |||
579 | } | 563 | } |
580 | } | 564 | } |
581 | 565 | ||
582 | fn push_tt(buf: &mut Vec<tt::TokenTree>, tt: tt::TokenTree) { | 566 | fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { |
583 | match tt { | 567 | match fragment { |
584 | tt::TokenTree::Subtree(tt) => push_subtree(buf, tt), | 568 | Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt), |
585 | _ => buf.push(tt), | 569 | Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt), |
586 | } | 570 | } |
587 | } | 571 | } |
588 | 572 | ||
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 2b80c5f49..0f07e935d 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -657,7 +657,6 @@ fn test_expr() { | |||
657 | } | 657 | } |
658 | 658 | ||
659 | #[test] | 659 | #[test] |
660 | #[ignore] | ||
661 | fn test_expr_order() { | 660 | fn test_expr_order() { |
662 | let rules = create_rules( | 661 | let rules = create_rules( |
663 | r#" | 662 | r#" |
@@ -668,9 +667,9 @@ fn test_expr_order() { | |||
668 | } | 667 | } |
669 | "#, | 668 | "#, |
670 | ); | 669 | ); |
671 | 670 | let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()); | |
672 | assert_eq_text!( | 671 | assert_eq_text!( |
673 | &format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()), | 672 | dump.trim(), |
674 | r#"MACRO_ITEMS@[0; 15) | 673 | r#"MACRO_ITEMS@[0; 15) |
675 | FN_DEF@[0; 15) | 674 | FN_DEF@[0; 15) |
676 | FN_KW@[0; 2) "fn" | 675 | FN_KW@[0; 2) "fn" |