From 0b06d946062f254d8e097f7a0a0ad308b159d739 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Sun, 9 Oct 2022 13:18:32 -0400 Subject: refactor(tvix/eval): Abstract away calling functions 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 Reviewed-by: tazjin Tested-by: BuildkiteCI --- tvix/eval/src/vm.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'tvix/eval/src/vm.rs') 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(&mut self, callable: &Value, args: I) -> EvalResult + where + I: IntoIterator, + { + 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), -- cgit 1.4.1