use mumu::parser::types::Value;
use mumu::parser::interpreter::Interpreter;
use mumu::parser::types::FunctionValue::RustClosure;
use std::sync::{Arc, Mutex};
fn is_placeholder(v: &Value) -> bool {
match v {
Value::Placeholder => true,
Value::SingleString(s) if s == "_" => true,
Value::StrArray(ss) if ss.len() == 1 && ss[0] == "_" => true,
_ => false,
}
}
pub fn array_join_bridge(
_interp: &mut Interpreter,
args: Vec<Value>
) -> Result<Value, String> {
match args.len() {
0 => Ok(make_partial(None, None)),
1 => {
let a = &args[0];
if is_placeholder(a) {
Ok(make_partial(None, None))
} else {
Ok(make_partial(Some(a.clone()), None))
}
}
2 => {
let sep_is_pl = is_placeholder(&args[0]);
let arr_is_pl = is_placeholder(&args[1]);
if !sep_is_pl && !arr_is_pl {
join_finalize(args[0].clone(), args[1].clone())
} else {
Ok(make_partial(
if sep_is_pl { None } else { Some(args[0].clone()) },
if arr_is_pl { None } else { Some(args[1].clone()) },
))
}
}
n => Err(format!("array:join expects up to 2 arguments (separator, array), got {}", n)),
}
}
fn make_partial(sep_opt: Option<Value>, arr_opt: Option<Value>) -> Value {
let closure = move |_interp: &mut Interpreter, call_args: Vec<Value>| {
let mut sep = sep_opt.clone();
let mut arr = arr_opt.clone();
for arg in call_args {
if sep.is_none() {
if is_placeholder(&arg) { }
else { sep = Some(arg); }
continue;
}
if arr.is_none() {
if is_placeholder(&arg) { }
else { arr = Some(arg); }
continue;
}
return Err("array:join partial: too many arguments".to_string());
}
if sep.is_some() && arr.is_some() {
join_finalize(sep.unwrap(), arr.unwrap())
} else {
Ok(make_partial(sep, arr))
}
};
Value::Function(Box::new(RustClosure(
"array:join-partial".to_string(),
Arc::new(Mutex::new(closure)),
0,
)))
}
fn join_finalize(sep_val: Value, arr_val: Value) -> Result<Value, String> {
let sep = match sep_val {
Value::SingleString(s) => s,
Value::StrArray(ref arr) if arr.len() == 1 => arr[0].clone(),
other => return Err(format!("array:join => first argument must be string separator, got {:?}", other)),
};
match &arr_val {
Value::StrArray(arr) if arr.is_empty() => return Ok(Value::SingleString("".to_string())),
Value::MixedArray(arr) if arr.is_empty() => return Ok(Value::SingleString("".to_string())),
_ => {}
}
match arr_val {
Value::StrArray(arr) => Ok(Value::SingleString(arr.join(&sep))),
Value::SingleString(s) => Ok(Value::SingleString(s)),
Value::MixedArray(items) => {
let mut strs = Vec::with_capacity(items.len());
for v in items {
match v {
Value::SingleString(s) => strs.push(s),
_ => return Err("array:join => second argument must be all strings (StrArray, string, or MixedArray of strings)".to_string()),
}
}
Ok(Value::SingleString(strs.join(&sep)))
}
Value::IntArray(arr) if arr.is_empty() => Ok(Value::SingleString("".to_string())),
Value::BoolArray(arr) if arr.is_empty() => Ok(Value::SingleString("".to_string())),
other => Err(format!("array:join => second argument must be StrArray, string, or MixedArray of strings, got {:?}", other)),
}
}