summaryrefslogtreecommitdiff
path: root/src/eval/scope.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-30 16:19:57 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-30 16:19:57 +0100
commit5943f552e512f940d4b76055d51215c23420f03a (patch)
tree0e80936f8bda91fb03076b6548bbdace707f74f5 /src/eval/scope.rs
parent67047047e82c564d7701c3505c85db6e34223763 (diff)
Capture variable by slot instead of value 🎣
Diffstat (limited to 'src/eval/scope.rs')
-rw-r--r--src/eval/scope.rs62
1 files changed, 32 insertions, 30 deletions
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 9c966a24..70338041 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -1,9 +1,14 @@
+use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::iter;
+use std::rc::Rc;
use super::Value;
+/// A slot where a variable is stored.
+pub type Slot = Rc<RefCell<Value>>;
+
/// A stack of scopes.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Scopes<'a> {
@@ -34,38 +39,29 @@ impl<'a> Scopes<'a> {
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);
+ /// Define a constant variable in the active scope.
+ pub fn def_const(&mut self, var: impl Into<String>, value: impl Into<Value>) {
+ self.top.def_const(var, value);
}
- /// Look up the value of a variable.
- pub fn get(&self, var: &str) -> Option<&Value> {
+ /// Define a mutable variable in the active scope.
+ pub fn def_mut(&mut self, var: impl Into<String>, value: impl Into<Value>) {
+ self.top.def_mut(var, value);
+ }
+
+ /// Look up the slot of a variable.
+ pub fn get(&self, var: &str) -> Option<&Slot> {
iter::once(&self.top)
.chain(self.scopes.iter().rev())
.chain(self.base.into_iter())
.find_map(|scope| scope.get(var))
}
-
- /// Get a mutable reference to a variable.
- pub fn get_mut(&mut self, var: &str) -> Option<&mut Value> {
- iter::once(&mut self.top)
- .chain(self.scopes.iter_mut().rev())
- .find_map(|scope| scope.get_mut(var))
- }
-
- /// Return whether the variable is constant (not writable).
- ///
- /// Defaults to `false` if the variable does not exist.
- pub fn is_const(&self, var: &str) -> bool {
- self.base.map_or(false, |base| base.get(var).is_some())
- }
}
-/// A map from variable names to values.
+/// A map from variable names to variable slots.
#[derive(Default, Clone, PartialEq)]
pub struct Scope {
- values: HashMap<String, Value>,
+ values: HashMap<String, Slot>,
}
impl Scope {
@@ -74,19 +70,25 @@ impl Scope {
Self::default()
}
- /// Define a new variable.
- pub fn define(&mut self, var: impl Into<String>, value: impl Into<Value>) {
- self.values.insert(var.into(), value.into());
+ /// Define a constant variable.
+ pub fn def_const(&mut self, var: impl Into<String>, value: impl Into<Value>) {
+ let cell = RefCell::new(value.into());
+
+ // Make it impossible to write to this value again.
+ // FIXME: Use Ref::leak once stable.
+ std::mem::forget(cell.borrow());
+
+ self.values.insert(var.into(), Rc::new(cell));
}
- /// Look up the value of a variable.
- pub fn get(&self, var: &str) -> Option<&Value> {
- self.values.get(var)
+ /// Define a mutable variable.
+ pub fn def_mut(&mut self, var: impl Into<String>, value: impl Into<Value>) {
+ self.values.insert(var.into(), Rc::new(RefCell::new(value.into())));
}
- /// Get a mutable reference to a variable.
- pub fn get_mut(&mut self, var: &str) -> Option<&mut Value> {
- self.values.get_mut(var)
+ /// Look up the value of a variable.
+ pub fn get(&self, var: &str) -> Option<&Slot> {
+ self.values.get(var)
}
}