diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-10-05 15:54:25 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-10-05 15:54:25 +0100 |
commit | d3872964f88a0d751c428c150bb40d8b4f4c89a9 (patch) | |
tree | 14b7045119a1918118c18857cc094c914284705c /crates/ra_syntax/src/lib.rs | |
parent | ae6305b90c80eb919cfde985cba66975b6222ed2 (diff) | |
parent | 311dbb854536dd526cdbcadc6d270f9a37e4b816 (diff) |
Merge #1960
1960: Replace AST visitors with macro r=viorina a=viorina
Fixes #1672.
Co-authored-by: Ekaterina Babshukova <[email protected]>
Diffstat (limited to 'crates/ra_syntax/src/lib.rs')
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 31 |
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] | ||
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,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); |