aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/lib.rs
diff options
context:
space:
mode:
authorEkaterina Babshukova <[email protected]>2019-10-05 15:48:31 +0100
committerEkaterina Babshukova <[email protected]>2019-10-05 15:48:31 +0100
commit311dbb854536dd526cdbcadc6d270f9a37e4b816 (patch)
treedb4857e394f6bd6a1045a13d0b3f11a98be8da49 /crates/ra_syntax/src/lib.rs
parent2fc22901730f35405d2bdfe33f88d7b3c6b14304 (diff)
remove `visitor` module
Diffstat (limited to 'crates/ra_syntax/src/lib.rs')
-rw-r--r--crates/ra_syntax/src/lib.rs43
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]
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,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]
325macro_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}