ksl 0.1.7

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

use crate::{Environment, builtin::eval_builtin, 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 [func, arguments @ ..] = &args[..] {
        let mut eval_args = Vec::with_capacity(arguments.len());
        for argument in arguments.iter() {
            if let Some((new_arg, new_env)) = eval_apply(argument, &current_environment) {
                local_environment.extend(new_env.clone());
                current_environment.extend(new_env);
                eval_args.push(new_arg);
            } else {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::apply]: ",
                        "Cannot evaluate expression {:?}."
                    ),
                    argument
                );
                return None;
            }
        }
        match eval_apply(func, &current_environment) {
            Some((Value::Identity(id), _)) => {
                if let Some(func_body) = current_environment.get(&id) {
                    eval_apply(
                        &Value::Apply(eval_args, Box::new(func_body.clone())),
                        &current_environment,
                    )
                } else {
                    eprintln!("Error[ksl::builtin::apply]: Symbol `{}` is not bound.", id);
                    None
                }
            }
            Some((lambda @ Value::Lambda(_, _, _), _)) => eval_apply(
                &Value::Apply(eval_args, Box::new(lambda)),
                &current_environment,
            ),
            Some((Value::Builtin(name), _)) => eval_builtin(name, &eval_args, &current_environment),
            Some((plugin @ Value::Plugin(_, _), _)) => eval_apply(
                &Value::Apply(arguments.to_vec(), Box::new(plugin)),
                &current_environment,
            ),
            Some((e, _)) => {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::apply]: ",
                        "`{:?}` is not an applicable value.",
                    ),
                    e
                );
                None
            }
            None => {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::apply]: ",
                        "Cannot evaluate expression {:?}."
                    ),
                    func
                );
                None
            }
        }
    } else {
        eprintln!(
            concat!(
                "Error[ksl::builtin::apply]: ",
                "Only accepts an applicable value ",
                "and a series of arbitrary values as arguments, ",
                "but {:?} were passed."
            ),
            args
        );
        None
    }
}