From 2fc22901730f35405d2bdfe33f88d7b3c6b14304 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 5 Oct 2019 17:03:03 +0300 Subject: replace AST visitors with macro --- crates/ra_syntax/src/lib.rs | 12 ++++++++++++ crates/ra_syntax/src/validation.rs | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'crates/ra_syntax') diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index edb6076bb..09230ccb2 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -295,6 +295,7 @@ fn api_walkthrough() { // 1. explicitly call getter methods on AST nodes. // 2. use descendants and `AstNode::cast`. // 3. use descendants and the visitor. + // 4. use descendants and `match_ast!`. // // Here's how the first one looks like: let exprs_cast: Vec = file @@ -319,3 +320,14 @@ fn api_walkthrough() { } assert_eq!(exprs_cast, exprs_visit); } + +#[macro_export] +macro_rules! match_ast { + (match $node:ident { + $( ast::$ast:ident($it:ident) => $res:block, )* + _ => $catch_all:expr, + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* + { $catch_all } + }}; +} diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 4f8935b2c..ab4f15908 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs @@ -5,8 +5,7 @@ mod block; use rustc_lexer::unescape; use crate::{ - algo::visit::{visitor_ctx, VisitorCtx}, - ast, AstNode, SyntaxError, SyntaxErrorKind, + ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, SyntaxNode, SyntaxToken, TextUnit, T, }; @@ -97,12 +96,15 @@ impl From for SyntaxErrorKind { pub(crate) fn validate(root: &SyntaxNode) -> Vec { let mut errors = Vec::new(); for node in root.descendants() { - let _ = visitor_ctx(&mut errors) - .visit::(validate_literal) - .visit::(block::validate_block_expr) - .visit::(|it, errors| validate_numeric_name(it.name_ref(), errors)) - .visit::(|it, errors| validate_numeric_name(it.name_ref(), errors)) - .accept(&node); + match_ast! { + match node { + ast::Literal(it) => { validate_literal(it, &mut errors) }, + ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) }, + ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, + ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, + _ => (), + } + } } errors } -- cgit v1.2.3 From 311dbb854536dd526cdbcadc6d270f9a37e4b816 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 5 Oct 2019 17:48:31 +0300 Subject: remove `visitor` module --- crates/ra_syntax/src/algo.rs | 2 - crates/ra_syntax/src/algo/visit.rs | 112 ------------------------------------- crates/ra_syntax/src/lib.rs | 43 +++++++------- 3 files changed, 21 insertions(+), 136 deletions(-) delete mode 100644 crates/ra_syntax/src/algo/visit.rs (limited to 'crates/ra_syntax') diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index d55534ede..7cfea70f9 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -1,7 +1,5 @@ //! FIXME: write short doc here -pub mod visit; - use std::ops::RangeInclusive; use itertools::Itertools; diff --git a/crates/ra_syntax/src/algo/visit.rs b/crates/ra_syntax/src/algo/visit.rs deleted file mode 100644 index 4df275ba4..000000000 --- a/crates/ra_syntax/src/algo/visit.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! FIXME: write short doc here - -use crate::{AstNode, SyntaxNode}; - -use std::marker::PhantomData; - -pub fn visitor<'a, T>() -> impl Visitor<'a, Output = T> { - EmptyVisitor { ph: PhantomData } -} - -pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> { - EmptyVisitorCtx { ph: PhantomData, ctx } -} - -pub trait Visitor<'a>: Sized { - type Output; - fn accept(self, node: &'a SyntaxNode) -> Option; - fn visit(self, f: F) -> Vis - where - N: AstNode + 'a, - F: FnOnce(N) -> Self::Output, - { - Vis { inner: self, f, ph: PhantomData } - } -} - -pub trait VisitorCtx<'a>: Sized { - type Output; - type Ctx; - fn accept(self, node: &'a SyntaxNode) -> Result; - fn visit(self, f: F) -> VisCtx - where - N: AstNode + 'a, - F: FnOnce(N, Self::Ctx) -> Self::Output, - { - VisCtx { inner: self, f, ph: PhantomData } - } -} - -#[derive(Debug)] -struct EmptyVisitor { - ph: PhantomData T>, -} - -impl<'a, T> Visitor<'a> for EmptyVisitor { - type Output = T; - - fn accept(self, _node: &'a SyntaxNode) -> Option { - None - } -} - -#[derive(Debug)] -struct EmptyVisitorCtx { - ctx: C, - ph: PhantomData T>, -} - -impl<'a, T, C> VisitorCtx<'a> for EmptyVisitorCtx { - type Output = T; - type Ctx = C; - - fn accept(self, _node: &'a SyntaxNode) -> Result { - Err(self.ctx) - } -} - -#[derive(Debug)] -pub struct Vis { - inner: V, - f: F, - ph: PhantomData, -} - -impl<'a, V, N, F> Visitor<'a> for Vis -where - V: Visitor<'a>, - N: AstNode + 'a, - F: FnOnce(N) -> >::Output, -{ - type Output = >::Output; - - fn accept(self, node: &'a SyntaxNode) -> Option { - let Vis { inner, f, .. } = self; - inner.accept(node).or_else(|| N::cast(node.clone()).map(f)) - } -} - -#[derive(Debug)] -pub struct VisCtx { - inner: V, - f: F, - ph: PhantomData, -} - -impl<'a, V, N, F> VisitorCtx<'a> for VisCtx -where - V: VisitorCtx<'a>, - N: AstNode + 'a, - F: FnOnce(N, >::Ctx) -> >::Output, -{ - type Output = >::Output; - type Ctx = >::Ctx; - - fn accept(self, node: &'a SyntaxNode) -> Result { - let VisCtx { inner, f, .. } = self; - inner.accept(node).or_else(|ctx| match N::cast(node.clone()) { - None => Err(ctx), - Some(node) => Ok(f(node, ctx)), - }) - } -} 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 { } } +#[macro_export] +macro_rules! match_ast { + (match $node:ident { + $( ast::$ast:ident($it:ident) => $res:block, )* + _ => $catch_all:expr, + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* + { $catch_all } + }}; +} + /// This test does not assert anything and instead just shows off the crate's /// API. #[test] @@ -294,8 +305,7 @@ fn api_walkthrough() { // To recursively process the tree, there are three approaches: // 1. explicitly call getter methods on AST nodes. // 2. use descendants and `AstNode::cast`. - // 3. use descendants and the visitor. - // 4. use descendants and `match_ast!`. + // 3. use descendants and `match_ast!`. // // Here's how the first one looks like: let exprs_cast: Vec = file @@ -305,29 +315,18 @@ fn api_walkthrough() { .map(|expr| expr.syntax().text().to_string()) .collect(); - // An alternative is to use a visitor. The visitor does not do traversal - // automatically (so it's more akin to a generic lambda) and is constructed - // from closures. This seems more flexible than a single generated visitor - // trait. - use algo::visit::{visitor, Visitor}; + // An alternative is to use a macro. let mut exprs_visit = Vec::new(); for node in file.syntax().descendants() { - if let Some(result) = - visitor().visit::(|expr| expr.syntax().text().to_string()).accept(&node) - { - exprs_visit.push(result); + match_ast! { + match node { + ast::Expr(it) => { + let res = it.syntax().text().to_string(); + exprs_visit.push(res); + }, + _ => (), + } } } assert_eq!(exprs_cast, exprs_visit); } - -#[macro_export] -macro_rules! match_ast { - (match $node:ident { - $( ast::$ast:ident($it:ident) => $res:block, )* - _ => $catch_all:expr, - }) => {{ - $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* - { $catch_all } - }}; -} -- cgit v1.2.3