diff options
Diffstat (limited to 'crates/ra_syntax/src/lib.rs')
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 43 |
1 files changed, 21 insertions, 22 deletions
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 09230ccb2..c315ba552 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -160,6 +160,17 @@ impl SourceFile { | |||
160 | } | 160 | } |
161 | } | 161 | } |
162 | 162 | ||
163 | #[macro_export] | ||
164 | macro_rules! match_ast { | ||
165 | (match $node:ident { | ||
166 | $( ast::$ast:ident($it:ident) => $res:block, )* | ||
167 | _ => $catch_all:expr, | ||
168 | }) => {{ | ||
169 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | ||
170 | { $catch_all } | ||
171 | }}; | ||
172 | } | ||
173 | |||
163 | /// This test does not assert anything and instead just shows off the crate's | 174 | /// This test does not assert anything and instead just shows off the crate's |
164 | /// API. | 175 | /// API. |
165 | #[test] | 176 | #[test] |
@@ -294,8 +305,7 @@ fn api_walkthrough() { | |||
294 | // To recursively process the tree, there are three approaches: | 305 | // To recursively process the tree, there are three approaches: |
295 | // 1. explicitly call getter methods on AST nodes. | 306 | // 1. explicitly call getter methods on AST nodes. |
296 | // 2. use descendants and `AstNode::cast`. | 307 | // 2. use descendants and `AstNode::cast`. |
297 | // 3. use descendants and the visitor. | 308 | // 3. use descendants and `match_ast!`. |
298 | // 4. use descendants and `match_ast!`. | ||
299 | // | 309 | // |
300 | // Here's how the first one looks like: | 310 | // Here's how the first one looks like: |
301 | let exprs_cast: Vec<String> = file | 311 | let exprs_cast: Vec<String> = file |
@@ -305,29 +315,18 @@ fn api_walkthrough() { | |||
305 | .map(|expr| expr.syntax().text().to_string()) | 315 | .map(|expr| expr.syntax().text().to_string()) |
306 | .collect(); | 316 | .collect(); |
307 | 317 | ||
308 | // An alternative is to use a visitor. The visitor does not do traversal | 318 | // An alternative is to use a macro. |
309 | // automatically (so it's more akin to a generic lambda) and is constructed | ||
310 | // from closures. This seems more flexible than a single generated visitor | ||
311 | // trait. | ||
312 | use algo::visit::{visitor, Visitor}; | ||
313 | let mut exprs_visit = Vec::new(); | 319 | let mut exprs_visit = Vec::new(); |
314 | for node in file.syntax().descendants() { | 320 | for node in file.syntax().descendants() { |
315 | if let Some(result) = | 321 | match_ast! { |
316 | visitor().visit::<ast::Expr, _>(|expr| expr.syntax().text().to_string()).accept(&node) | 322 | match node { |
317 | { | 323 | ast::Expr(it) => { |
318 | exprs_visit.push(result); | 324 | let res = it.syntax().text().to_string(); |
325 | exprs_visit.push(res); | ||
326 | }, | ||
327 | _ => (), | ||
328 | } | ||
319 | } | 329 | } |
320 | } | 330 | } |
321 | assert_eq!(exprs_cast, exprs_visit); | 331 | assert_eq!(exprs_cast, exprs_visit); |
322 | } | 332 | } |
323 | |||
324 | #[macro_export] | ||
325 | macro_rules! match_ast { | ||
326 | (match $node:ident { | ||
327 | $( ast::$ast:ident($it:ident) => $res:block, )* | ||
328 | _ => $catch_all:expr, | ||
329 | }) => {{ | ||
330 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | ||
331 | { $catch_all } | ||
332 | }}; | ||
333 | } | ||