diff options
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 124 |
1 files changed, 46 insertions, 78 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index f185aecb7..01641fdee 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -1,7 +1,9 @@ | |||
1 | //! This module takes a (parsed) definition of `macro_rules` invocation, a | ||
2 | //! `tt::TokenTree` representing an argument of macro invocation, and produces a | ||
3 | //! `tt::TokenTree` for the result of the expansion. | ||
4 | |||
5 | use ra_parser::FragmentKind::*; | ||
1 | use ra_syntax::SmolStr; | 6 | use ra_syntax::SmolStr; |
2 | /// This module takes a (parsed) definition of `macro_rules` invocation, a | ||
3 | /// `tt::TokenTree` representing an argument of macro invocation, and produces a | ||
4 | /// `tt::TokenTree` for the result of the expansion. | ||
5 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
6 | use tt::TokenId; | 8 | use tt::TokenId; |
7 | 9 | ||
@@ -191,82 +193,12 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
191 | match pat { | 193 | match pat { |
192 | crate::TokenTree::Leaf(leaf) => match leaf { | 194 | crate::TokenTree::Leaf(leaf) => match leaf { |
193 | crate::Leaf::Var(crate::Var { text, kind }) => { | 195 | crate::Leaf::Var(crate::Var { text, kind }) => { |
194 | let kind = kind.clone().ok_or(ExpandError::UnexpectedToken)?; | 196 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; |
195 | match kind.as_str() { | 197 | match match_meta_var(kind.as_str(), input)? { |
196 | "ident" => { | 198 | Some(tt) => { |
197 | let ident = | 199 | res.inner.insert(text.clone(), Binding::Simple(tt)); |
198 | input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
199 | res.inner.insert( | ||
200 | text.clone(), | ||
201 | Binding::Simple(tt::Leaf::from(ident).into()), | ||
202 | ); | ||
203 | } | ||
204 | "path" => { | ||
205 | let path = | ||
206 | input.eat_path().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
207 | res.inner.insert(text.clone(), Binding::Simple(path)); | ||
208 | } | ||
209 | "expr" => { | ||
210 | let expr = | ||
211 | input.eat_expr().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
212 | res.inner.insert(text.clone(), Binding::Simple(expr)); | ||
213 | } | ||
214 | "ty" => { | ||
215 | let ty = input.eat_ty().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
216 | res.inner.insert(text.clone(), Binding::Simple(ty)); | ||
217 | } | ||
218 | "pat" => { | ||
219 | let pat = input.eat_pat().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
220 | res.inner.insert(text.clone(), Binding::Simple(pat)); | ||
221 | } | ||
222 | "stmt" => { | ||
223 | let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
224 | res.inner.insert(text.clone(), Binding::Simple(pat)); | ||
225 | } | ||
226 | "block" => { | ||
227 | let block = | ||
228 | input.eat_block().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
229 | res.inner.insert(text.clone(), Binding::Simple(block)); | ||
230 | } | ||
231 | "meta" => { | ||
232 | let meta = | ||
233 | input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
234 | res.inner.insert(text.clone(), Binding::Simple(meta)); | ||
235 | } | ||
236 | "tt" => { | ||
237 | let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
238 | res.inner.insert(text.clone(), Binding::Simple(token)); | ||
239 | } | ||
240 | "item" => { | ||
241 | let item = | ||
242 | input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
243 | res.inner.insert(text.clone(), Binding::Simple(item)); | ||
244 | } | ||
245 | "lifetime" => { | ||
246 | let lifetime = | ||
247 | input.eat_lifetime().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
248 | res.inner.insert(text.clone(), Binding::Simple(lifetime)); | ||
249 | } | 200 | } |
250 | "literal" => { | 201 | None => res.push_optional(text), |
251 | let literal = | ||
252 | input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
253 | |||
254 | res.inner.insert( | ||
255 | text.clone(), | ||
256 | Binding::Simple(tt::Leaf::from(literal).into()), | ||
257 | ); | ||
258 | } | ||
259 | "vis" => { | ||
260 | // `vis` is optional | ||
261 | if let Some(vis) = input.try_eat_vis() { | ||
262 | let vis = vis.clone(); | ||
263 | res.inner.insert(text.clone(), Binding::Simple(vis)); | ||
264 | } else { | ||
265 | res.push_optional(&text); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | _ => return Err(ExpandError::UnexpectedToken), | ||
270 | } | 202 | } |
271 | } | 203 | } |
272 | crate::Leaf::Punct(punct) => { | 204 | crate::Leaf::Punct(punct) => { |
@@ -360,6 +292,42 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
360 | Ok(res) | 292 | Ok(res) |
361 | } | 293 | } |
362 | 294 | ||
295 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTree>, ExpandError> { | ||
296 | let fragment = match kind { | ||
297 | "path" => Path, | ||
298 | "expr" => Expr, | ||
299 | "ty" => Type, | ||
300 | "pat" => Pattern, | ||
301 | "stmt" => Statement, | ||
302 | "block" => Block, | ||
303 | "meta" => MetaItem, | ||
304 | "item" => Item, | ||
305 | _ => { | ||
306 | let binding = match kind { | ||
307 | "ident" => { | ||
308 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
309 | tt::Leaf::from(ident).into() | ||
310 | } | ||
311 | "tt" => input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(), | ||
312 | "lifetime" => input.eat_lifetime().ok_or(ExpandError::UnexpectedToken)?.clone(), | ||
313 | "literal" => { | ||
314 | let literal = input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
315 | tt::Leaf::from(literal).into() | ||
316 | } | ||
317 | // `vis` is optional | ||
318 | "vis" => match input.try_eat_vis() { | ||
319 | Some(vis) => vis, | ||
320 | None => return Ok(None), | ||
321 | }, | ||
322 | _ => return Err(ExpandError::UnexpectedToken), | ||
323 | }; | ||
324 | return Ok(Some(binding)); | ||
325 | } | ||
326 | }; | ||
327 | let binding = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; | ||
328 | Ok(Some(binding)) | ||
329 | } | ||
330 | |||
363 | #[derive(Debug)] | 331 | #[derive(Debug)] |
364 | struct ExpandCtx<'a> { | 332 | struct ExpandCtx<'a> { |
365 | bindings: &'a Bindings, | 333 | bindings: &'a Bindings, |