aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src')
-rw-r--r--crates/ra_mbe/src/lib.rs4
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs118
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs36
-rw-r--r--crates/ra_mbe/src/tests.rs18
4 files changed, 74 insertions, 102 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 52c3d03b5..f07f000ff 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -41,8 +41,8 @@ pub enum ExpandError {
41} 41}
42 42
43pub use crate::syntax_bridge::{ 43pub use crate::syntax_bridge::{
44 ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_ast_item_list, token_tree_to_expr, 44 ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_expr, token_tree_to_items,
45 token_tree_to_macro_items, token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty, 45 token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty,
46}; 46};
47 47
48/// This struct contains AST for a single `macro_rules` definition. What might 48/// This struct contains AST for a single `macro_rules` definition. What might
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 01641fdee..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)]
@@ -339,45 +345,20 @@ fn expand_subtree(
339 template: &crate::Subtree, 345 template: &crate::Subtree,
340 ctx: &mut ExpandCtx, 346 ctx: &mut ExpandCtx,
341) -> Result<tt::Subtree, ExpandError> { 347) -> Result<tt::Subtree, ExpandError> {
342 let token_trees = template 348 let mut buf: Vec<tt::TokenTree> = Vec::new();
343 .token_trees 349 for tt in template.token_trees.iter() {
344 .iter() 350 let tt = expand_tt(tt, ctx)?;
345 .map(|it| expand_tt(it, ctx)) 351 push_fragment(&mut buf, tt);
346 .filter(|it| {
347 // Filter empty subtree
348 if let Ok(tt::TokenTree::Subtree(subtree)) = it {
349 subtree.delimiter != tt::Delimiter::None || !subtree.token_trees.is_empty()
350 } else {
351 true
352 }
353 })
354 .collect::<Result<Vec<_>, ExpandError>>()?;
355
356 Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
357}
358
359/// Reduce single token subtree to single token
360/// In `tt` matcher case, all tt tokens will be braced by a Delimiter::None
361/// which makes all sort of problems.
362fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree {
363 if subtree.delimiter != tt::Delimiter::None || subtree.token_trees.len() != 1 {
364 return subtree.into();
365 } 352 }
366 353
367 match subtree.token_trees.pop().unwrap() { 354 Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf })
368 tt::TokenTree::Subtree(subtree) => reduce_single_token(subtree),
369 tt::TokenTree::Leaf(token) => token.into(),
370 }
371} 355}
372 356
373fn expand_tt( 357fn expand_tt(template: &crate::TokenTree, ctx: &mut ExpandCtx) -> Result<Fragment, ExpandError> {
374 template: &crate::TokenTree,
375 ctx: &mut ExpandCtx,
376) -> Result<tt::TokenTree, ExpandError> {
377 let res: tt::TokenTree = match template { 358 let res: tt::TokenTree = match template {
378 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), 359 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(),
379 crate::TokenTree::Repeat(repeat) => { 360 crate::TokenTree::Repeat(repeat) => {
380 let mut token_trees: Vec<tt::TokenTree> = Vec::new(); 361 let mut buf: Vec<tt::TokenTree> = Vec::new();
381 ctx.nesting.push(0); 362 ctx.nesting.push(0);
382 // Dirty hack to make macro-expansion terminate. 363 // Dirty hack to make macro-expansion terminate.
383 // This should be replaced by a propper macro-by-example implementation 364 // This should be replaced by a propper macro-by-example implementation
@@ -418,23 +399,23 @@ fn expand_tt(
418 399
419 let idx = ctx.nesting.pop().unwrap(); 400 let idx = ctx.nesting.pop().unwrap();
420 ctx.nesting.push(idx + 1); 401 ctx.nesting.push(idx + 1);
421 token_trees.push(reduce_single_token(t)); 402 push_subtree(&mut buf, t);
422 403
423 if let Some(ref sep) = repeat.separator { 404 if let Some(ref sep) = repeat.separator {
424 match sep { 405 match sep {
425 crate::Separator::Ident(ident) => { 406 crate::Separator::Ident(ident) => {
426 has_seps = 1; 407 has_seps = 1;
427 token_trees.push(tt::Leaf::from(ident.clone()).into()); 408 buf.push(tt::Leaf::from(ident.clone()).into());
428 } 409 }
429 crate::Separator::Literal(lit) => { 410 crate::Separator::Literal(lit) => {
430 has_seps = 1; 411 has_seps = 1;
431 token_trees.push(tt::Leaf::from(lit.clone()).into()); 412 buf.push(tt::Leaf::from(lit.clone()).into());
432 } 413 }
433 414
434 crate::Separator::Puncts(puncts) => { 415 crate::Separator::Puncts(puncts) => {
435 has_seps = puncts.len(); 416 has_seps = puncts.len();
436 for punct in puncts { 417 for punct in puncts {
437 token_trees.push(tt::Leaf::from(*punct).into()); 418 buf.push(tt::Leaf::from(*punct).into());
438 } 419 }
439 } 420 }
440 } 421 }
@@ -450,16 +431,16 @@ fn expand_tt(
450 431
451 ctx.nesting.pop().unwrap(); 432 ctx.nesting.pop().unwrap();
452 for _ in 0..has_seps { 433 for _ in 0..has_seps {
453 token_trees.pop(); 434 buf.pop();
454 } 435 }
455 436
456 if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 { 437 if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 {
457 return Err(ExpandError::UnexpectedToken); 438 return Err(ExpandError::UnexpectedToken);
458 } 439 }
459 440
460 // Check if it is a singel token subtree without any delimiter 441 // Check if it is a single token subtree without any delimiter
461 // e.g {Delimiter:None> ['>'] /Delimiter:None>} 442 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
462 reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) 443 tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into()
463 } 444 }
464 crate::TokenTree::Leaf(leaf) => match leaf { 445 crate::TokenTree::Leaf(leaf) => match leaf {
465 crate::Leaf::Ident(ident) => { 446 crate::Leaf::Ident(ident) => {
@@ -500,20 +481,15 @@ fn expand_tt(
500 } 481 }
501 .into() 482 .into()
502 } else { 483 } else {
503 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); 484 let fragment = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
504 ctx.var_expanded = true; 485 ctx.var_expanded = true;
505 486 return Ok(fragment);
506 if let tt::TokenTree::Subtree(subtree) = tkn {
507 reduce_single_token(subtree)
508 } else {
509 tkn
510 }
511 } 487 }
512 } 488 }
513 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(),
514 }, 490 },
515 }; 491 };
516 Ok(res) 492 Ok(Fragment::Tokens(res))
517} 493}
518 494
519#[cfg(test)] 495#[cfg(test)]
@@ -586,3 +562,17 @@ mod tests {
586 expand_rule(&rules.rules[0], &invocation_tt) 562 expand_rule(&rules.rules[0], &invocation_tt)
587 } 563 }
588} 564}
565
566fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
567 match fragment {
568 Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
569 Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt),
570 }
571}
572
573fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
574 match tt.delimiter {
575 tt::Delimiter::None => buf.extend(tt.token_trees),
576 _ => buf.push(tt.into()),
577 }
578}
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index a380b1cfd..2d035307b 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -46,31 +46,19 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke
46// * TraitItems(SmallVec<[ast::TraitItem; 1]>) 46// * TraitItems(SmallVec<[ast::TraitItem; 1]>)
47// * ImplItems(SmallVec<[ast::ImplItem; 1]>) 47// * ImplItems(SmallVec<[ast::ImplItem; 1]>)
48// * ForeignItems(SmallVec<[ast::ForeignItem; 1]> 48// * ForeignItems(SmallVec<[ast::ForeignItem; 1]>
49//
50//
51
52fn token_tree_to_syntax_node<F>(tt: &tt::Subtree, f: F) -> Result<Parse<SyntaxNode>, ExpandError>
53where
54 F: Fn(&mut dyn ra_parser::TokenSource, &mut dyn ra_parser::TreeSink),
55{
56 let tokens = [tt.clone().into()];
57 let buffer = TokenBuffer::new(&tokens);
58 let mut token_source = SubtreeTokenSource::new(&buffer);
59 let mut tree_sink = TtTreeSink::new(buffer.begin());
60 f(&mut token_source, &mut tree_sink);
61 if tree_sink.roots.len() != 1 {
62 return Err(ExpandError::ConversionError);
63 }
64 //FIXME: would be cool to report errors
65 let parse = tree_sink.inner.finish();
66 Ok(parse)
67}
68 49
69fn fragment_to_syntax_node( 50fn fragment_to_syntax_node(
70 tt: &tt::Subtree, 51 tt: &tt::Subtree,
71 fragment_kind: FragmentKind, 52 fragment_kind: FragmentKind,
72) -> Result<Parse<SyntaxNode>, ExpandError> { 53) -> Result<Parse<SyntaxNode>, ExpandError> {
73 let tokens = [tt.clone().into()]; 54 let tmp;
55 let tokens = match tt {
56 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(),
57 _ => {
58 tmp = [tt.clone().into()];
59 &tmp[..]
60 }
61 };
74 let buffer = TokenBuffer::new(&tokens); 62 let buffer = TokenBuffer::new(&tokens);
75 let mut token_source = SubtreeTokenSource::new(&buffer); 63 let mut token_source = SubtreeTokenSource::new(&buffer);
76 let mut tree_sink = TtTreeSink::new(buffer.begin()); 64 let mut tree_sink = TtTreeSink::new(buffer.begin());
@@ -108,17 +96,11 @@ pub fn token_tree_to_macro_stmts(tt: &tt::Subtree) -> Result<Parse<ast::MacroStm
108} 96}
109 97
110/// Parses the token tree (result of macro expansion) as a sequence of items 98/// Parses the token tree (result of macro expansion) as a sequence of items
111pub fn token_tree_to_macro_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> { 99pub fn token_tree_to_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> {
112 let parse = fragment_to_syntax_node(tt, Items)?; 100 let parse = fragment_to_syntax_node(tt, Items)?;
113 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) 101 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
114} 102}
115 103
116/// Parses the token tree (result of macro expansion) as a sequence of items
117pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> Parse<ast::SourceFile> {
118 let parse = token_tree_to_syntax_node(tt, ra_parser::parse).unwrap();
119 parse.cast().unwrap()
120}
121
122impl TokenMap { 104impl TokenMap {
123 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { 105 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> {
124 let idx = tt.0 as usize; 106 let idx = tt.0 as usize;
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 034ea639b..312fa4626 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,4 +1,5 @@
1use ra_syntax::{ast, AstNode, NodeOrToken}; 1use ra_syntax::{ast, AstNode, NodeOrToken};
2use test_utils::assert_eq_text;
2 3
3use super::*; 4use super::*;
4 5
@@ -69,7 +70,7 @@ pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
69 70
70pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems { 71pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems {
71 let expanded = expand(rules, invocation); 72 let expanded = expand(rules, invocation);
72 token_tree_to_macro_items(&expanded).unwrap().tree() 73 token_tree_to_items(&expanded).unwrap().tree()
73} 74}
74 75
75#[allow(unused)] 76#[allow(unused)]
@@ -152,11 +153,10 @@ pub(crate) fn assert_expansion(
152 153
153 // wrap the given text to a macro call 154 // wrap the given text to a macro call
154 let expected = text_to_tokentree(&expected); 155 let expected = text_to_tokentree(&expected);
155
156 let (expanded_tree, expected_tree) = match kind { 156 let (expanded_tree, expected_tree) = match kind {
157 MacroKind::Items => { 157 MacroKind::Items => {
158 let expanded_tree = token_tree_to_macro_items(&expanded).unwrap().tree(); 158 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree();
159 let expected_tree = token_tree_to_macro_items(&expected).unwrap().tree(); 159 let expected_tree = token_tree_to_items(&expected).unwrap().tree();
160 160
161 ( 161 (
162 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), 162 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
@@ -178,7 +178,7 @@ pub(crate) fn assert_expansion(
178 let expected_tree = expected_tree.replace("C_C__C", "$crate"); 178 let expected_tree = expected_tree.replace("C_C__C", "$crate");
179 assert_eq!( 179 assert_eq!(
180 expanded_tree, expected_tree, 180 expanded_tree, expected_tree,
181 "left => {}\nright => {}", 181 "\nleft:\n{}\nright:\n{}",
182 expanded_tree, expected_tree, 182 expanded_tree, expected_tree,
183 ); 183 );
184 184
@@ -410,7 +410,7 @@ fn test_expand_to_item_list() {
410 ", 410 ",
411 ); 411 );
412 let expansion = expand(&rules, "structs!(Foo, Bar);"); 412 let expansion = expand(&rules, "structs!(Foo, Bar);");
413 let tree = token_tree_to_macro_items(&expansion).unwrap().tree(); 413 let tree = token_tree_to_items(&expansion).unwrap().tree();
414 assert_eq!( 414 assert_eq!(
415 format!("{:#?}", tree.syntax()).trim(), 415 format!("{:#?}", tree.syntax()).trim(),
416 r#" 416 r#"
@@ -667,9 +667,9 @@ fn test_expr_order() {
667 } 667 }
668"#, 668"#,
669 ); 669 );
670 670 let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax());
671 assert_eq!( 671 assert_eq_text!(
672 format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()).trim(), 672 dump.trim(),
673 r#"MACRO_ITEMS@[0; 15) 673 r#"MACRO_ITEMS@[0; 15)
674 FN_DEF@[0; 15) 674 FN_DEF@[0; 15)
675 FN_KW@[0; 2) "fn" 675 FN_KW@[0; 2) "fn"