diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/macros.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/macros/mbe.rs | 148 | ||||
-rw-r--r-- | crates/ra_hir/src/macros/tt.rs | 2 |
3 files changed, 131 insertions, 23 deletions
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs index 0497d2168..dc016a704 100644 --- a/crates/ra_hir/src/macros.rs +++ b/crates/ra_hir/src/macros.rs | |||
@@ -260,7 +260,7 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> { | |||
260 | fn test_convert_tt() { | 260 | fn test_convert_tt() { |
261 | let text = r#" | 261 | let text = r#" |
262 | macro_rules! impl_froms { | 262 | macro_rules! impl_froms { |
263 | ($e:ident: $($v:ident), *) => { | 263 | ($e:ident: $($v:ident),*) => { |
264 | $( | 264 | $( |
265 | impl From<$v> for $e { | 265 | impl From<$v> for $e { |
266 | fn from(it: $v) -> $e { | 266 | fn from(it: $v) -> $e { |
@@ -279,5 +279,5 @@ macro_rules! impl_froms { | |||
279 | .unwrap(); | 279 | .unwrap(); |
280 | let tt = macro_call_to_tt(maco_call).unwrap(); | 280 | let tt = macro_call_to_tt(maco_call).unwrap(); |
281 | let tt = mbe::parse(&tt); | 281 | let tt = mbe::parse(&tt); |
282 | dbg!(tt); | 282 | assert!(tt.is_some()); |
283 | } | 283 | } |
diff --git a/crates/ra_hir/src/macros/mbe.rs b/crates/ra_hir/src/macros/mbe.rs index 62b7fa24c..6c93ae5e3 100644 --- a/crates/ra_hir/src/macros/mbe.rs +++ b/crates/ra_hir/src/macros/mbe.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::SmolStr; | 1 | use ra_syntax::SmolStr; |
2 | 2 | ||
3 | use crate::macros::tt; | 3 | use crate::macros::tt::{self, Delimiter}; |
4 | 4 | ||
5 | #[derive(Debug)] | 5 | #[derive(Debug)] |
6 | pub(crate) struct MacroRules { | 6 | pub(crate) struct MacroRules { |
@@ -19,6 +19,7 @@ enum TokenTree { | |||
19 | Subtree(Subtree), | 19 | Subtree(Subtree), |
20 | Repeat(Repeat), | 20 | Repeat(Repeat), |
21 | } | 21 | } |
22 | impl_froms!(TokenTree: Leaf, Subtree, Repeat); | ||
22 | 23 | ||
23 | #[derive(Debug)] | 24 | #[derive(Debug)] |
24 | enum Leaf { | 25 | enum Leaf { |
@@ -27,6 +28,7 @@ enum Leaf { | |||
27 | Ident(Ident), | 28 | Ident(Ident), |
28 | Var(Var), | 29 | Var(Var), |
29 | } | 30 | } |
31 | impl_froms!(Leaf: Literal, Punct, Ident, Var); | ||
30 | 32 | ||
31 | #[derive(Debug)] | 33 | #[derive(Debug)] |
32 | struct Subtree { | 34 | struct Subtree { |
@@ -35,17 +37,10 @@ struct Subtree { | |||
35 | } | 37 | } |
36 | 38 | ||
37 | #[derive(Debug)] | 39 | #[derive(Debug)] |
38 | enum Delimiter { | ||
39 | Parenthesis, | ||
40 | Brace, | ||
41 | Bracket, | ||
42 | None, | ||
43 | } | ||
44 | |||
45 | #[derive(Debug)] | ||
46 | struct Repeat { | 40 | struct Repeat { |
47 | subtree: Subtree, | 41 | subtree: Subtree, |
48 | kind: RepeatKind, | 42 | kind: RepeatKind, |
43 | separator: Option<Punct>, | ||
49 | } | 44 | } |
50 | 45 | ||
51 | #[derive(Debug)] | 46 | #[derive(Debug)] |
@@ -73,6 +68,7 @@ struct Ident { | |||
73 | #[derive(Debug)] | 68 | #[derive(Debug)] |
74 | struct Var { | 69 | struct Var { |
75 | text: SmolStr, | 70 | text: SmolStr, |
71 | kind: Option<SmolStr>, | ||
76 | } | 72 | } |
77 | 73 | ||
78 | pub(crate) fn parse(tt: &tt::Subtree) -> Option<MacroRules> { | 74 | pub(crate) fn parse(tt: &tt::Subtree) -> Option<MacroRules> { |
@@ -86,16 +82,81 @@ pub(crate) fn parse(tt: &tt::Subtree) -> Option<MacroRules> { | |||
86 | 82 | ||
87 | fn parse_rule(p: &mut RulesParser) -> Option<Rule> { | 83 | fn parse_rule(p: &mut RulesParser) -> Option<Rule> { |
88 | let lhs = parse_subtree(p.eat_subtree()?)?; | 84 | let lhs = parse_subtree(p.eat_subtree()?)?; |
89 | p.eat_punct('=')?; | 85 | p.expect_char('=')?; |
90 | p.eat_punct('>')?; | 86 | p.expect_char('>')?; |
91 | let rhs = parse_subtree(p.eat_subtree()?)?; | 87 | let rhs = parse_subtree(p.eat_subtree()?)?; |
92 | Some(Rule { lhs, rhs }) | 88 | Some(Rule { lhs, rhs }) |
93 | } | 89 | } |
94 | 90 | ||
95 | fn parse_subtree(tt: &tt::Subtree) -> Option<Subtree> { | 91 | fn parse_subtree(tt: &tt::Subtree) -> Option<Subtree> { |
92 | let mut token_trees = Vec::new(); | ||
93 | let mut p = RulesParser::new(tt); | ||
94 | while let Some(tt) = p.eat() { | ||
95 | let child: TokenTree = match tt { | ||
96 | tt::TokenTree::Leaf(leaf) => match leaf { | ||
97 | tt::Leaf::Punct(tt::Punct { char: '$' }) => { | ||
98 | if p.at_ident().is_some() { | ||
99 | Leaf::from(parse_var(&mut p)?).into() | ||
100 | } else { | ||
101 | parse_repeat(&mut p)?.into() | ||
102 | } | ||
103 | } | ||
104 | tt::Leaf::Punct(tt::Punct { char }) => Leaf::from(Punct { char: *char }).into(), | ||
105 | tt::Leaf::Ident(tt::Ident { text }) => { | ||
106 | Leaf::from(Ident { text: text.clone() }).into() | ||
107 | } | ||
108 | tt::Leaf::Literal(tt::Literal { text }) => { | ||
109 | Leaf::from(Literal { text: text.clone() }).into() | ||
110 | } | ||
111 | }, | ||
112 | tt::TokenTree::Subtree(subtree) => parse_subtree(subtree)?.into(), | ||
113 | }; | ||
114 | token_trees.push(child); | ||
115 | } | ||
96 | Some(Subtree { | 116 | Some(Subtree { |
97 | token_trees: Vec::new(), | 117 | token_trees, |
98 | delimiter: Delimiter::None, | 118 | delimiter: tt.delimiter, |
119 | }) | ||
120 | } | ||
121 | |||
122 | fn parse_var(p: &mut RulesParser) -> Option<Var> { | ||
123 | let ident = p.eat_ident().unwrap(); | ||
124 | let text = ident.text.clone(); | ||
125 | let kind = if p.at_char(':') { | ||
126 | p.bump(); | ||
127 | if let Some(ident) = p.eat_ident() { | ||
128 | Some(ident.text.clone()) | ||
129 | } else { | ||
130 | // ugly as hell :( | ||
131 | p.pos -= 1; | ||
132 | None | ||
133 | } | ||
134 | } else { | ||
135 | None | ||
136 | }; | ||
137 | Some(Var { text, kind }) | ||
138 | } | ||
139 | |||
140 | fn parse_repeat(p: &mut RulesParser) -> Option<Repeat> { | ||
141 | let subtree = p.eat_subtree().unwrap(); | ||
142 | let subtree = parse_subtree(subtree)?; | ||
143 | let mut sep = p.eat_punct()?; | ||
144 | let (separator, rep) = match sep.char { | ||
145 | '*' | '+' | '?' => (None, sep.char), | ||
146 | char => (Some(Punct { char }), p.eat_punct()?.char), | ||
147 | }; | ||
148 | |||
149 | let kind = match rep { | ||
150 | '*' => RepeatKind::ZeroOrMore, | ||
151 | '+' => RepeatKind::OneOrMore, | ||
152 | '?' => RepeatKind::ZeroOrMore, | ||
153 | _ => return None, | ||
154 | }; | ||
155 | p.bump(); | ||
156 | Some(Repeat { | ||
157 | subtree, | ||
158 | kind, | ||
159 | separator, | ||
99 | }) | 160 | }) |
100 | } | 161 | } |
101 | 162 | ||
@@ -117,9 +178,41 @@ impl<'a> RulesParser<'a> { | |||
117 | self.subtree.token_trees.get(self.pos) | 178 | self.subtree.token_trees.get(self.pos) |
118 | } | 179 | } |
119 | 180 | ||
181 | fn at_punct(&self) -> Option<&'a tt::Punct> { | ||
182 | match self.current() { | ||
183 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(it))) => Some(it), | ||
184 | _ => None, | ||
185 | } | ||
186 | } | ||
187 | |||
188 | fn at_char(&self, char: char) -> bool { | ||
189 | match self.at_punct() { | ||
190 | Some(tt::Punct { char: c }) if *c == char => true, | ||
191 | _ => false, | ||
192 | } | ||
193 | } | ||
194 | |||
195 | fn at_ident(&mut self) -> Option<&'a tt::Ident> { | ||
196 | match self.current() { | ||
197 | Some(tt::TokenTree::Leaf(tt::Leaf::Ident(i))) => Some(i), | ||
198 | _ => None, | ||
199 | } | ||
200 | } | ||
201 | |||
120 | fn bump(&mut self) { | 202 | fn bump(&mut self) { |
121 | self.pos += 1; | 203 | self.pos += 1; |
122 | } | 204 | } |
205 | |||
206 | fn eat(&mut self) -> Option<&'a tt::TokenTree> { | ||
207 | match self.current() { | ||
208 | Some(it) => { | ||
209 | self.bump(); | ||
210 | Some(it) | ||
211 | } | ||
212 | None => None, | ||
213 | } | ||
214 | } | ||
215 | |||
123 | fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> { | 216 | fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> { |
124 | match self.current()? { | 217 | match self.current()? { |
125 | tt::TokenTree::Subtree(sub) => { | 218 | tt::TokenTree::Subtree(sub) => { |
@@ -129,13 +222,28 @@ impl<'a> RulesParser<'a> { | |||
129 | _ => return None, | 222 | _ => return None, |
130 | } | 223 | } |
131 | } | 224 | } |
132 | fn eat_punct(&mut self, char: char) -> Option<()> { | 225 | |
133 | match self.current()? { | 226 | fn eat_punct(&mut self) -> Option<&'a tt::Punct> { |
134 | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c })) if *c == char => { | 227 | if let Some(it) = self.at_punct() { |
135 | self.bump(); | 228 | self.bump(); |
136 | Some(()) | 229 | return Some(it); |
137 | } | 230 | } |
138 | _ => None, | 231 | None |
232 | } | ||
233 | |||
234 | fn eat_ident(&mut self) -> Option<&'a tt::Ident> { | ||
235 | if let Some(i) = self.at_ident() { | ||
236 | self.bump(); | ||
237 | return Some(i); | ||
238 | } | ||
239 | None | ||
240 | } | ||
241 | |||
242 | fn expect_char(&mut self, char: char) -> Option<()> { | ||
243 | if self.at_char(char) { | ||
244 | self.bump(); | ||
245 | return Some(()); | ||
139 | } | 246 | } |
247 | None | ||
140 | } | 248 | } |
141 | } | 249 | } |
diff --git a/crates/ra_hir/src/macros/tt.rs b/crates/ra_hir/src/macros/tt.rs index 02ff422b5..64e88ddc5 100644 --- a/crates/ra_hir/src/macros/tt.rs +++ b/crates/ra_hir/src/macros/tt.rs | |||
@@ -21,7 +21,7 @@ pub(crate) struct Subtree { | |||
21 | pub(crate) token_trees: Vec<TokenTree>, | 21 | pub(crate) token_trees: Vec<TokenTree>, |
22 | } | 22 | } |
23 | 23 | ||
24 | #[derive(Debug)] | 24 | #[derive(Clone, Copy, Debug)] |
25 | pub(crate) enum Delimiter { | 25 | pub(crate) enum Delimiter { |
26 | Parenthesis, | 26 | Parenthesis, |
27 | Brace, | 27 | Brace, |