diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-01-27 11:50:51 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-01-27 11:50:51 +0100 |
| commit | ce8138c68557a2d158424a8aa6056d73ff9cb1ba (patch) | |
| tree | a90616fc9194a6814e9a36493e38c6efb65af7e3 /src/eval | |
| parent | 710f88ccb2bceb9851a8fb0b7f131343ee33dbd5 (diff) | |
Scope variables in blocks 🏔️
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/mod.rs | 9 | ||||
| -rw-r--r-- | src/eval/scope.rs | 19 |
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)) } |
