summaryrefslogtreecommitdiff
path: root/src/eval/capture.rs
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2021-10-23 19:03:27 +0200
committerMartin Haug <mhaug@live.de>2021-11-05 13:44:49 +0100
commit4875633acf4701705b9b3b014eb7d94268b897c2 (patch)
tree0aedda87c8c2dc65316e2455c35e72054d9bae0e /src/eval/capture.rs
parentea6ee3f667e922ed2f21b08719a45d2395787932 (diff)
Change parser
Diffstat (limited to 'src/eval/capture.rs')
-rw-r--r--src/eval/capture.rs96
1 files changed, 71 insertions, 25 deletions
diff --git a/src/eval/capture.rs b/src/eval/capture.rs
index f0a2b729..baf59747 100644
--- a/src/eval/capture.rs
+++ b/src/eval/capture.rs
@@ -1,8 +1,7 @@
use std::rc::Rc;
use super::{Scope, Scopes, Value};
-use crate::syntax::visit::{immutable::visit_expr, Visit};
-use crate::syntax::{Expr, Ident};
+use crate::syntax::{ClosureParam, Expr, Imports, RedTicket};
/// A visitor that captures variable slots.
pub struct CapturesVisitor<'a> {
@@ -21,36 +20,83 @@ impl<'a> CapturesVisitor<'a> {
}
}
- /// Return the scope of captured variables.
- pub fn finish(self) -> Scope {
- self.captures
- }
-}
+ pub fn visit(&mut self, node: RedTicket) {
+ let expr: Option<Expr> = node.cast();
+
+ match expr.as_ref() {
+ Some(Expr::Let(expr)) => {
+ self.visit(expr.init_ticket());
+ let ident = expr.binding();
+ self.internal.def_mut(ident.as_str(), Value::None);
+ }
+ Some(Expr::Closure(closure)) => {
+ for arg in closure.params() {
+ match arg {
+ ClosureParam::Pos(ident) | ClosureParam::Sink(ident) => {
+ self.internal.def_mut(ident.as_str(), Value::None);
+ }
+ ClosureParam::Named(name) => {
+ self.internal.def_mut(name.name().as_str(), Value::None);
+ }
+ }
+ }
+ self.visit(closure.body_ticket());
+ }
+ Some(Expr::For(forloop)) => {
+ let pattern = forloop.pattern();
+ self.internal.def_mut(pattern.value().as_str(), Value::None);
-impl<'ast> Visit<'ast> for CapturesVisitor<'_> {
- fn visit_expr(&mut self, node: &'ast Expr) {
- if let Expr::Ident(ident) = node {
- // Find out whether the name is not locally defined and if so if it
- // can be captured.
- if self.internal.get(ident).is_none() {
- if let Some(slot) = self.external.get(ident) {
- self.captures.def_slot(ident.as_str(), Rc::clone(slot));
+ if let Some(key) = pattern.key() {
+ self.internal.def_mut(key.as_str(), Value::None);
+ }
+ self.visit(forloop.body_ticket());
+ }
+ Some(Expr::Import(import)) => {
+ if let Imports::Idents(idents) = import.imports() {
+ for ident in idents {
+ self.internal.def_mut(ident.as_str(), Value::None);
+ }
}
}
- } else {
- visit_expr(self, node);
+ Some(Expr::Ident(ident)) => {
+ if self.internal.get(ident.as_str()).is_none() {
+ if let Some(slot) = self.external.get(ident.as_str()) {
+ self.captures.def_slot(ident.as_str(), Rc::clone(slot));
+ }
+ }
+ }
+ _ => {}
}
- }
- fn visit_binding(&mut self, ident: &'ast Ident) {
- self.internal.def_mut(ident.as_str(), Value::None);
- }
+ match expr.as_ref() {
+ Some(Expr::Let(_)) | Some(Expr::For(_)) | Some(Expr::Closure(_)) => {}
+
+ Some(Expr::Block(_)) => {
+ self.internal.enter();
+ for child in node.own().children() {
+ self.visit(child);
+ }
+ self.internal.exit();
+ }
+
+ Some(Expr::Template(_)) => {
+ self.internal.enter();
+ for child in node.own().children() {
+ self.visit(child);
+ }
+ self.internal.exit();
+ }
- fn visit_enter(&mut self) {
- self.internal.enter();
+ _ => {
+ for child in node.own().children() {
+ self.visit(child);
+ }
+ }
+ }
}
- fn visit_exit(&mut self) {
- self.internal.exit();
+ /// Return the scope of captured variables.
+ pub fn finish(self) -> Scope {
+ self.captures
}
}