use crate::{Environment, builtin::MultiFunctionType, eval::apply::eval_apply, value::Value};
pub(crate) fn builtin(args: &[Value], func_type: MultiFunctionType, env: Environment) -> Result<Value, std::sync::Arc<str>> {
if let [v1, rest @ ..] = args {
match (eval_apply(v1, env.clone())?, &func_type) {
(Value::Number(n1), MultiFunctionType::Add) => {
let mut result = n1;
for val in rest.iter() {
match eval_apply(val, env.clone())? {
Value::Number(n) => result += n,
e => {
return Err(std::sync::Arc::from(format!(
concat!("Error[ksl::builtin::{:?}]: ", "Unexpected value: `{}`."),
func_type, e
)));
}
}
}
Ok(Value::Number(result))
}
(Value::Number(n1), MultiFunctionType::Mul) => {
let mut result = n1;
for val in rest.iter() {
match eval_apply(val, env.clone())? {
Value::Number(n) => result *= n,
e => {
return Err(std::sync::Arc::from(format!(
concat!("Error[ksl::builtin::{:?}]: ", "Unexpected value: `{}`."),
func_type, e
)));
}
}
}
Ok(Value::Number(result))
}
(Value::String(s1), MultiFunctionType::Concat) => {
let mut result = s1.to_string();
for val in rest.iter() {
match eval_apply(val, env.clone())? {
Value::String(s) => result.push_str(&s),
e => {
return Err(std::sync::Arc::from(format!(
concat!(
"Error[ksl::builtin::{:?}]: ",
"Expected a string, but got: `{}`."
),
func_type, e
)));
}
}
}
Ok(Value::String(std::sync::Arc::from(result)))
}
(Value::List(lst1), MultiFunctionType::Concat) => {
let mut result = lst1.to_vec();
for val in rest.iter() {
match eval_apply(val, env.clone())? {
Value::List(lst) => result.extend_from_slice(&lst),
e => {
return Err(std::sync::Arc::from(format!(
concat!(
"Error[ksl::builtin::{:?}]: ",
"Expected a list, but got: `{}`."
),
func_type, e
)));
}
}
}
Ok(Value::List(std::sync::Arc::from(result)))
}
(e @ (Value::String(_) | Value::List(_)), MultiFunctionType::Add | MultiFunctionType::Mul) => {
Err(std::sync::Arc::from(format!(
concat!("Error[ksl::builtin::{:?}]: ", "Unexpected value: `{}`."),
func_type, e
)))
}
(e @ Value::Number(_), MultiFunctionType::Concat) => Err(std::sync::Arc::from(format!(
concat!("Error[ksl::builtin::{:?}]: ", "Unexpected value: `{}`."),
func_type, e
))),
(e, _) => Err(std::sync::Arc::from(format!(
concat!("Error[ksl::builtin::{:?}]: ", "Unexpected value: `{}`."),
func_type, e
))),
}
} else {
Err(std::sync::Arc::from(format!(
concat!(
"Error[ksl::builtin::{:?}]: ",
"Expected at least 1 parameter, but {} were passed."
),
func_type,
args.len()
)))
}
}