diff options
author | Aleksey Kladov <[email protected]> | 2019-01-31 18:29:04 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-31 20:23:30 +0000 |
commit | 2d1f0b105d7995088fdf7a90e5e594b5555699c6 (patch) | |
tree | 2c70b7671381c0ec42190303bbf6865a638ed39c | |
parent | 40feacdeb90786b49ea9e0510ba22ff7af79e020 (diff) |
move test
-rw-r--r-- | Cargo.lock | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/macros.rs | 114 | ||||
-rw-r--r-- | crates/ra_mbe/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 9 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 2 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 113 | ||||
-rw-r--r-- | crates/ra_tt/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_tt/src/lib.rs | 4 |
8 files changed, 129 insertions, 120 deletions
diff --git a/Cargo.lock b/Cargo.lock index 426f4af27..49a9da624 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1023,9 +1023,9 @@ dependencies = [ | |||
1023 | name = "ra_mbe" | 1023 | name = "ra_mbe" |
1024 | version = "0.1.0" | 1024 | version = "0.1.0" |
1025 | dependencies = [ | 1025 | dependencies = [ |
1026 | "ra_syntax 0.1.0", | ||
1026 | "ra_tt 0.1.0", | 1027 | "ra_tt 0.1.0", |
1027 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1028 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1028 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||
1029 | ] | 1029 | ] |
1030 | 1030 | ||
1031 | [[package]] | 1031 | [[package]] |
@@ -1058,7 +1058,6 @@ dependencies = [ | |||
1058 | name = "ra_tt" | 1058 | name = "ra_tt" |
1059 | version = "0.1.0" | 1059 | version = "0.1.0" |
1060 | dependencies = [ | 1060 | dependencies = [ |
1061 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||
1062 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | 1061 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", |
1063 | ] | 1062 | ] |
1064 | 1063 | ||
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs index ffcf1c3f9..7ca34d434 100644 --- a/crates/ra_hir/src/macros.rs +++ b/crates/ra_hir/src/macros.rs | |||
@@ -11,7 +11,6 @@ use std::sync::Arc; | |||
11 | 11 | ||
12 | use ra_syntax::{ | 12 | use ra_syntax::{ |
13 | TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr, | 13 | TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr, |
14 | SyntaxKind::*, | ||
15 | ast::{self, NameOwner}, | 14 | ast::{self, NameOwner}, |
16 | }; | 15 | }; |
17 | 16 | ||
@@ -196,116 +195,3 @@ pub(crate) fn expand_macro_invocation( | |||
196 | let (def, input) = MacroDef::from_call(macro_call)?; | 195 | let (def, input) = MacroDef::from_call(macro_call)?; |
197 | def.expand(input).map(Arc::new) | 196 | def.expand(input).map(Arc::new) |
198 | } | 197 | } |
199 | |||
200 | fn macro_call_to_tt(call: &ast::MacroCall) -> Option<tt::Subtree> { | ||
201 | let tt = call.token_tree()?; | ||
202 | convert_tt(tt.syntax()) | ||
203 | } | ||
204 | |||
205 | fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> { | ||
206 | let first_child = tt.first_child()?; | ||
207 | let last_child = tt.last_child()?; | ||
208 | let delimiter = match (first_child.kind(), last_child.kind()) { | ||
209 | (L_PAREN, R_PAREN) => tt::Delimiter::Parenthesis, | ||
210 | (L_CURLY, R_CURLY) => tt::Delimiter::Brace, | ||
211 | (L_BRACK, R_BRACK) => tt::Delimiter::Bracket, | ||
212 | _ => return None, | ||
213 | }; | ||
214 | let mut token_trees = Vec::new(); | ||
215 | for child in tt.children().skip(1) { | ||
216 | if child == first_child || child == last_child || child.kind().is_trivia() { | ||
217 | continue; | ||
218 | } | ||
219 | if child.kind().is_punct() { | ||
220 | let mut prev = None; | ||
221 | for char in child.leaf_text().unwrap().chars() { | ||
222 | if let Some(char) = prev { | ||
223 | token_trees.push( | ||
224 | tt::Leaf::from(tt::Punct { | ||
225 | char, | ||
226 | spacing: tt::Spacing::Joint, | ||
227 | }) | ||
228 | .into(), | ||
229 | ); | ||
230 | } | ||
231 | prev = Some(char) | ||
232 | } | ||
233 | if let Some(char) = prev { | ||
234 | token_trees.push( | ||
235 | tt::Leaf::from(tt::Punct { | ||
236 | char, | ||
237 | spacing: tt::Spacing::Alone, | ||
238 | }) | ||
239 | .into(), | ||
240 | ); | ||
241 | } | ||
242 | } else { | ||
243 | let child: tt::TokenTree = if child.kind() == TOKEN_TREE { | ||
244 | convert_tt(child)?.into() | ||
245 | } else if child.kind().is_keyword() || child.kind() == IDENT { | ||
246 | let text = child.leaf_text().unwrap().clone(); | ||
247 | tt::Leaf::from(tt::Ident { text }).into() | ||
248 | } else if child.kind().is_literal() { | ||
249 | tt::Leaf::from(tt::Literal { | ||
250 | text: child.leaf_text().unwrap().clone(), | ||
251 | }) | ||
252 | .into() | ||
253 | } else { | ||
254 | log::error!("unknown kind: {:?}", child); | ||
255 | return None; | ||
256 | }; | ||
257 | token_trees.push(child) | ||
258 | } | ||
259 | } | ||
260 | |||
261 | let res = tt::Subtree { | ||
262 | delimiter, | ||
263 | token_trees, | ||
264 | }; | ||
265 | Some(res) | ||
266 | } | ||
267 | |||
268 | #[test] | ||
269 | fn test_convert_tt() { | ||
270 | let macro_definition = r#" | ||
271 | macro_rules! impl_froms { | ||
272 | ($e:ident: $($v:ident),*) => { | ||
273 | $( | ||
274 | impl From<$v> for $e { | ||
275 | fn from(it: $v) -> $e { | ||
276 | $e::$v(it) | ||
277 | } | ||
278 | } | ||
279 | )* | ||
280 | } | ||
281 | } | ||
282 | "#; | ||
283 | |||
284 | let macro_invocation = r#" | ||
285 | impl_froms!(TokenTree: Leaf, Subtree); | ||
286 | "#; | ||
287 | |||
288 | let source_file = ast::SourceFile::parse(macro_definition); | ||
289 | let macro_definition = source_file | ||
290 | .syntax() | ||
291 | .descendants() | ||
292 | .find_map(ast::MacroCall::cast) | ||
293 | .unwrap(); | ||
294 | |||
295 | let source_file = ast::SourceFile::parse(macro_invocation); | ||
296 | let macro_invocation = source_file | ||
297 | .syntax() | ||
298 | .descendants() | ||
299 | .find_map(ast::MacroCall::cast) | ||
300 | .unwrap(); | ||
301 | |||
302 | let definition_tt = macro_call_to_tt(macro_definition).unwrap(); | ||
303 | let invocation_tt = macro_call_to_tt(macro_invocation).unwrap(); | ||
304 | let mbe = mbe::parse(&definition_tt).unwrap(); | ||
305 | let expansion = mbe::exapnd(&mbe, &invocation_tt).unwrap(); | ||
306 | assert_eq!( | ||
307 | expansion.to_string(), | ||
308 | "{(impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}}) \ | ||
309 | (impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}})}" | ||
310 | ) | ||
311 | } | ||
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml index b7f03cd38..68dc85eb9 100644 --- a/crates/ra_mbe/Cargo.toml +++ b/crates/ra_mbe/Cargo.toml | |||
@@ -5,6 +5,7 @@ version = "0.1.0" | |||
5 | authors = ["Aleksey Kladov <[email protected]>"] | 5 | authors = ["Aleksey Kladov <[email protected]>"] |
6 | 6 | ||
7 | [dependencies] | 7 | [dependencies] |
8 | ra_syntax = { path = "../ra_syntax" } | ||
8 | tt = { path = "../ra_tt", package = "ra_tt" } | 9 | tt = { path = "../ra_tt", package = "ra_tt" } |
10 | |||
9 | rustc-hash = "1.0.0" | 11 | rustc-hash = "1.0.0" |
10 | smol_str = "0.1.9" | ||
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 38bf3431a..c7be33b19 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -1,3 +1,8 @@ | |||
1 | /// `mbe` (short for Macro By Example) crate contains code for handling | ||
2 | /// `macro_rules` macros. It uses `TokenTree` (from `ra_tt` package) as the | ||
3 | /// interface, although it contains some code to bridge `SyntaxNode`s and | ||
4 | /// `TokenTree`s as well! | ||
5 | |||
1 | macro_rules! impl_froms { | 6 | macro_rules! impl_froms { |
2 | ($e:ident: $($v:ident), *) => { | 7 | ($e:ident: $($v:ident), *) => { |
3 | $( | 8 | $( |
@@ -13,14 +18,16 @@ macro_rules! impl_froms { | |||
13 | mod tt_cursor; | 18 | mod tt_cursor; |
14 | mod mbe_parser; | 19 | mod mbe_parser; |
15 | mod mbe_expander; | 20 | mod mbe_expander; |
21 | mod syntax_bridge; | ||
16 | 22 | ||
17 | use smol_str::SmolStr; | 23 | use ra_syntax::SmolStr; |
18 | 24 | ||
19 | pub use tt::{Delimiter, Punct}; | 25 | pub use tt::{Delimiter, Punct}; |
20 | 26 | ||
21 | pub use crate::{ | 27 | pub use crate::{ |
22 | mbe_parser::parse, | 28 | mbe_parser::parse, |
23 | mbe_expander::exapnd, | 29 | mbe_expander::exapnd, |
30 | syntax_bridge::macro_call_to_tt, | ||
24 | }; | 31 | }; |
25 | 32 | ||
26 | #[derive(Debug)] | 33 | #[derive(Debug)] |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 92ad26889..21c1552ce 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use rustc_hash::FxHashMap; | 1 | use rustc_hash::FxHashMap; |
2 | use smol_str::SmolStr; | 2 | use ra_syntax::SmolStr; |
3 | 3 | ||
4 | use crate::{self as mbe, tt_cursor::TtCursor}; | 4 | use crate::{self as mbe, tt_cursor::TtCursor}; |
5 | 5 | ||
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs new file mode 100644 index 000000000..aad5f24b7 --- /dev/null +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -0,0 +1,113 @@ | |||
1 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxKind::*}; | ||
2 | |||
3 | pub fn macro_call_to_tt(call: &ast::MacroCall) -> Option<tt::Subtree> { | ||
4 | let tt = call.token_tree()?; | ||
5 | convert_tt(tt.syntax()) | ||
6 | } | ||
7 | |||
8 | fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> { | ||
9 | let first_child = tt.first_child()?; | ||
10 | let last_child = tt.last_child()?; | ||
11 | let delimiter = match (first_child.kind(), last_child.kind()) { | ||
12 | (L_PAREN, R_PAREN) => tt::Delimiter::Parenthesis, | ||
13 | (L_CURLY, R_CURLY) => tt::Delimiter::Brace, | ||
14 | (L_BRACK, R_BRACK) => tt::Delimiter::Bracket, | ||
15 | _ => return None, | ||
16 | }; | ||
17 | let mut token_trees = Vec::new(); | ||
18 | for child in tt.children().skip(1) { | ||
19 | if child == first_child || child == last_child || child.kind().is_trivia() { | ||
20 | continue; | ||
21 | } | ||
22 | if child.kind().is_punct() { | ||
23 | let mut prev = None; | ||
24 | for char in child.leaf_text().unwrap().chars() { | ||
25 | if let Some(char) = prev { | ||
26 | token_trees.push( | ||
27 | tt::Leaf::from(tt::Punct { | ||
28 | char, | ||
29 | spacing: tt::Spacing::Joint, | ||
30 | }) | ||
31 | .into(), | ||
32 | ); | ||
33 | } | ||
34 | prev = Some(char) | ||
35 | } | ||
36 | if let Some(char) = prev { | ||
37 | token_trees.push( | ||
38 | tt::Leaf::from(tt::Punct { | ||
39 | char, | ||
40 | spacing: tt::Spacing::Alone, | ||
41 | }) | ||
42 | .into(), | ||
43 | ); | ||
44 | } | ||
45 | } else { | ||
46 | let child: tt::TokenTree = if child.kind() == TOKEN_TREE { | ||
47 | convert_tt(child)?.into() | ||
48 | } else if child.kind().is_keyword() || child.kind() == IDENT { | ||
49 | let text = child.leaf_text().unwrap().clone(); | ||
50 | tt::Leaf::from(tt::Ident { text }).into() | ||
51 | } else if child.kind().is_literal() { | ||
52 | tt::Leaf::from(tt::Literal { | ||
53 | text: child.leaf_text().unwrap().clone(), | ||
54 | }) | ||
55 | .into() | ||
56 | } else { | ||
57 | return None; | ||
58 | }; | ||
59 | token_trees.push(child) | ||
60 | } | ||
61 | } | ||
62 | |||
63 | let res = tt::Subtree { | ||
64 | delimiter, | ||
65 | token_trees, | ||
66 | }; | ||
67 | Some(res) | ||
68 | } | ||
69 | |||
70 | #[test] | ||
71 | fn test_convert_tt() { | ||
72 | let macro_definition = r#" | ||
73 | macro_rules! impl_froms { | ||
74 | ($e:ident: $($v:ident),*) => { | ||
75 | $( | ||
76 | impl From<$v> for $e { | ||
77 | fn from(it: $v) -> $e { | ||
78 | $e::$v(it) | ||
79 | } | ||
80 | } | ||
81 | )* | ||
82 | } | ||
83 | } | ||
84 | "#; | ||
85 | |||
86 | let macro_invocation = r#" | ||
87 | impl_froms!(TokenTree: Leaf, Subtree); | ||
88 | "#; | ||
89 | |||
90 | let source_file = ast::SourceFile::parse(macro_definition); | ||
91 | let macro_definition = source_file | ||
92 | .syntax() | ||
93 | .descendants() | ||
94 | .find_map(ast::MacroCall::cast) | ||
95 | .unwrap(); | ||
96 | |||
97 | let source_file = ast::SourceFile::parse(macro_invocation); | ||
98 | let macro_invocation = source_file | ||
99 | .syntax() | ||
100 | .descendants() | ||
101 | .find_map(ast::MacroCall::cast) | ||
102 | .unwrap(); | ||
103 | |||
104 | let definition_tt = macro_call_to_tt(macro_definition).unwrap(); | ||
105 | let invocation_tt = macro_call_to_tt(macro_invocation).unwrap(); | ||
106 | let mbe = crate::parse(&definition_tt).unwrap(); | ||
107 | let expansion = crate::exapnd(&mbe, &invocation_tt).unwrap(); | ||
108 | assert_eq!( | ||
109 | expansion.to_string(), | ||
110 | "{(impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}}) \ | ||
111 | (impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}})}" | ||
112 | ) | ||
113 | } | ||
diff --git a/crates/ra_tt/Cargo.toml b/crates/ra_tt/Cargo.toml index 357a5c5a3..02accd404 100644 --- a/crates/ra_tt/Cargo.toml +++ b/crates/ra_tt/Cargo.toml | |||
@@ -5,5 +5,4 @@ version = "0.1.0" | |||
5 | authors = ["Aleksey Kladov <[email protected]>"] | 5 | authors = ["Aleksey Kladov <[email protected]>"] |
6 | 6 | ||
7 | [dependencies] | 7 | [dependencies] |
8 | rustc-hash = "1.0.0" | ||
9 | smol_str = "0.1.9" | 8 | smol_str = "0.1.9" |
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs index d7c3c62bf..043417abc 100644 --- a/crates/ra_tt/src/lib.rs +++ b/crates/ra_tt/src/lib.rs | |||
@@ -1,3 +1,7 @@ | |||
1 | /// `tt` crate defines a `TokenTree` datastructure: this is the interface (both | ||
2 | /// input and output) of macros. It closely mirrors `proc_macro` crate's | ||
3 | /// `TokenTree`. | ||
4 | |||
1 | macro_rules! impl_froms { | 5 | macro_rules! impl_froms { |
2 | ($e:ident: $($v:ident), *) => { | 6 | ($e:ident: $($v:ident), *) => { |
3 | $( | 7 | $( |