diff options
Diffstat (limited to 'src/eval/capture.rs')
| -rw-r--r-- | src/eval/capture.rs | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/src/eval/capture.rs b/src/eval/capture.rs index 42b617a7..9ef55fb2 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -3,17 +3,27 @@ use std::rc::Rc; use super::*; use crate::syntax::visit::*; -/// A visitor that replaces all captured variables with their values. +/// A visitor that captures variable slots. #[derive(Debug)] pub struct CapturesVisitor<'a> { external: &'a Scopes<'a>, internal: Scopes<'a>, + captures: Scope, } impl<'a> CapturesVisitor<'a> { /// Create a new visitor for the given external scopes. pub fn new(external: &'a Scopes) -> Self { - Self { external, internal: Scopes::default() } + Self { + external, + internal: Scopes::default(), + captures: Scope::new(), + } + } + + /// Return the scope of capture variables. + pub fn finish(self) -> Scope { + self.captures } /// Define an internal variable. @@ -23,14 +33,14 @@ impl<'a> CapturesVisitor<'a> { } impl<'ast> Visit<'ast> for CapturesVisitor<'_> { - fn visit_expr(&mut self, item: &'ast mut Expr) { + fn visit_expr(&mut self, item: &'ast Expr) { match item { Expr::Ident(ident) => { // Find out whether the identifier is not locally defined, but // captured, and if so, replace it with its value. if self.internal.get(ident).is_none() { - if let Some(value) = self.external.get(ident) { - *item = Expr::Captured(Rc::clone(&value)); + if let Some(slot) = self.external.get(ident) { + self.captures.def_slot(ident.as_str(), Rc::clone(slot)); } } } @@ -38,7 +48,7 @@ impl<'ast> Visit<'ast> for CapturesVisitor<'_> { } } - fn visit_block(&mut self, item: &'ast mut ExprBlock) { + fn visit_block(&mut self, item: &'ast ExprBlock) { // Blocks create a scope except if directly in a template. if item.scopes { self.internal.push(); @@ -49,20 +59,20 @@ impl<'ast> Visit<'ast> for CapturesVisitor<'_> { } } - fn visit_template(&mut self, item: &'ast mut ExprTemplate) { + fn visit_template(&mut self, item: &'ast ExprTemplate) { // Templates always create a scope. self.internal.push(); visit_template(self, item); self.internal.pop(); } - fn visit_let(&mut self, item: &'ast mut ExprLet) { + fn visit_let(&mut self, item: &'ast ExprLet) { self.define(&item.pat.v); visit_let(self, item); } - fn visit_for(&mut self, item: &'ast mut ExprFor) { - match &mut item.pat.v { + fn visit_for(&mut self, item: &'ast ExprFor) { + match &item.pat.v { ForPattern::Value(value) => self.define(value), ForPattern::KeyValue(key, value) => { self.define(key); |
