summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-02-07 13:39:05 +0100
committerLaurenz <laurmaedje@gmail.com>2021-02-07 13:39:05 +0100
commite35bbfffcb1f84b2fb0679759152ca0a5eabfad4 (patch)
tree28123506b60be4e90ec611f8f3f9bb0ab5bec2f6 /src/eval
parent062d99f70fe5eed0fbc81182565b51360495e465 (diff)
Remove captured expression 🗑️
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/capture.rs30
-rw-r--r--src/eval/mod.rs15
-rw-r--r--src/eval/scope.rs5
3 files changed, 30 insertions, 20 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);
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index cfd1c808..e49f7779 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -194,7 +194,6 @@ impl Eval for Spanned<&Expr> {
Expr::Let(v) => v.with_span(self.span).eval(ctx),
Expr::If(v) => v.with_span(self.span).eval(ctx),
Expr::For(v) => v.with_span(self.span).eval(ctx),
- Expr::Captured(v) => v.borrow().clone(),
}
}
}
@@ -344,21 +343,17 @@ impl Spanned<&ExprBinary> {
let rhs = self.v.rhs.eval(ctx);
let span = self.v.lhs.span;
- let slot = match &self.v.lhs.v {
- Expr::Ident(id) => match ctx.scopes.get(id) {
+ let slot = if let Expr::Ident(id) = &self.v.lhs.v {
+ match ctx.scopes.get(id) {
Some(slot) => slot,
None => {
ctx.diag(error!(span, "unknown variable"));
return Value::Error;
}
- },
-
- Expr::Captured(slot) => slot,
-
- _ => {
- ctx.diag(error!(span, "cannot assign to this expression"));
- return Value::Error;
}
+ } else {
+ ctx.diag(error!(span, "cannot assign to this expression"));
+ return Value::Error;
};
let (constant, err, value) = if let Ok(mut inner) = slot.try_borrow_mut() {
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 70338041..8f2bd1d5 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -86,6 +86,11 @@ impl Scope {
self.values.insert(var.into(), Rc::new(RefCell::new(value.into())));
}
+ /// Define a variable with a slot.
+ pub fn def_slot(&mut self, var: impl Into<String>, slot: Slot) {
+ self.values.insert(var.into(), slot);
+ }
+
/// Look up the value of a variable.
pub fn get(&self, var: &str) -> Option<&Slot> {
self.values.get(var)