use mumu::parser::types::Value;
use mumu::parser::interpreter::Interpreter;
use super::common::{is_placeholder, make_three_arg_partial};
pub fn array_slice_bridge(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
match args.len() {
0 => Ok(make_three_arg_partial(do_slice, None, None, None, "array-transform-slice-partial")),
1 => {
if is_placeholder(&args[0]) {
Ok(make_three_arg_partial(do_slice, None, None, None, "array-transform-slice-partial"))
} else {
Ok(make_three_arg_partial(do_slice, Some(args[0].clone()), None, None, "array-transform-slice-partial"))
}
}
2 => {
let a1_pl = is_placeholder(&args[0]);
let a2_pl = is_placeholder(&args[1]);
Ok(make_three_arg_partial(
do_slice,
if a1_pl { None } else { Some(args[0].clone()) },
if a2_pl { None } else { Some(args[1].clone()) },
None,
"array-transform-slice-partial",
))
}
3 => {
let a1_pl = is_placeholder(&args[0]);
let a2_pl = is_placeholder(&args[1]);
let a3_pl = is_placeholder(&args[2]);
if !a1_pl && !a2_pl && !a3_pl {
do_slice(_interp, args[0].clone(), args[1].clone(), args[2].clone())
} else {
Ok(make_three_arg_partial(
do_slice,
if a1_pl { None } else { Some(args[0].clone()) },
if a2_pl { None } else { Some(args[1].clone()) },
if a3_pl { None } else { Some(args[2].clone()) },
"array-transform-slice-partial",
))
}
}
_ => Err("array:slice expects up to 3 arguments (start, end, array)".to_string()),
}
}
fn do_slice(_interp: &mut Interpreter, start: Value, end: Value, arr: Value) -> Result<Value, String> {
let start_idx = match start {
Value::Int(i) => i as isize,
Value::IntArray(ref a) if a.len() == 1 => a[0] as isize,
_ => return Err("array:slice => first arg must be int".to_string()),
};
let end_idx = match end {
Value::Int(i) => i as isize,
Value::IntArray(ref a) if a.len() == 1 => a[0] as isize,
_ => return Err("array:slice => second arg must be int".to_string()),
};
match arr {
Value::IntArray(xs) => Ok(Value::IntArray(xs.get(slice_range(xs.len(), start_idx, end_idx)).unwrap_or(&[]).to_vec())),
Value::FloatArray(xs) => Ok(Value::FloatArray(xs.get(slice_range(xs.len(), start_idx, end_idx)).unwrap_or(&[]).to_vec())),
Value::StrArray(xs) => Ok(Value::StrArray(xs.get(slice_range(xs.len(), start_idx, end_idx)).unwrap_or(&[]).to_vec())),
Value::BoolArray(xs) => Ok(Value::BoolArray(xs.get(slice_range(xs.len(), start_idx, end_idx)).unwrap_or(&[]).to_vec())),
Value::MixedArray(xs) => Ok(Value::MixedArray(xs.get(slice_range(xs.len(), start_idx, end_idx)).unwrap_or(&[]).to_vec())),
_ => Err("array:slice => third argument must be array".to_string()),
}
}
fn slice_range(len: usize, start: isize, end: isize) -> std::ops::Range<usize> {
let s = if start < 0 {
(len as isize + start).max(0) as usize
} else {
(start as usize).min(len)
};
let e = if end < 0 {
(len as isize + end).max(0) as usize
} else {
(end as usize).min(len)
};
s..e
}