summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-27 11:50:51 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-27 11:50:51 +0100
commitce8138c68557a2d158424a8aa6056d73ff9cb1ba (patch)
treea90616fc9194a6814e9a36493e38c6efb65af7e3 /src/eval
parent710f88ccb2bceb9851a8fb0b7f131343ee33dbd5 (diff)
Scope variables in blocks 🏔️
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/mod.rs9
-rw-r--r--src/eval/scope.rs19
2 files changed, 25 insertions, 3 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index e04879d2..cadffef5 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -210,10 +210,19 @@ impl Eval for Spanned<&ExprBlock> {
type Output = Value;
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
+ if self.v.scopes {
+ ctx.scopes.push();
+ }
+
let mut output = Value::None;
for expr in &self.v.exprs {
output = expr.eval(ctx);
}
+
+ if self.v.scopes {
+ ctx.scopes.pop();
+ }
+
output
}
}
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index ed4edbb9..1ed34f86 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -4,7 +4,7 @@ use std::iter;
use super::Value;
-/// A hierarchy of scopes.
+/// A stack of scopes.
#[derive(Debug, Clone, PartialEq)]
pub struct Scopes<'a> {
/// The active scope.
@@ -21,6 +21,19 @@ impl<'a> Scopes<'a> {
Self { top: Scope::new(), scopes: vec![], base }
}
+ /// Push a new scope.
+ pub fn push(&mut self) {
+ self.scopes.push(std::mem::take(&mut self.top));
+ }
+
+ /// Pop the topmost scope.
+ ///
+ /// # Panics
+ /// Panics if no scope was pushed.
+ pub fn pop(&mut self) {
+ self.top = self.scopes.pop().expect("no pushed scope");
+ }
+
/// Define a variable in the active scope.
pub fn define(&mut self, var: impl Into<String>, value: impl Into<Value>) {
self.top.define(var, value);
@@ -29,7 +42,7 @@ impl<'a> Scopes<'a> {
/// Look up the value of a variable.
pub fn get(&self, var: &str) -> Option<&Value> {
iter::once(&self.top)
- .chain(&self.scopes)
+ .chain(self.scopes.iter().rev())
.chain(iter::once(self.base))
.find_map(|scope| scope.get(var))
}
@@ -37,7 +50,7 @@ impl<'a> Scopes<'a> {
/// Get a mutable reference to a variable.
pub fn get_mut(&mut self, var: &str) -> Option<&mut Value> {
iter::once(&mut self.top)
- .chain(&mut self.scopes)
+ .chain(self.scopes.iter_mut().rev())
.find_map(|scope| scope.get_mut(var))
}