use super::Entry;
use crate::builtins::{expect_int, expect_list, none, some};
use lex_bytecode::{List, Value};
pub(crate) const TABLE: &[Entry] = &[
("len", len),
("is_empty", is_empty),
("range", range),
("head", head),
("tail", tail),
("concat", concat),
("reverse", reverse),
("cons", cons),
("enumerate", enumerate),
];
fn owned_list(v: Option<Value>) -> Result<List, String> {
match v {
Some(Value::List(xs)) => Ok(xs),
Some(other) => Err(format!("expected List, got {other:?}")),
None => Err("missing argument".into()),
}
}
fn len(args: Vec<Value>) -> Result<Value, String> {
Ok(Value::Int(expect_list(args.first())?.len() as i64))
}
fn is_empty(args: Vec<Value>) -> Result<Value, String> {
Ok(Value::Bool(expect_list(args.first())?.is_empty()))
}
fn head(args: Vec<Value>) -> Result<Value, String> {
let xs = expect_list(args.first())?;
Ok(match xs.front() {
Some(v) => some(v.clone()),
None => none(),
})
}
fn tail(args: Vec<Value>) -> Result<Value, String> {
let mut xs = owned_list(args.into_iter().next())?;
xs.pop_front();
Ok(Value::List(xs))
}
fn range(args: Vec<Value>) -> Result<Value, String> {
let lo = expect_int(args.first())?;
let hi = expect_int(args.get(1))?;
Ok(Value::List((lo..hi).map(Value::Int).collect::<std::collections::VecDeque<_>>().into()))
}
fn concat(args: Vec<Value>) -> Result<Value, String> {
let mut it = args.into_iter();
let mut out = owned_list(it.next())?;
let rest = owned_list(it.next())?;
out.extend(rest.iter().cloned());
Ok(Value::List(out))
}
fn reverse(args: Vec<Value>) -> Result<Value, String> {
let xs = owned_list(args.into_iter().next())?;
let rev: std::collections::VecDeque<Value> = xs.into_inner().into_iter().rev().collect();
Ok(Value::List(rev.into()))
}
fn cons(args: Vec<Value>) -> Result<Value, String> {
let mut it = args.into_iter();
let head = it.next().unwrap_or(Value::Unit);
let mut tail = match it.next() {
Some(Value::List(v)) => v,
Some(other) => return Err(format!("list.cons: expected List, got {other:?}")),
None => List::new(),
};
tail.push_front(head);
Ok(Value::List(tail))
}
fn enumerate(args: Vec<Value>) -> Result<Value, String> {
let xs = expect_list(args.first())?;
let pairs = xs
.iter()
.cloned()
.enumerate()
.map(|(i, v)| Value::Tuple(vec![Value::Int(i as i64), v]))
.collect::<std::collections::VecDeque<_>>();
Ok(Value::List(pairs.into()))
}