summaryrefslogtreecommitdiff
path: root/src/syntax/visit.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-02-07 13:14:28 +0100
committerLaurenz <laurmaedje@gmail.com>2021-02-07 13:14:28 +0100
commitc80e13579f3e6ca8fb1aac5a6d423d902747368d (patch)
treeee62a7b7517acd16e9b2b5133c7ad1bdceff0d3c /src/syntax/visit.rs
parentbfc2f5aefc6c407de0b699b31dafd835fc2c9be3 (diff)
Dry-clean visitor with a macro 🏜
Diffstat (limited to 'src/syntax/visit.rs')
-rw-r--r--src/syntax/visit.rs263
1 files changed, 113 insertions, 150 deletions
diff --git a/src/syntax/visit.rs b/src/syntax/visit.rs
index 6f0e7ef3..2e4391ac 100644
--- a/src/syntax/visit.rs
+++ b/src/syntax/visit.rs
@@ -2,184 +2,147 @@
use super::*;
-/// Visits syntax tree nodes in a depth-first manner.
-pub trait Visitor<'a>: Sized {
- /// Visit a variable definition.
- fn visit_def(&mut self, _ident: &'a mut Ident) {}
-
- /// Visit the start of a scope.
- fn visit_scope_pre(&mut self) {}
-
- /// Visit the end of a scope.
- fn visit_scope_post(&mut self) {}
+macro_rules! visit {
+ ($(fn $name:ident($v:ident, $item:ident: &mut $ty:ty) $body:block)*) => {
+ /// Traverses the syntax tree.
+ pub trait Visit<'ast> {
+ $(fn $name(&mut self, $item: &'ast mut $ty) {
+ $name(self, $item);
+ })*
+ }
- fn visit_node(&mut self, node: &'a mut Node) {
- walk_node(self, node)
- }
- fn visit_expr(&mut self, expr: &'a mut Expr) {
- walk_expr(self, expr)
- }
- fn visit_array(&mut self, array: &'a mut ExprArray) {
- walk_array(self, array)
- }
- fn visit_dict(&mut self, dict: &'a mut ExprDict) {
- walk_dict(self, dict)
- }
- fn visit_template(&mut self, template: &'a mut ExprTemplate) {
- walk_template(self, template)
- }
- fn visit_group(&mut self, group: &'a mut ExprGroup) {
- walk_group(self, group)
- }
- fn visit_block(&mut self, block: &'a mut ExprBlock) {
- walk_block(self, block)
- }
- fn visit_binary(&mut self, binary: &'a mut ExprBinary) {
- walk_binary(self, binary)
- }
- fn visit_unary(&mut self, unary: &'a mut ExprUnary) {
- walk_unary(self, unary)
- }
- fn visit_call(&mut self, call: &'a mut ExprCall) {
- walk_call(self, call)
+ $(visit! {
+ @concat!("Walk a node of type [`", stringify!($ty), "`]."),
+ pub fn $name<'ast, V>($v: &mut V, $item: &'ast mut $ty)
+ where
+ V: Visit<'ast> + ?Sized
+ $body
+ })*
+ };
+ (@$doc:expr, $($tts:tt)*) => {
+ #[doc = $doc]
+ $($tts)*
}
- fn visit_arg(&mut self, arg: &'a mut Argument) {
- walk_arg(self, arg)
- }
- fn visit_let(&mut self, expr_let: &'a mut ExprLet) {
- walk_let(self, expr_let)
- }
- fn visit_if(&mut self, expr_if: &'a mut ExprIf) {
- walk_if(self, expr_if)
- }
- fn visit_for(&mut self, expr_for: &'a mut ExprFor) {
- walk_for(self, expr_for)
- }
-}
-pub fn walk_node<'a, V: Visitor<'a>>(v: &mut V, node: &'a mut Node) {
- match node {
- Node::Strong => {}
- Node::Emph => {}
- Node::Space => {}
- Node::Linebreak => {}
- Node::Parbreak => {}
- Node::Text(_) => {}
- Node::Heading(_) => {}
- Node::Raw(_) => {}
- Node::Expr(expr) => v.visit_expr(expr),
- }
}
-pub fn walk_expr<'a, V: Visitor<'a>>(v: &mut V, expr: &'a mut Expr) {
- match expr {
- Expr::None => {}
- Expr::Ident(_) => {}
- Expr::Bool(_) => {}
- Expr::Int(_) => {}
- Expr::Float(_) => {}
- Expr::Length(_, _) => {}
- Expr::Angle(_, _) => {}
- Expr::Percent(_) => {}
- Expr::Color(_) => {}
- Expr::Str(_) => {}
- Expr::Array(e) => v.visit_array(e),
- Expr::Dict(e) => v.visit_dict(e),
- Expr::Template(e) => v.visit_template(e),
- Expr::Group(e) => v.visit_group(e),
- Expr::Block(e) => v.visit_block(e),
- Expr::Unary(e) => v.visit_unary(e),
- Expr::Binary(e) => v.visit_binary(e),
- Expr::Call(e) => v.visit_call(e),
- Expr::Let(e) => v.visit_let(e),
- Expr::If(e) => v.visit_if(e),
- Expr::For(e) => v.visit_for(e),
- Expr::Captured(_) => {}
+visit! {
+ fn visit_tree(v, item: &mut Tree) {
+ for node in item {
+ v.visit_node(&mut node.v);
+ }
}
-}
-pub fn walk_array<'a, V: Visitor<'a>>(v: &mut V, array: &'a mut ExprArray) {
- for expr in array {
- v.visit_expr(&mut expr.v);
+ fn visit_node(v, item: &mut Node) {
+ match item {
+ Node::Strong => {}
+ Node::Emph => {}
+ Node::Space => {}
+ Node::Linebreak => {}
+ Node::Parbreak => {}
+ Node::Text(_) => {}
+ Node::Heading(n) => v.visit_tree(&mut n.contents),
+ Node::Raw(_) => {}
+ Node::Expr(expr) => v.visit_expr(expr),
+ }
}
-}
-pub fn walk_dict<'a, V: Visitor<'a>>(v: &mut V, dict: &'a mut ExprDict) {
- for named in dict {
- v.visit_expr(&mut named.expr.v);
+ fn visit_expr(v, item: &mut Expr) {
+ match item {
+ Expr::None => {}
+ Expr::Ident(_) => {}
+ Expr::Bool(_) => {}
+ Expr::Int(_) => {}
+ Expr::Float(_) => {}
+ Expr::Length(_, _) => {}
+ Expr::Angle(_, _) => {}
+ Expr::Percent(_) => {}
+ Expr::Color(_) => {}
+ Expr::Str(_) => {}
+ Expr::Array(e) => v.visit_array(e),
+ Expr::Dict(e) => v.visit_dict(e),
+ Expr::Template(e) => v.visit_template(e),
+ Expr::Group(e) => v.visit_group(e),
+ Expr::Block(e) => v.visit_block(e),
+ Expr::Unary(e) => v.visit_unary(e),
+ Expr::Binary(e) => v.visit_binary(e),
+ Expr::Call(e) => v.visit_call(e),
+ Expr::Let(e) => v.visit_let(e),
+ Expr::If(e) => v.visit_if(e),
+ Expr::For(e) => v.visit_for(e),
+ Expr::Captured(_) => {}
+ }
}
-}
-pub fn walk_template<'a, V: Visitor<'a>>(v: &mut V, template: &'a mut ExprTemplate) {
- v.visit_scope_pre();
- for node in template {
- v.visit_node(&mut node.v);
+ fn visit_array(v, item: &mut ExprArray) {
+ for expr in item {
+ v.visit_expr(&mut expr.v);
+ }
}
- v.visit_scope_post();
-}
-pub fn walk_group<'a, V: Visitor<'a>>(v: &mut V, group: &'a mut ExprGroup) {
- v.visit_expr(&mut group.v);
-}
+ fn visit_dict(v, item: &mut ExprDict) {
+ for named in item {
+ v.visit_expr(&mut named.expr.v);
+ }
+ }
-pub fn walk_block<'a, V: Visitor<'a>>(v: &mut V, block: &'a mut ExprBlock) {
- if block.scopes {
- v.visit_scope_pre();
+ fn visit_template(v, item: &mut ExprTemplate) {
+ v.visit_tree(item);
}
- for expr in &mut block.exprs {
- v.visit_expr(&mut expr.v);
+
+ fn visit_group(v, item: &mut ExprGroup) {
+ v.visit_expr(&mut item.v);
}
- if block.scopes {
- v.visit_scope_post();
+
+ fn visit_block(v, item: &mut ExprBlock) {
+ for expr in &mut item.exprs {
+ v.visit_expr(&mut expr.v);
+ }
}
-}
-pub fn walk_binary<'a, V: Visitor<'a>>(v: &mut V, binary: &'a mut ExprBinary) {
- v.visit_expr(&mut binary.lhs.v);
- v.visit_expr(&mut binary.rhs.v);
-}
+ fn visit_binary(v, item: &mut ExprBinary) {
+ v.visit_expr(&mut item.lhs.v);
+ v.visit_expr(&mut item.rhs.v);
+ }
-pub fn walk_unary<'a, V: Visitor<'a>>(v: &mut V, unary: &'a mut ExprUnary) {
- v.visit_expr(&mut unary.expr.v);
-}
+ fn visit_unary(v, item: &mut ExprUnary) {
+ v.visit_expr(&mut item.expr.v);
+ }
-pub fn walk_call<'a, V: Visitor<'a>>(v: &mut V, call: &'a mut ExprCall) {
- v.visit_expr(&mut call.callee.v);
- for arg in &mut call.args.v {
- v.visit_arg(arg);
+ fn visit_call(v, item: &mut ExprCall) {
+ v.visit_expr(&mut item.callee.v);
+ v.visit_args(&mut item.args.v);
}
-}
-pub fn walk_arg<'a, V: Visitor<'a>>(v: &mut V, arg: &'a mut Argument) {
- match arg {
- Argument::Pos(expr) => v.visit_expr(&mut expr.v),
- Argument::Named(named) => v.visit_expr(&mut named.expr.v),
+ fn visit_args(v, item: &mut ExprArgs) {
+ for arg in item {
+ v.visit_arg(arg);
+ }
}
-}
-pub fn walk_let<'a, V: Visitor<'a>>(v: &mut V, expr_let: &'a mut ExprLet) {
- v.visit_def(&mut expr_let.pat.v);
- if let Some(init) = &mut expr_let.init {
- v.visit_expr(&mut init.v);
+ fn visit_arg(v, item: &mut Argument) {
+ match item {
+ Argument::Pos(expr) => v.visit_expr(&mut expr.v),
+ Argument::Named(named) => v.visit_expr(&mut named.expr.v),
+ }
}
-}
-pub fn walk_if<'a, V: Visitor<'a>>(v: &mut V, expr_if: &'a mut ExprIf) {
- v.visit_expr(&mut expr_if.condition.v);
- v.visit_expr(&mut expr_if.if_body.v);
- if let Some(body) = &mut expr_if.else_body {
- v.visit_expr(&mut body.v);
+ fn visit_let(v, item: &mut ExprLet) {
+ if let Some(init) = &mut item.init {
+ v.visit_expr(&mut init.v);
+ }
}
-}
-pub fn walk_for<'a, V: Visitor<'a>>(v: &mut V, expr_for: &'a mut ExprFor) {
- match &mut expr_for.pat.v {
- ForPattern::Value(value) => v.visit_def(value),
- ForPattern::KeyValue(key, value) => {
- v.visit_def(key);
- v.visit_def(value);
+ fn visit_if(v, item: &mut ExprIf) {
+ v.visit_expr(&mut item.condition.v);
+ v.visit_expr(&mut item.if_body.v);
+ if let Some(body) = &mut item.else_body {
+ v.visit_expr(&mut body.v);
}
}
- v.visit_expr(&mut expr_for.iter.v);
- v.visit_expr(&mut expr_for.body.v);
+
+ fn visit_for(v, item: &mut ExprFor) {
+ v.visit_expr(&mut item.iter.v);
+ v.visit_expr(&mut item.body.v);
+ }
}