aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_mbe/src/tests.rs344
1 files changed, 159 insertions, 185 deletions
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index d7482c63d..f34ab52e1 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{ast, AstNode, NodeOrToken}; 1use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent};
2use test_utils::assert_eq_text; 2use test_utils::assert_eq_text;
3 3
4use super::*; 4use super::*;
@@ -78,18 +78,8 @@ macro_rules! impl_froms {
78impl_froms!(TokenTree: Leaf, Subtree); 78impl_froms!(TokenTree: Leaf, Subtree);
79"#; 79"#;
80 80
81 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); 81 let rules = create_rules(macro_definition);
82 let macro_definition = 82 let expansion = expand(&rules, macro_invocation);
83 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
84
85 let source_file = ast::SourceFile::parse(macro_invocation).ok().unwrap();
86 let macro_invocation =
87 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
88
89 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
90 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
91 let rules = crate::MacroRules::parse(&definition_tt).unwrap();
92 let expansion = rules.expand(&invocation_tt).unwrap();
93 assert_eq!( 83 assert_eq!(
94 expansion.to_string(), 84 expansion.to_string(),
95 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ 85 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
@@ -97,140 +87,48 @@ impl_froms!(TokenTree: Leaf, Subtree);
97 ) 87 )
98} 88}
99 89
100pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { 90#[test]
101 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); 91fn test_expr_order() {
102 let macro_definition = 92 let rules = create_rules(
103 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 93 r#"
104 94 macro_rules! foo {
105 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap(); 95 ($ i:expr) => {
106 crate::MacroRules::parse(&definition_tt).unwrap() 96 fn bar() { $ i * 2; }
107}
108
109pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
110 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
111 let macro_invocation =
112 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
113
114 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
115
116 rules.expand(&invocation_tt).unwrap()
117}
118
119pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems {
120 let expanded = expand(rules, invocation);
121 token_tree_to_items(&expanded).unwrap().tree()
122}
123
124#[allow(unused)]
125pub(crate) fn expand_to_stmts(rules: &MacroRules, invocation: &str) -> ast::MacroStmts {
126 let expanded = expand(rules, invocation);
127 token_tree_to_macro_stmts(&expanded).unwrap().tree()
128}
129
130pub(crate) fn expand_to_expr(rules: &MacroRules, invocation: &str) -> ast::Expr {
131 let expanded = expand(rules, invocation);
132 token_tree_to_expr(&expanded).unwrap().tree()
133}
134
135pub(crate) fn text_to_tokentree(text: &str) -> tt::Subtree {
136 // wrap the given text to a macro call
137 let wrapped = format!("wrap_macro!( {} )", text);
138 let wrapped = ast::SourceFile::parse(&wrapped);
139 let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
140 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
141 wrapped.delimiter = tt::Delimiter::None;
142
143 wrapped
144}
145
146pub(crate) enum MacroKind {
147 Items,
148 Stmts,
149}
150
151use ra_syntax::WalkEvent;
152
153pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
154 use std::fmt::Write;
155
156 let mut level = 0;
157 let mut buf = String::new();
158 macro_rules! indent {
159 () => {
160 for _ in 0..level {
161 buf.push_str(" ");
162 }
163 };
164 }
165
166 for event in node.preorder_with_tokens() {
167 match event {
168 WalkEvent::Enter(element) => {
169 match element {
170 NodeOrToken::Node(node) => {
171 indent!();
172 writeln!(buf, "{:?}", node.kind()).unwrap();
173 }
174 NodeOrToken::Token(token) => match token.kind() {
175 ra_syntax::SyntaxKind::WHITESPACE => {}
176 _ => {
177 indent!();
178 writeln!(buf, "{:?}", token.kind()).unwrap();
179 }
180 },
181 }
182 level += 1;
183 } 97 }
184 WalkEvent::Leave(_) => level -= 1,
185 } 98 }
186 } 99"#,
187
188 buf
189}
190
191pub(crate) fn assert_expansion(
192 kind: MacroKind,
193 rules: &MacroRules,
194 invocation: &str,
195 expected: &str,
196) -> tt::Subtree {
197 let expanded = expand(rules, invocation);
198 assert_eq!(expanded.to_string(), expected);
199
200 let expected = expected.replace("$crate", "C_C__C");
201
202 // wrap the given text to a macro call
203 let expected = text_to_tokentree(&expected);
204 let (expanded_tree, expected_tree) = match kind {
205 MacroKind::Items => {
206 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree();
207 let expected_tree = token_tree_to_items(&expected).unwrap().tree();
208
209 (
210 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
211 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
212 )
213 }
214
215 MacroKind::Stmts => {
216 let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree();
217 let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree();
218
219 (
220 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
221 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
222 )
223 }
224 };
225
226 let expected_tree = expected_tree.replace("C_C__C", "$crate");
227 assert_eq!(
228 expanded_tree, expected_tree,
229 "\nleft:\n{}\nright:\n{}",
230 expanded_tree, expected_tree,
231 ); 100 );
101 let expanded = expand(&rules, "foo! { 1 + 1}");
102 let tree = token_tree_to_items(&expanded).unwrap().tree();
232 103
233 expanded 104 let dump = format!("{:#?}", tree.syntax());
105 assert_eq_text!(
106 dump.trim(),
107 r#"MACRO_ITEMS@[0; 15)
108 FN_DEF@[0; 15)
109 FN_KW@[0; 2) "fn"
110 NAME@[2; 5)
111 IDENT@[2; 5) "bar"
112 PARAM_LIST@[5; 7)
113 L_PAREN@[5; 6) "("
114 R_PAREN@[6; 7) ")"
115 BLOCK_EXPR@[7; 15)
116 BLOCK@[7; 15)
117 L_CURLY@[7; 8) "{"
118 EXPR_STMT@[8; 14)
119 BIN_EXPR@[8; 13)
120 BIN_EXPR@[8; 11)
121 LITERAL@[8; 9)
122 INT_NUMBER@[8; 9) "1"
123 PLUS@[9; 10) "+"
124 LITERAL@[10; 11)
125 INT_NUMBER@[10; 11) "1"
126 STAR@[11; 12) "*"
127 LITERAL@[12; 13)
128 INT_NUMBER@[12; 13) "2"
129 SEMI@[13; 14) ";"
130 R_CURLY@[14; 15) "}""#,
131 );
234} 132}
235 133
236#[test] 134#[test]
@@ -705,47 +603,6 @@ fn test_expr() {
705} 603}
706 604
707#[test] 605#[test]
708fn test_expr_order() {
709 let rules = create_rules(
710 r#"
711 macro_rules! foo {
712 ($ i:expr) => {
713 fn bar() { $ i * 2; }
714 }
715 }
716"#,
717 );
718 let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax());
719 assert_eq_text!(
720 dump.trim(),
721 r#"MACRO_ITEMS@[0; 15)
722 FN_DEF@[0; 15)
723 FN_KW@[0; 2) "fn"
724 NAME@[2; 5)
725 IDENT@[2; 5) "bar"
726 PARAM_LIST@[5; 7)
727 L_PAREN@[5; 6) "("
728 R_PAREN@[6; 7) ")"
729 BLOCK_EXPR@[7; 15)
730 BLOCK@[7; 15)
731 L_CURLY@[7; 8) "{"
732 EXPR_STMT@[8; 14)
733 BIN_EXPR@[8; 13)
734 BIN_EXPR@[8; 11)
735 LITERAL@[8; 9)
736 INT_NUMBER@[8; 9) "1"
737 PLUS@[9; 10) "+"
738 LITERAL@[10; 11)
739 INT_NUMBER@[10; 11) "1"
740 STAR@[11; 12) "*"
741 LITERAL@[12; 13)
742 INT_NUMBER@[12; 13) "2"
743 SEMI@[13; 14) ";"
744 R_CURLY@[14; 15) "}""#,
745 );
746}
747
748#[test]
749fn test_last_expr() { 606fn test_last_expr() {
750 let rules = create_rules( 607 let rules = create_rules(
751 r#" 608 r#"
@@ -1061,8 +918,11 @@ fn test_vec() {
1061 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, 918 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
1062 ); 919 );
1063 920
921 let expansion = expand(&rules, r#"vec![1u32,2];"#);
922 let tree = token_tree_to_expr(&expansion).unwrap().tree();
923
1064 assert_eq!( 924 assert_eq!(
1065 format!("{:#?}", expand_to_expr(&rules, r#"vec![1u32,2];"#).syntax()).trim(), 925 format!("{:#?}", tree.syntax()).trim(),
1066 r#"BLOCK_EXPR@[0; 45) 926 r#"BLOCK_EXPR@[0; 45)
1067 BLOCK@[0; 45) 927 BLOCK@[0; 45)
1068 L_CURLY@[0; 1) "{" 928 L_CURLY@[0; 1) "{"
@@ -1502,3 +1362,117 @@ macro_rules! delegate_impl {
1502 1362
1503 assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}"); 1363 assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}");
1504} 1364}
1365
1366pub(crate) fn create_rules(macro_definition: &str) -> MacroRules {
1367 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
1368 let macro_definition =
1369 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1370
1371 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
1372 crate::MacroRules::parse(&definition_tt).unwrap()
1373}
1374
1375pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
1376 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
1377 let macro_invocation =
1378 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1379
1380 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
1381
1382 rules.expand(&invocation_tt).unwrap()
1383}
1384
1385pub(crate) enum MacroKind {
1386 Items,
1387 Stmts,
1388}
1389
1390pub(crate) fn assert_expansion(
1391 kind: MacroKind,
1392 rules: &MacroRules,
1393 invocation: &str,
1394 expected: &str,
1395) -> tt::Subtree {
1396 let expanded = expand(rules, invocation);
1397 assert_eq!(expanded.to_string(), expected);
1398
1399 let expected = expected.replace("$crate", "C_C__C");
1400
1401 // wrap the given text to a macro call
1402 let expected = {
1403 let wrapped = format!("wrap_macro!( {} )", expected);
1404 let wrapped = ast::SourceFile::parse(&wrapped);
1405 let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1406 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1407 wrapped.delimiter = tt::Delimiter::None;
1408 wrapped
1409 };
1410 let (expanded_tree, expected_tree) = match kind {
1411 MacroKind::Items => {
1412 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree();
1413 let expected_tree = token_tree_to_items(&expected).unwrap().tree();
1414
1415 (
1416 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
1417 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
1418 )
1419 }
1420
1421 MacroKind::Stmts => {
1422 let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree();
1423 let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree();
1424
1425 (
1426 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
1427 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
1428 )
1429 }
1430 };
1431
1432 let expected_tree = expected_tree.replace("C_C__C", "$crate");
1433 assert_eq!(
1434 expanded_tree, expected_tree,
1435 "\nleft:\n{}\nright:\n{}",
1436 expanded_tree, expected_tree,
1437 );
1438
1439 expanded
1440}
1441
1442pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
1443 use std::fmt::Write;
1444
1445 let mut level = 0;
1446 let mut buf = String::new();
1447 macro_rules! indent {
1448 () => {
1449 for _ in 0..level {
1450 buf.push_str(" ");
1451 }
1452 };
1453 }
1454
1455 for event in node.preorder_with_tokens() {
1456 match event {
1457 WalkEvent::Enter(element) => {
1458 match element {
1459 NodeOrToken::Node(node) => {
1460 indent!();
1461 writeln!(buf, "{:?}", node.kind()).unwrap();
1462 }
1463 NodeOrToken::Token(token) => match token.kind() {
1464 ra_syntax::SyntaxKind::WHITESPACE => {}
1465 _ => {
1466 indent!();
1467 writeln!(buf, "{:?}", token.kind()).unwrap();
1468 }
1469 },
1470 }
1471 level += 1;
1472 }
1473 WalkEvent::Leave(_) => level -= 1,
1474 }
1475 }
1476
1477 buf
1478}