use mumu::{
Interpreter,
Value,
};
use std::sync::{Arc, Mutex};
pub fn array_append_bridge(
_interp: &mut Interpreter,
mut args: Vec<Value>
) -> Result<Value, String> {
match args.len() {
0 => {
Ok(make_append_partial(None, None))
}
1 => {
let val = args.remove(0);
if let Value::Placeholder = val {
Ok(make_append_partial(None, None))
} else {
Ok(make_append_partial(Some(val), None))
}
}
2 => {
let item_val = args.remove(0);
let list_val = args.remove(0);
let item_is_pl = matches!(item_val, Value::Placeholder);
let list_is_pl = matches!(list_val, Value::Placeholder);
if item_is_pl || list_is_pl {
let maybe_item = if item_is_pl { None } else { Some(item_val) };
let maybe_list = if list_is_pl { None } else { Some(list_val) };
Ok(make_append_partial(maybe_item, maybe_list))
} else {
do_append(item_val, list_val)
}
}
n => {
Err(format!("array:append => expected up to 2 arguments, got {}", n))
}
}
}
fn make_append_partial(
item_opt: Option<Value>,
list_opt: Option<Value>,
) -> Value {
use mumu::parser::types::FunctionValue::RustClosure;
let closure = move |_interp: &mut Interpreter, new_args: Vec<Value>| {
let mut item = item_opt.clone();
let mut lst = list_opt.clone();
for arg in new_args {
if item.is_none() {
if let Value::Placeholder = arg {
} else {
item = Some(arg);
}
continue;
}
if lst.is_none() {
if let Value::Placeholder = arg {
} else {
lst = Some(arg);
}
continue;
}
return Err("array:append => partial => too many arguments".to_string());
}
if item.is_some() && lst.is_some() {
do_append(item.unwrap(), lst.unwrap())
} else {
Ok(make_append_partial(item, lst))
}
};
Value::Function(Box::new(RustClosure(
"array:append-partial".to_string(),
Arc::new(Mutex::new(closure)),
0,
)))
}
fn do_append(item: Value, list_val: Value) -> Result<Value, String> {
match list_val {
Value::IntArray(xs) => match item {
Value::Int(i) => {
let mut new_xs = xs.clone();
new_xs.push(i);
Ok(Value::IntArray(new_xs))
}
_ => Err("array:append => cannot append non-Int to IntArray".to_string()),
},
Value::StrArray(ss) => match item {
Value::SingleString(s) => {
let mut new_ss = ss.clone();
new_ss.push(s);
Ok(Value::StrArray(new_ss))
}
_ => Err("array:append => cannot append non-SingleString to StrArray".to_string()),
},
Value::BoolArray(bb) => match item {
Value::Bool(b) => {
let mut new_bb = bb.clone();
new_bb.push(b);
Ok(Value::BoolArray(new_bb))
}
_ => Err("array:append => cannot append non-Bool to BoolArray".to_string()),
},
Value::SingleString(st) => match item {
Value::SingleString(x) => {
Ok(Value::SingleString(format!("{}{}", st, x)))
}
_ => Err("array:append => cannot append non-SingleString to SingleString".to_string()),
},
other => Err(format!("array:append => cannot append to {:?}", other)),
}
}