use crate::lang::adapter::Adapter;
use crate::lang::args::eval_args;
use crate::lang::arity::Arity;
use crate::lang::arity::assert_func_arity;
use crate::lang::error::Error;
use crate::lang::machine::Machine;
use crate::lang::node::Node;
use crate::value::Value;
use crate::value::list::List;
pub(crate) fn slice(
adapter: &impl Adapter,
machine: &mut Machine<'_>,
stdin: Option<&Value>,
node: Node,
) -> Result<Value, Error> {
assert_func_arity(adapter, machine, stdin, &node, &Arity::minmax(2, 3))?;
let mut args = eval_args(adapter, machine, stdin, node)?;
let list = args.pop().flatten().unwrap_or_default().into_parts();
let len = list.len();
let arg1 = pop_isize_arg(&mut args);
let arg0 = pop_isize_arg(&mut args);
let index0 = arg0.map(|a| resolve_reverse_arg(a, len));
let index1 = arg1.map(|a| resolve_reverse_arg(a, len));
let (start, end) = match (index0, index1) {
(None, None) => (0, 0),
(None, Some(a1)) => (a1, len),
(Some(a0), None) => (a0, len),
(Some(a0), Some(a1)) => (a0, a1),
};
let get0 = start.min(end);
let get1 = end.min(len);
let list = list.data.get(get0..get1).unwrap_or_default();
let list = Value::from(List::from(list.to_vec()));
Ok(list)
}
fn pop_isize_arg(args: &mut Vec<Option<Value>>) -> Option<isize> {
args.pop()
.flatten()
.as_ref()
.and_then(Value::as_number)
.and_then(|a| isize::try_from(a).ok())
}
fn resolve_reverse_arg(mut index: isize, len: usize) -> usize {
if index < 0 {
index = isize::try_from(len)
.unwrap_or_default()
.saturating_sub(index.abs());
}
usize::try_from(index).unwrap_or_default()
}