aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-10 18:29:22 +0100
committerGitHub <[email protected]>2019-09-10 18:29:22 +0100
commit753a569c79c5a4a1dd7624028cc85fa9590da53d (patch)
treebda5c9cccae5835990e89ffbd5671dad8f248706
parent9d3c78e2eee6635772c99d7351b621cefb08bac5 (diff)
parent4fdaec99c0b97c56b67483b57fe2bcb89570d7c8 (diff)
Merge #1809
1809: add fragmets to expansion r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs82
-rw-r--r--crates/ra_mbe/src/tests.rs5
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)]
83enum Binding { 83enum 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)]
90enum 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
89impl Bindings { 98impl 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
295fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTree>, ExpandError> { 300fn 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 357fn 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.
354fn 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
365fn 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
582fn push_tt(buf: &mut Vec<tt::TokenTree>, tt: tt::TokenTree) { 566fn 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]
661fn test_expr_order() { 660fn 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"