ksl 0.1.30

KSL core library and interpreter
Documentation
//! # ksl::builtin::apply
//!
//! Built-in functions which accept multiple arguments.
//!
//! - Add
//! - Concat
//! - Mul

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()
        )))
    }
}