diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/macros.rs | 31 | ||||
-rw-r--r-- | crates/ra_macros/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_macros/src/mbe.rs | 7 | ||||
-rw-r--r-- | crates/ra_macros/src/mbe_expander.rs | 145 | ||||
-rw-r--r-- | crates/ra_macros/src/mbe_parser.rs | 2 | ||||
-rw-r--r-- | crates/ra_macros/src/tt.rs | 67 | ||||
-rw-r--r-- | crates/ra_macros/src/tt_cursor.rs | 1 |
8 files changed, 215 insertions, 40 deletions
diff --git a/Cargo.lock b/Cargo.lock index b48721622..a9bc80c40 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1022,6 +1022,7 @@ dependencies = [ | |||
1022 | name = "ra_macros" | 1022 | name = "ra_macros" |
1023 | version = "0.1.0" | 1023 | version = "0.1.0" |
1024 | dependencies = [ | 1024 | dependencies = [ |
1025 | "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||
1025 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1026 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1026 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | 1027 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", |
1027 | ] | 1028 | ] |
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs index 7e9aba3f2..059543bf2 100644 --- a/crates/ra_hir/src/macros.rs +++ b/crates/ra_hir/src/macros.rs | |||
@@ -254,7 +254,7 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> { | |||
254 | 254 | ||
255 | #[test] | 255 | #[test] |
256 | fn test_convert_tt() { | 256 | fn test_convert_tt() { |
257 | let text = r#" | 257 | let macro_defenition = r#" |
258 | macro_rules! impl_froms { | 258 | macro_rules! impl_froms { |
259 | ($e:ident: $($v:ident),*) => { | 259 | ($e:ident: $($v:ident),*) => { |
260 | $( | 260 | $( |
@@ -267,13 +267,32 @@ macro_rules! impl_froms { | |||
267 | } | 267 | } |
268 | } | 268 | } |
269 | "#; | 269 | "#; |
270 | let source_file = ast::SourceFile::parse(text); | 270 | |
271 | let maco_call = source_file | 271 | let macro_invocation = r#" |
272 | impl_froms!(TokenTree: Leaf, Subtree); | ||
273 | "#; | ||
274 | |||
275 | let source_file = ast::SourceFile::parse(macro_defenition); | ||
276 | let macro_defenition = source_file | ||
272 | .syntax() | 277 | .syntax() |
273 | .descendants() | 278 | .descendants() |
274 | .find_map(ast::MacroCall::cast) | 279 | .find_map(ast::MacroCall::cast) |
275 | .unwrap(); | 280 | .unwrap(); |
276 | let tt = macro_call_to_tt(maco_call).unwrap(); | 281 | |
277 | let tt = mbe::parse(&tt); | 282 | let source_file = ast::SourceFile::parse(macro_invocation); |
278 | assert!(tt.is_some()); | 283 | let macro_invocation = source_file |
284 | .syntax() | ||
285 | .descendants() | ||
286 | .find_map(ast::MacroCall::cast) | ||
287 | .unwrap(); | ||
288 | |||
289 | let defenition_tt = macro_call_to_tt(macro_defenition).unwrap(); | ||
290 | let invocation_tt = macro_call_to_tt(macro_invocation).unwrap(); | ||
291 | let mbe = mbe::parse(&defenition_tt).unwrap(); | ||
292 | let expansion = mbe::exapnd(&mbe, &invocation_tt).unwrap(); | ||
293 | assert_eq!( | ||
294 | expansion.to_string(), | ||
295 | "{(impl From < Leaf > for TokenTree {fn from (it : Leaf) - > TokenTree {TokenTree : : Leaf (it)}}) \ | ||
296 | (impl From < Subtree > for TokenTree {fn from (it : Subtree) - > TokenTree {TokenTree : : Subtree (it)}})}" | ||
297 | ) | ||
279 | } | 298 | } |
diff --git a/crates/ra_macros/Cargo.toml b/crates/ra_macros/Cargo.toml index 7d3cb055c..1c9cc9e92 100644 --- a/crates/ra_macros/Cargo.toml +++ b/crates/ra_macros/Cargo.toml | |||
@@ -7,3 +7,4 @@ authors = ["Aleksey Kladov <[email protected]>"] | |||
7 | [dependencies] | 7 | [dependencies] |
8 | rustc-hash = "1.0.0" | 8 | rustc-hash = "1.0.0" |
9 | smol_str = "0.1.9" | 9 | smol_str = "0.1.9" |
10 | join_to_string = "0.1.3" | ||
diff --git a/crates/ra_macros/src/mbe.rs b/crates/ra_macros/src/mbe.rs index 6a168a1b5..ac76d64e4 100644 --- a/crates/ra_macros/src/mbe.rs +++ b/crates/ra_macros/src/mbe.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use smol_str::SmolStr; | 1 | use smol_str::SmolStr; |
2 | 2 | ||
3 | use crate::tt::Delimiter; | 3 | pub(crate) use crate::tt::{Delimiter, Punct}; |
4 | 4 | ||
5 | pub use crate::{ | 5 | pub use crate::{ |
6 | mbe_parser::parse, | 6 | mbe_parser::parse, |
@@ -61,11 +61,6 @@ pub(crate) struct Literal { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | #[derive(Debug)] | 63 | #[derive(Debug)] |
64 | pub(crate) struct Punct { | ||
65 | pub(crate) char: char, | ||
66 | } | ||
67 | |||
68 | #[derive(Debug)] | ||
69 | pub(crate) struct Ident { | 64 | pub(crate) struct Ident { |
70 | pub(crate) text: SmolStr, | 65 | pub(crate) text: SmolStr, |
71 | } | 66 | } |
diff --git a/crates/ra_macros/src/mbe_expander.rs b/crates/ra_macros/src/mbe_expander.rs index f55c337da..5d5363261 100644 --- a/crates/ra_macros/src/mbe_expander.rs +++ b/crates/ra_macros/src/mbe_expander.rs | |||
@@ -1,15 +1,16 @@ | |||
1 | use rustc_hash::FxHashMap; | 1 | use rustc_hash::FxHashMap; |
2 | use smol_str::SmolStr; | 2 | use smol_str::SmolStr; |
3 | 3 | ||
4 | use crate::{mbe, tt}; | 4 | use crate::{mbe, tt, tt_cursor::TtCursor}; |
5 | 5 | ||
6 | pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> { | 6 | pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> { |
7 | rules.rules.iter().find_map(|it| expand_rule(it, input)) | 7 | rules.rules.iter().find_map(|it| expand_rule(it, input)) |
8 | } | 8 | } |
9 | 9 | ||
10 | fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> { | 10 | fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> { |
11 | let bindings = match_lhs(&rule.lhs, input)?; | 11 | let mut input = TtCursor::new(input); |
12 | expand_rhs(&rule.rhs, &bindings) | 12 | let bindings = match_lhs(&rule.lhs, &mut input)?; |
13 | expand_subtree(&rule.rhs, &bindings, &mut Vec::new()) | ||
13 | } | 14 | } |
14 | 15 | ||
15 | #[derive(Debug, Default)] | 16 | #[derive(Debug, Default)] |
@@ -23,25 +24,35 @@ enum Binding { | |||
23 | Nested(Vec<Binding>), | 24 | Nested(Vec<Binding>), |
24 | } | 25 | } |
25 | 26 | ||
26 | /* | 27 | impl Bindings { |
27 | 28 | fn get(&self, name: &SmolStr, nesting: &[usize]) -> Option<&tt::TokenTree> { | |
28 | macro_rules! impl_froms { | 29 | let mut b = self.inner.get(name)?; |
29 | ($e:ident: $($v:ident),*) => { | 30 | for &idx in nesting.iter() { |
30 | $( | 31 | b = match b { |
31 | impl From<$v> for $e { | 32 | Binding::Simple(_) => break, |
32 | fn from(it: $v) -> $e { | 33 | Binding::Nested(bs) => bs.get(idx)?, |
33 | $e::$v(it) | 34 | }; |
34 | } | 35 | } |
36 | match b { | ||
37 | Binding::Simple(it) => Some(it), | ||
38 | Binding::Nested(_) => None, | ||
39 | } | ||
40 | } | ||
41 | fn push_nested(&mut self, nested: Bindings) -> Option<()> { | ||
42 | for (key, value) in nested.inner { | ||
43 | if !self.inner.contains_key(&key) { | ||
44 | self.inner.insert(key.clone(), Binding::Nested(Vec::new())); | ||
35 | } | 45 | } |
36 | )* | 46 | match self.inner.get_mut(&key) { |
47 | Some(Binding::Nested(it)) => it.push(value), | ||
48 | _ => return None, | ||
49 | } | ||
50 | } | ||
51 | Some(()) | ||
37 | } | 52 | } |
38 | } | 53 | } |
39 | 54 | ||
40 | impl_froms! (Foo: Bar, Baz) | 55 | fn match_lhs(pattern: &mbe::Subtree, input: &mut TtCursor) -> Option<Bindings> { |
41 | |||
42 | */ | ||
43 | |||
44 | fn match_lhs(pattern: &mbe::Subtree, input: &tt::Subtree) -> Option<Bindings> { | ||
45 | let mut res = Bindings::default(); | 56 | let mut res = Bindings::default(); |
46 | for pat in pattern.token_trees.iter() { | 57 | for pat in pattern.token_trees.iter() { |
47 | match pat { | 58 | match pat { |
@@ -49,18 +60,110 @@ fn match_lhs(pattern: &mbe::Subtree, input: &tt::Subtree) -> Option<Bindings> { | |||
49 | mbe::Leaf::Var(mbe::Var { text, kind }) => { | 60 | mbe::Leaf::Var(mbe::Var { text, kind }) => { |
50 | let kind = kind.clone()?; | 61 | let kind = kind.clone()?; |
51 | match kind.as_str() { | 62 | match kind.as_str() { |
52 | "ident" => (), | 63 | "ident" => { |
64 | let ident = input.eat_ident()?.clone(); | ||
65 | res.inner.insert( | ||
66 | text.clone(), | ||
67 | Binding::Simple(tt::Leaf::from(ident).into()), | ||
68 | ); | ||
69 | } | ||
53 | _ => return None, | 70 | _ => return None, |
54 | } | 71 | } |
55 | } | 72 | } |
73 | mbe::Leaf::Punct(punct) => { | ||
74 | if input.eat_punct()? != punct { | ||
75 | return None; | ||
76 | } | ||
77 | } | ||
56 | _ => return None, | 78 | _ => return None, |
57 | }, | 79 | }, |
80 | mbe::TokenTree::Repeat(mbe::Repeat { | ||
81 | subtree, | ||
82 | kind: _, | ||
83 | separator, | ||
84 | }) => { | ||
85 | while let Some(nested) = match_lhs(subtree, input) { | ||
86 | res.push_nested(nested)?; | ||
87 | if separator.is_some() && !input.is_eof() { | ||
88 | input.eat_punct()?; | ||
89 | } | ||
90 | } | ||
91 | } | ||
58 | _ => {} | 92 | _ => {} |
59 | } | 93 | } |
60 | } | 94 | } |
61 | Some(res) | 95 | Some(res) |
62 | } | 96 | } |
63 | 97 | ||
64 | fn expand_rhs(template: &mbe::Subtree, bindings: &Bindings) -> Option<tt::Subtree> { | 98 | /* |
65 | None | 99 | |
100 | macro_rules! impl_froms { | ||
101 | ($e:ident: $($v:ident),*) => { | ||
102 | $( | ||
103 | impl From<$v> for $e { | ||
104 | fn from(it: $v) -> $e { | ||
105 | $e::$v(it) | ||
106 | } | ||
107 | } | ||
108 | )* | ||
109 | } | ||
110 | } | ||
111 | |||
112 | impl_froms! (Foo: Bar, Baz) | ||
113 | |||
114 | */ | ||
115 | |||
116 | fn expand_subtree( | ||
117 | template: &mbe::Subtree, | ||
118 | bindings: &Bindings, | ||
119 | nesting: &mut Vec<usize>, | ||
120 | ) -> Option<tt::Subtree> { | ||
121 | let token_trees = template | ||
122 | .token_trees | ||
123 | .iter() | ||
124 | .map(|it| expand_tt(it, bindings, nesting)) | ||
125 | .collect::<Option<Vec<_>>>()?; | ||
126 | |||
127 | Some(tt::Subtree { | ||
128 | token_trees, | ||
129 | delimiter: template.delimiter, | ||
130 | }) | ||
131 | } | ||
132 | |||
133 | fn expand_tt( | ||
134 | template: &mbe::TokenTree, | ||
135 | bindings: &Bindings, | ||
136 | nesting: &mut Vec<usize>, | ||
137 | ) -> Option<tt::TokenTree> { | ||
138 | let res: tt::TokenTree = match template { | ||
139 | mbe::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(), | ||
140 | mbe::TokenTree::Repeat(repeat) => { | ||
141 | let mut token_trees = Vec::new(); | ||
142 | nesting.push(0); | ||
143 | while let Some(t) = expand_subtree(&repeat.subtree, bindings, nesting) { | ||
144 | let idx = nesting.pop().unwrap(); | ||
145 | nesting.push(idx + 1); | ||
146 | token_trees.push(t.into()) | ||
147 | } | ||
148 | nesting.pop().unwrap(); | ||
149 | tt::Subtree { | ||
150 | token_trees, | ||
151 | delimiter: tt::Delimiter::None, | ||
152 | } | ||
153 | .into() | ||
154 | } | ||
155 | mbe::TokenTree::Leaf(leaf) => match leaf { | ||
156 | mbe::Leaf::Ident(ident) => tt::Leaf::from(tt::Ident { | ||
157 | text: ident.text.clone(), | ||
158 | }) | ||
159 | .into(), | ||
160 | mbe::Leaf::Punct(punct) => tt::Leaf::from(punct.clone()).into(), | ||
161 | mbe::Leaf::Var(v) => bindings.get(&v.text, nesting)?.clone(), | ||
162 | mbe::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { | ||
163 | text: l.text.clone(), | ||
164 | }) | ||
165 | .into(), | ||
166 | }, | ||
167 | }; | ||
168 | Some(res) | ||
66 | } | 169 | } |
diff --git a/crates/ra_macros/src/mbe_parser.rs b/crates/ra_macros/src/mbe_parser.rs index 024d3a040..279ab2f25 100644 --- a/crates/ra_macros/src/mbe_parser.rs +++ b/crates/ra_macros/src/mbe_parser.rs | |||
@@ -84,7 +84,7 @@ fn parse_repeat(p: &mut TtCursor) -> Option<mbe::Repeat> { | |||
84 | let kind = match rep { | 84 | let kind = match rep { |
85 | '*' => mbe::RepeatKind::ZeroOrMore, | 85 | '*' => mbe::RepeatKind::ZeroOrMore, |
86 | '+' => mbe::RepeatKind::OneOrMore, | 86 | '+' => mbe::RepeatKind::OneOrMore, |
87 | '?' => mbe::RepeatKind::ZeroOrMore, | 87 | '?' => mbe::RepeatKind::ZeroOrOne, |
88 | _ => return None, | 88 | _ => return None, |
89 | }; | 89 | }; |
90 | p.bump(); | 90 | p.bump(); |
diff --git a/crates/ra_macros/src/tt.rs b/crates/ra_macros/src/tt.rs index 364eed9e6..56e930f00 100644 --- a/crates/ra_macros/src/tt.rs +++ b/crates/ra_macros/src/tt.rs | |||
@@ -1,13 +1,16 @@ | |||
1 | use std::fmt; | ||
2 | |||
1 | use smol_str::SmolStr; | 3 | use smol_str::SmolStr; |
4 | use join_to_string::join; | ||
2 | 5 | ||
3 | #[derive(Debug)] | 6 | #[derive(Debug, Clone)] |
4 | pub enum TokenTree { | 7 | pub enum TokenTree { |
5 | Leaf(Leaf), | 8 | Leaf(Leaf), |
6 | Subtree(Subtree), | 9 | Subtree(Subtree), |
7 | } | 10 | } |
8 | impl_froms!(TokenTree: Leaf, Subtree); | 11 | impl_froms!(TokenTree: Leaf, Subtree); |
9 | 12 | ||
10 | #[derive(Debug)] | 13 | #[derive(Debug, Clone)] |
11 | pub enum Leaf { | 14 | pub enum Leaf { |
12 | Literal(Literal), | 15 | Literal(Literal), |
13 | Punct(Punct), | 16 | Punct(Punct), |
@@ -15,7 +18,7 @@ pub enum Leaf { | |||
15 | } | 18 | } |
16 | impl_froms!(Leaf: Literal, Punct, Ident); | 19 | impl_froms!(Leaf: Literal, Punct, Ident); |
17 | 20 | ||
18 | #[derive(Debug)] | 21 | #[derive(Debug, Clone)] |
19 | pub struct Subtree { | 22 | pub struct Subtree { |
20 | pub delimiter: Delimiter, | 23 | pub delimiter: Delimiter, |
21 | pub token_trees: Vec<TokenTree>, | 24 | pub token_trees: Vec<TokenTree>, |
@@ -29,17 +32,69 @@ pub enum Delimiter { | |||
29 | None, | 32 | None, |
30 | } | 33 | } |
31 | 34 | ||
32 | #[derive(Debug)] | 35 | #[derive(Debug, Clone)] |
33 | pub struct Literal { | 36 | pub struct Literal { |
34 | pub text: SmolStr, | 37 | pub text: SmolStr, |
35 | } | 38 | } |
36 | 39 | ||
37 | #[derive(Debug)] | 40 | #[derive(Debug, Clone, PartialEq, Eq)] |
38 | pub struct Punct { | 41 | pub struct Punct { |
39 | pub char: char, | 42 | pub char: char, |
40 | } | 43 | } |
41 | 44 | ||
42 | #[derive(Debug)] | 45 | #[derive(Debug, Clone)] |
43 | pub struct Ident { | 46 | pub struct Ident { |
44 | pub text: SmolStr, | 47 | pub text: SmolStr, |
45 | } | 48 | } |
49 | |||
50 | impl fmt::Display for TokenTree { | ||
51 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
52 | match self { | ||
53 | TokenTree::Leaf(it) => fmt::Display::fmt(it, f), | ||
54 | TokenTree::Subtree(it) => fmt::Display::fmt(it, f), | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | impl fmt::Display for Subtree { | ||
60 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
61 | let (l, r) = match self.delimiter { | ||
62 | Delimiter::Parenthesis => ("(", ")"), | ||
63 | Delimiter::Brace => ("{", "}"), | ||
64 | Delimiter::Bracket => ("[", "]"), | ||
65 | Delimiter::None => ("", ""), | ||
66 | }; | ||
67 | join(self.token_trees.iter()) | ||
68 | .separator(" ") | ||
69 | .surround_with(l, r) | ||
70 | .to_fmt(f) | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl fmt::Display for Leaf { | ||
75 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
76 | match self { | ||
77 | Leaf::Ident(it) => fmt::Display::fmt(it, f), | ||
78 | Leaf::Literal(it) => fmt::Display::fmt(it, f), | ||
79 | Leaf::Punct(it) => fmt::Display::fmt(it, f), | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | impl fmt::Display for Ident { | ||
85 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
86 | fmt::Display::fmt(&self.text, f) | ||
87 | } | ||
88 | } | ||
89 | |||
90 | impl fmt::Display for Literal { | ||
91 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
92 | fmt::Display::fmt(&self.text, f) | ||
93 | } | ||
94 | } | ||
95 | |||
96 | impl fmt::Display for Punct { | ||
97 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
98 | fmt::Display::fmt(&self.char, f) | ||
99 | } | ||
100 | } | ||
diff --git a/crates/ra_macros/src/tt_cursor.rs b/crates/ra_macros/src/tt_cursor.rs index 380c60b40..6dc9f400d 100644 --- a/crates/ra_macros/src/tt_cursor.rs +++ b/crates/ra_macros/src/tt_cursor.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use crate::tt; | 1 | use crate::tt; |
2 | 2 | ||
3 | #[derive(Clone)] | ||
3 | pub(crate) struct TtCursor<'a> { | 4 | pub(crate) struct TtCursor<'a> { |
4 | subtree: &'a tt::Subtree, | 5 | subtree: &'a tt::Subtree, |
5 | pos: usize, | 6 | pos: usize, |