use crate::{Environment, FALSE_SYMBOL, TRUE_SYMBOL, eval::apply::eval_apply, value::Value};
pub(crate) fn builtin(args: &[Value], env: &Environment) -> Option<(Value, Environment)> {
let mut current_environment = env.clone();
let mut local_environment = Environment::new();
if let [pred, func @ Value::List(_)] = &args[..] {
let mut final_result = Value::Unit;
while let Some((e, _)) = eval_apply(pred, ¤t_environment) {
match e {
Value::Atom(p) if &p == TRUE_SYMBOL => match eval_apply(func, ¤t_environment) {
Some((result, new_env)) => {
local_environment.extend(new_env.clone());
current_environment.extend(new_env);
final_result = result;
}
None => {
eprintln!(
concat!(
"Error[ksl::builtin::while]: ",
"Cannot evaluate expression {:?}."
),
func
);
return None;
}
},
Value::Atom(p) if &p == FALSE_SYMBOL => break,
_ => {
eprintln!(
concat!(
"Error[ksl::builtin::while]: ",
"Expected a boolean, but got `{:?}`."
),
e
);
return None;
}
}
}
Some((final_result, local_environment))
} else {
eprintln!(
concat!(
"Error[ksl::builtin::while]: ",
"Only accepts a predicate expression ",
"and a list of expressions as arguments, but got `{:?}`."
),
args
);
None
}
}