about summary refs log tree commit diff
path: root/tvix/eval/src/vm.rs
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2022-10-09T17·18-0400
committerclbot <clbot@tvl.fyi>2022-10-10T15·34+0000
commit0b06d946062f254d8e097f7a0a0ad308b159d739 (patch)
tree766fa8b75339662af9a6463886edf7b5380783ee /tvix/eval/src/vm.rs
parentba8ec1910bf2527eb290c128a04c23f42ec6a3bb (diff)
refactor(tvix/eval): Abstract away calling functions r/5077
The process of calling a function from a builtin, especially if it's got
more than 1 arrgument, is reasonably involved and easy to get wrong due
to having to interact directly with the stack - instead of having that
done entirely manually in builtins, this wraps it up in a new
`call_with` function which handles pushing arguments onto the stack and
recursively calling the (partially applied) function.

Change-Id: I14700c639a0deca53b9a060f6d70dbc7762e9007
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6910
Autosubmit: grfn <grfn@gws.fyi>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r--tvix/eval/src/vm.rs25
1 files changed, 25 insertions, 0 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 9d28c7be1b93..b89b61f7626a 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -229,6 +229,31 @@ impl<'o> VM<'o> {
         }
     }
 
+    /// Call the given `callable` value with the given list of `args`
+    ///
+    /// # Panics
+    ///
+    /// Panics if the passed list of `args` is empty
+    #[track_caller]
+    pub fn call_with<I>(&mut self, callable: &Value, args: I) -> EvalResult<Value>
+    where
+        I: IntoIterator<Item = Value>,
+    {
+        let mut num_args = 0_usize;
+        for arg in args {
+            num_args += 1;
+            self.push(arg);
+        }
+        if num_args == 0 {
+            panic!("call_with called with an empty list of args");
+        }
+        let mut res = self.call_value(callable)?;
+        for _ in 0..(num_args - 1) {
+            res = self.call_value(&res)?;
+        }
+        Ok(res)
+    }
+
     fn tail_call_value(&mut self, callable: Value) -> EvalResult<()> {
         match callable {
             Value::Builtin(builtin) => self.call_builtin(builtin),