about summary refs log tree commit diff
path: root/tvix/eval/src/upvalues.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/upvalues.rs')
-rw-r--r--tvix/eval/src/upvalues.rs39
1 files changed, 39 insertions, 0 deletions
diff --git a/tvix/eval/src/upvalues.rs b/tvix/eval/src/upvalues.rs
new file mode 100644
index 0000000000..9287e7abdf
--- /dev/null
+++ b/tvix/eval/src/upvalues.rs
@@ -0,0 +1,39 @@
+//! This module encapsulates some logic for upvalue handling, which is
+//! relevant to both thunks (delayed computations for lazy-evaluation)
+//! as well as closures (lambdas that capture variables from the
+//! surrounding scope).
+
+use std::cell::{Ref, RefMut};
+
+use crate::{opcode::UpvalueIdx, Value};
+
+/// `UpvalueCarrier` is implemented by all types that carry upvalues.
+pub trait UpvalueCarrier {
+    fn upvalue_count(&self) -> usize;
+
+    /// Read-only accessor for the stored upvalues.
+    fn upvalues(&self) -> Ref<'_, [Value]>;
+
+    /// Mutable accessor for stored upvalues.
+    fn upvalues_mut(&self) -> RefMut<'_, Vec<Value>>;
+
+    /// Read an upvalue at the given index.
+    fn upvalue(&self, idx: UpvalueIdx) -> Ref<'_, Value> {
+        Ref::map(self.upvalues(), |v| &v[idx.0])
+    }
+
+    /// Push an upvalue at the end of the upvalue list.
+    fn push_upvalue(&self, value: Value) {
+        self.upvalues_mut().push(value);
+    }
+
+    /// Resolve deferred upvalues from the provided stack slice,
+    /// mutating them in the internal upvalue slots.
+    fn resolve_deferred_upvalues(&self, stack: &[Value]) {
+        for upvalue in self.upvalues_mut().iter_mut() {
+            if let Value::DeferredUpvalue(idx) = upvalue {
+                *upvalue = stack[idx.0].clone();
+            }
+        }
+    }
+}