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}