ksl 0.1.7

KSL core library and interpreter
Documentation
//! # ksl::builtin::while_
//!
//! Built-in function `While`.

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, &current_environment) {
            match e {
                Value::Atom(p) if &p == TRUE_SYMBOL => match eval_apply(func, &current_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
    }
}