aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/lib.rs')
-rw-r--r--crates/ra_syntax/src/lib.rs31
1 files changed, 21 insertions, 10 deletions
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index edb6076bb..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]
164macro_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,7 +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 // 309 //
299 // Here's how the first one looks like: 310 // Here's how the first one looks like:
300 let exprs_cast: Vec<String> = file 311 let exprs_cast: Vec<String> = file
@@ -304,17 +315,17 @@ fn api_walkthrough() {
304 .map(|expr| expr.syntax().text().to_string()) 315 .map(|expr| expr.syntax().text().to_string())
305 .collect(); 316 .collect();
306 317
307 // An alternative is to use a visitor. The visitor does not do traversal 318 // An alternative is to use a macro.
308 // automatically (so it's more akin to a generic lambda) and is constructed
309 // from closures. This seems more flexible than a single generated visitor
310 // trait.
311 use algo::visit::{visitor, Visitor};
312 let mut exprs_visit = Vec::new(); 319 let mut exprs_visit = Vec::new();
313 for node in file.syntax().descendants() { 320 for node in file.syntax().descendants() {
314 if let Some(result) = 321 match_ast! {
315 visitor().visit::<ast::Expr, _>(|expr| expr.syntax().text().to_string()).accept(&node) 322 match node {
316 { 323 ast::Expr(it) => {
317 exprs_visit.push(result); 324 let res = it.syntax().text().to_string();
325 exprs_visit.push(res);
326 },
327 _ => (),
328 }
318 } 329 }
319 } 330 }
320 assert_eq!(exprs_cast, exprs_visit); 331 assert_eq!(exprs_cast, exprs_visit);