Skip to main content

runmat_vm/call/
feval.rs

1use crate::bytecode::UserFunction;
2use crate::call::user::try_builtin_fallback_single;
3use crate::interpreter::runner::dynamic_user_functions_snapshot;
4use runmat_builtins::{Closure, Value};
5use runmat_runtime::RuntimeError;
6use std::collections::HashMap;
7
8pub fn closure_call_args(closure: &Closure, args: Vec<Value>) -> (String, Vec<Value>) {
9    let name = closure.function_name.clone();
10    let mut call_args = closure.captures.clone();
11    call_args.extend(args);
12    (name, call_args)
13}
14
15pub async fn forward_builtin_feval(
16    func_value: Value,
17    args: Vec<Value>,
18) -> Result<Value, RuntimeError> {
19    let mut argv = Vec::with_capacity(1 + args.len());
20    argv.push(func_value);
21    argv.extend(args);
22    runmat_runtime::call_builtin_async("feval", &argv).await
23}
24
25pub async fn try_closure_builtin_fallback(
26    name: &str,
27    call_args: &[Value],
28) -> Result<Option<Value>, RuntimeError> {
29    try_builtin_fallback_single(name, call_args).await
30}
31
32pub enum FevalDispatch {
33    Completed(Value),
34    InvokeUser {
35        name: String,
36        args: Vec<Value>,
37        functions: HashMap<String, UserFunction>,
38    },
39}
40
41pub async fn execute_feval(
42    func_val: Value,
43    args: Vec<Value>,
44    context_functions: &HashMap<String, UserFunction>,
45    bytecode_functions: &HashMap<String, UserFunction>,
46) -> Result<FevalDispatch, RuntimeError> {
47    match func_val {
48        Value::Closure(c) => {
49            let (name, call_args) = closure_call_args(&c, args);
50            if let Some(result) = try_closure_builtin_fallback(&name, &call_args).await? {
51                return Ok(FevalDispatch::Completed(result));
52            }
53            let mut functions = bytecode_functions.clone();
54            for (k, v) in context_functions {
55                functions.insert(k.clone(), v.clone());
56            }
57            for (k, v) in dynamic_user_functions_snapshot() {
58                functions.insert(k, v);
59            }
60            Ok(FevalDispatch::InvokeUser {
61                name,
62                args: call_args,
63                functions,
64            })
65        }
66        other => Ok(FevalDispatch::Completed(
67            forward_builtin_feval(other, args).await?,
68        )),
69    }
70}