diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-03-03 17:53:40 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-03-03 17:53:40 +0100 |
| commit | c94a18833f23d2b57de1b87971458fd54b56d088 (patch) | |
| tree | 9e1ed55cfca15aef6d39ced50a3a5b14d2800aae /src/syntax/visit.rs | |
| parent | 4d90a066f197264341eff6bf67e8c06cae434eb4 (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.rs | 53 |
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); } |
