1use crate::{Dict, Environment, Scope, builtin::eval_builtin, eval::plugin::apply_plugin, read_from_environment, value::Value};
3
4pub fn eval_apply(val: &Value, env: Environment) -> Result<Value, std::sync::Arc<str>> {
32 match val {
33 Value::List(contents) => Ok(Value::List(
35 contents
36 .iter()
37 .map(|content| eval_apply(content, env.clone()))
38 .collect::<Result<std::sync::Arc<[Value]>, std::sync::Arc<str>>>()?,
39 )),
40 Value::Apply(args, func_expr) => {
42 let func_value = eval_apply(func_expr, env.clone())?;
43 match func_value {
44 Value::Builtin(name) => eval_builtin(name, args, env),
45 Value::Lambda(params, func_body, cap) => {
46 if args.len() != params.len() {
47 return Err(std::sync::Arc::from(format!(
48 "Error[ksl::eval::apply::eval_apply]: Expected {} parameter(s), but {} were passed.",
49 params.len(),
50 args.len()
51 )));
52 }
53 let mut eval_args = Vec::with_capacity(args.len());
55 for arg in args.iter() {
56 eval_args.push(std::sync::Arc::new(eval_apply(arg, env.clone())?));
57 }
58 let mut local_store = Dict::with_capacity_and_hasher(params.len(), rustc_hash::FxBuildHasher);
60 for (param_name, arg_val) in params.iter().zip(eval_args) {
61 local_store.insert(param_name.clone(), arg_val);
62 }
63 let exec_env = std::sync::Arc::new(Scope {
64 store: parking_lot::RwLock::new(local_store),
65 parent: Some(cap.clone()),
66 });
67
68 eval_apply(&func_body, exec_env)
69 }
70
71 Value::Plugin(lib, name) => apply_plugin(&lib, &name, args, env),
72 _ => Err(std::sync::Arc::from(format!(
73 "Error[ksl::eval::apply::eval_apply]: Value `{}` is not callable.",
74 func_value
75 ))),
76 }
77 }
78 Value::Symbol(sym) => match read_from_environment(&env, sym) {
80 Some(val) => Ok(val.as_ref().clone()),
81 None => Err(std::sync::Arc::from(format!(
82 "Error[ksl::eval::apply::eval_apply]: Unknown symbol `{}`.",
83 sym
84 ))),
85 },
86 _ => Ok(val.clone()),
87 }
88}