aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs124
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
5use ra_parser::FragmentKind::*;
1use ra_syntax::SmolStr; 6use 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.
5use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
6use tt::TokenId; 8use 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
295fn 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)]
364struct ExpandCtx<'a> { 332struct ExpandCtx<'a> {
365 bindings: &'a Bindings, 333 bindings: &'a Bindings,