use mumu::{
Interpreter,
Value,
};
use crate::apply::apply_n_ary_function_value;
use std::sync::{Arc, Mutex};
pub fn array_each_bridge(
interp: &mut Interpreter,
args: Vec<Value>
) -> Result<Value, String> {
match args.len() {
0 => {
Ok(make_two_arg_partial(None, None))
}
1 => {
let val = &args[0];
if matches!(val, Value::Placeholder) {
Ok(make_two_arg_partial(None, None))
} else {
Ok(make_two_arg_partial(Some(val.clone()), None))
}
}
2 => {
let a = &args[0];
let b = &args[1];
let a_is_pl = matches!(a, Value::Placeholder);
let b_is_pl = matches!(b, Value::Placeholder);
if a_is_pl || b_is_pl {
let a_opt = if a_is_pl { None } else { Some(a.clone()) };
let b_opt = if b_is_pl { None } else { Some(b.clone()) };
Ok(make_two_arg_partial(a_opt, b_opt))
} else {
do_each(interp, &args[0], &args[1])
}
}
n => Err(format!("array:each => expected up to 2 arguments, got {}", n)),
}
}
fn do_each(
interp: &mut Interpreter,
func_val: &Value,
data_val: &Value
) -> Result<Value, String> {
let f_boxed = match func_val {
Value::Function(fb) => fb.clone(),
other => return Err(format!("array:each => first arg must be Function(...), got {:?}", other)),
};
match data_val {
Value::IntArray(xs) => {
for &x in xs {
let _ = apply_n_ary_function_value(interp, f_boxed.clone(), vec![Value::Int(x)])?;
}
Ok(Value::IntArray(xs.clone()))
}
Value::StrArray(ss) => {
for s in ss {
let _ = apply_n_ary_function_value(interp, f_boxed.clone(), vec![Value::SingleString(s.clone())])?;
}
Ok(Value::StrArray(ss.clone()))
}
Value::BoolArray(bb) => {
for &b in bb {
let _ = apply_n_ary_function_value(interp, f_boxed.clone(), vec![Value::Bool(b)])?;
}
Ok(Value::BoolArray(bb.clone()))
}
Value::FloatArray(ff) => {
for &f in ff {
let _ = apply_n_ary_function_value(interp, f_boxed.clone(), vec![Value::Float(f)])?;
}
Ok(Value::FloatArray(ff.clone()))
}
Value::MixedArray(items) => {
for item in items {
let _ = apply_n_ary_function_value(interp, f_boxed.clone(), vec![item.clone()])?;
}
Ok(Value::MixedArray(items.clone()))
}
other => Err(format!("array:each => second arg must be array (including MixedArray), got {:?}", other)),
}
}
fn make_two_arg_partial(
fn_opt: Option<Value>,
data_opt: Option<Value>
) -> Value {
use mumu::parser::types::FunctionValue::RustClosure;
let closure = move |interp: &mut Interpreter, new_args: Vec<Value>| {
let mut f_cur = fn_opt.clone();
let mut d_cur = data_opt.clone();
for arg in new_args {
if f_cur.is_none() {
if matches!(arg, Value::Placeholder) {
} else {
f_cur = Some(arg);
}
continue;
}
if d_cur.is_none() {
if matches!(arg, Value::Placeholder) {
} else {
d_cur = Some(arg);
}
continue;
}
return Err("array:each => partial => too many arguments".to_string());
}
if f_cur.is_some() && d_cur.is_some() {
do_each(
interp,
f_cur.as_ref().unwrap(),
d_cur.as_ref().unwrap()
)
} else {
Ok(make_two_arg_partial(f_cur, d_cur))
}
};
Value::Function(Box::new(RustClosure(
"array:each-partial".to_string(),
Arc::new(Mutex::new(closure)),
0,
)))
}