summaryrefslogtreecommitdiff
path: root/src/syntax/visit.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-03-03 17:53:40 +0100
committerLaurenz <laurmaedje@gmail.com>2021-03-03 17:53:40 +0100
commitc94a18833f23d2b57de1b87971458fd54b56d088 (patch)
tree9e1ed55cfca15aef6d39ced50a3a5b14d2800aae /src/syntax/visit.rs
parent4d90a066f197264341eff6bf67e8c06cae434eb4 (diff)
Closures and function definitions 🚀
Supports: - Closure syntax: `(x, y) => z` - Shorthand for a single argument: `x => y` - Function syntax: `let f(x) = y` - Capturing of variables from the environment - Error messages for too few / many passed arguments Does not support: - Named arguments - Variadic arguments with `..`
Diffstat (limited to 'src/syntax/visit.rs')
-rw-r--r--src/syntax/visit.rs53
1 files changed, 46 insertions, 7 deletions
diff --git a/src/syntax/visit.rs b/src/syntax/visit.rs
index 1bf260c7..15613233 100644
--- a/src/syntax/visit.rs
+++ b/src/syntax/visit.rs
@@ -3,27 +3,42 @@
use super::*;
macro_rules! visit {
- ($(fn $name:ident($v:ident, $node:ident: &$ty:ty) $body:block)*) => {
+ ($(fn $name:ident($v:ident $(, $node:ident: &$ty:ty)?) $body:block)*) => {
/// Traverses the syntax tree.
pub trait Visit<'ast> {
- $(fn $name(&mut self, $node: &'ast $ty) {
- $name(self, $node);
+ $(fn $name(&mut self $(, $node: &'ast $ty)?) {
+ $name(self, $($node)?);
})*
+
+ /// Visit a definition of a binding.
+ ///
+ /// Bindings are, for example, left-hand side of let expressions,
+ /// and key/value patterns in for loops.
+ fn visit_binding(&mut self, _: &'ast Ident) {}
+
+ /// Visit the entry into a scope.
+ fn visit_enter(&mut self) {}
+
+ /// Visit the exit from a scope.
+ fn visit_exit(&mut self) {}
}
$(visit! {
- @concat!("Walk a node of type [`", stringify!($ty), "`]."),
- pub fn $name<'ast, V>($v: &mut V, $node: &'ast $ty)
+ @$(concat!("Walk a node of type [`", stringify!($ty), "`]."), )?
+ pub fn $name<'ast, V>(
+ #[allow(unused)] $v: &mut V
+ $(, #[allow(unused)] $node: &'ast $ty)?
+ )
where
V: Visit<'ast> + ?Sized
$body
})*
};
+
(@$doc:expr, $($tts:tt)*) => {
#[doc = $doc]
$($tts)*
- }
-
+ };
}
visit! {
@@ -59,6 +74,7 @@ visit! {
Expr::Unary(e) => v.visit_unary(e),
Expr::Binary(e) => v.visit_binary(e),
Expr::Call(e) => v.visit_call(e),
+ Expr::Closure(e) => v.visit_closure(e),
Expr::Let(e) => v.visit_let(e),
Expr::If(e) => v.visit_if(e),
Expr::While(e) => v.visit_while(e),
@@ -79,7 +95,9 @@ visit! {
}
fn visit_template(v, node: &ExprTemplate) {
+ v.visit_enter();
v.visit_tree(&node.tree);
+ v.visit_exit();
}
fn visit_group(v, node: &ExprGroup) {
@@ -87,9 +105,15 @@ visit! {
}
fn visit_block(v, node: &ExprBlock) {
+ if node.scoping {
+ v.visit_enter();
+ }
for expr in &node.exprs {
v.visit_expr(&expr);
}
+ if node.scoping {
+ v.visit_exit();
+ }
}
fn visit_binary(v, node: &ExprBinary) {
@@ -106,6 +130,13 @@ visit! {
v.visit_args(&node.args);
}
+ fn visit_closure(v, node: &ExprClosure) {
+ for param in node.params.iter() {
+ v.visit_binding(param);
+ }
+ v.visit_expr(&node.body);
+ }
+
fn visit_args(v, node: &ExprArgs) {
for arg in &node.items {
v.visit_arg(arg);
@@ -120,6 +151,7 @@ visit! {
}
fn visit_let(v, node: &ExprLet) {
+ v.visit_binding(&node.binding);
if let Some(init) = &node.init {
v.visit_expr(&init);
}
@@ -139,6 +171,13 @@ visit! {
}
fn visit_for(v, node: &ExprFor) {
+ match &node.pattern {
+ ForPattern::Value(value) => v.visit_binding(value),
+ ForPattern::KeyValue(key, value) => {
+ v.visit_binding(key);
+ v.visit_binding(value);
+ }
+ }
v.visit_expr(&node.iter);
v.visit_expr(&node.body);
}