use crate::{Environment, eval::apply::eval_apply, is_number_eq, value::Value};
pub(crate) fn builtin(args: &[Value], env: &Environment) -> Option<(Value, Environment)> {
if let [v1, v2, v3] = &args[..] {
match (
eval_apply(v1, env),
eval_apply(v2, env),
eval_apply(v3, env),
) {
(Some((Value::Number(start), _)), Some((Value::Number(step), _)), Some((Value::Number(bound), _))) => {
if is_number_eq(step, 0.0) && is_number_eq(start, bound) {
Some((Value::List(vec![Value::Number(start)]), Environment::new()))
} else if step * (bound - start) >= 0.0 {
let mut elements = Vec::new();
let mut current = start;
while step * (bound - current) >= 0.0 {
elements.push(Value::Number(current));
current = current + step;
}
Some((Value::List(elements), Environment::new()))
} else {
eprintln!(concat!(
"Error[ksl::builtin::range]: ",
"No terminating range."
));
None
}
}
(Some((e1, _)), Some((e2, _)), Some((e3, _))) => {
eprintln!(
concat!(
"Error[ksl::builtin::range]: ",
"Only accepts 3 numbers, but {:?} was passed."
),
(e1, e2, e3)
);
None
}
_ => {
eprintln!(
concat!(
"Error[ksl::builtin::range]: ",
"Cannot evaluate expression {:?}."
),
(v1, v2, v3)
);
None
}
}
} else {
eprintln!(
concat!(
"Error[ksl::builtin::range]: ",
"Only accepts 3 arguments, but {} were passed."
),
args.len()
);
None
}
}