use crate::apply::do_map;
use mumu::{
parser::types::FunctionValue::RustClosure,
parser::types::Value,
Interpreter,
};
use std::sync::{Arc, Mutex};
pub fn array_map_bridge(
interp: &mut Interpreter,
mut args: Vec<Value>
) -> Result<Value, String> {
match args.len() {
0 => Ok(make_two_arg_partial(None, None)),
1 => {
let first = args.remove(0);
match first {
Value::Placeholder => Ok(make_two_arg_partial(None, None)),
Value::Function(_) => Ok(make_two_arg_partial(Some(first), None)),
other => Ok(make_two_arg_partial(None, Some(other))),
}
}
2 => {
let v1 = args.remove(0);
let v2 = args.remove(0);
let v1_is_pl = matches!(v1, Value::Placeholder);
let v2_is_pl = matches!(v2, Value::Placeholder);
if !v1_is_pl && !v2_is_pl {
do_map_final(interp, &v1, &v2)
} else {
let maybe_func = if v1_is_pl { None } else { Some(v1) };
let maybe_data = if v2_is_pl { None } else { Some(v2) };
Ok(make_two_arg_partial(maybe_func, maybe_data))
}
}
n => Err(format!("array:map => expected up to 2 arguments, got {}", n)),
}
}
fn do_map_final(
interp: &mut Interpreter,
func_val: &Value,
data_val: &Value
) -> Result<Value, String> {
let func_boxed = match func_val {
Value::Function(fb) => fb,
other => return Err(format!(
"array:map => first argument must be a Function(...), got {:?}",
other
)),
};
if let Value::Tensor(_) = data_val {
return Err("array:map => does not support Tensors yet".to_string());
}
do_map(interp, func_boxed, data_val.clone())
}
fn make_two_arg_partial(
func_opt: Option<Value>,
data_opt: Option<Value>
) -> Value {
Value::Function(Box::new(RustClosure(
"array:map-partial".to_string(),
Arc::new(Mutex::new(move |interp: &mut Interpreter, new_args: Vec<Value>| {
let mut f_current = func_opt.clone();
let mut d_current = data_opt.clone();
for arg in new_args {
if f_current.is_none() {
if matches!(arg, Value::Placeholder) {
} else {
f_current = Some(arg);
}
continue;
}
if d_current.is_none() {
if matches!(arg, Value::Placeholder) {
} else {
d_current = Some(arg);
}
continue;
}
return Err("array:map => partial => too many arguments".to_string());
}
if f_current.is_some() && d_current.is_some() {
do_map_final(
interp,
f_current.as_ref().unwrap(),
d_current.as_ref().unwrap()
)
} else {
Ok(make_two_arg_partial(f_current, d_current))
}
})),
0,
)))
}