ksl 0.1.7

KSL core library and interpreter
Documentation
//! # ksl::builtin
//!
//! Defines the constants and functions built into KSL
//! and the associated evaluation functions.

mod ano;
mod apply;
mod bimath;
mod block;
mod do_;
mod eq;
mod fun;
mod get;
mod get_type;
mod glt;
mod has;
mod head;
mod if_;
mod index;
mod is;
mod length;
mod let_;
mod load;
mod math;
mod module;
mod multi;
mod not;
mod pend;
mod plugin;
mod print;
mod range;
mod read;
mod set;
mod string_case;
mod substring;
mod tail;
mod to_string;
mod use_;
mod while_;
mod write;

use crate::{Environment, value::Value};

/// KSL file extension.
const FILE_EXT: &'static str = "ksl";
/// Literal value corresponding to the boolean true in Atom.
pub const TRUE_SYMBOL: &'static str = "t";
/// Literal value corresponding to the boolean false in Atom.
pub const FALSE_SYMBOL: &'static str = "f";
/// Literal value of the KSL_PATH environment variable.
pub const KSL_PATH_ENV: &'static str = "KSL_PATH";
pub(crate) const DEFAULT_KSL_PATH: &'static str = "~/.local/share/ksl";
/// Imported module path list in environment as key's literal value.
pub const MODULE_PATH_ENV: &'static str = "MODULE_PATH";
/// Module name in environment as key's literal value.
pub const MODULE_NAME_ENV: &'static str = "MODULE_NAME";
/// List of built-in functions.
pub const BULTIN_FUNCTIONS: [&'static str; 64] = [
    "Abs",
    "Add",
    "And",
    "Append",
    "Apply",
    "Block",
    "Concat",
    "Cos",
    "Cosh",
    "Div",
    "Do",
    "Eq",
    "Exp",
    "Fun",
    "Get",
    "GetType",
    "Greater",
    "Has",
    "Head",
    "If",
    "Index",
    "IsAtom",
    "IsBuiltin",
    "IsInteger",
    "IsLambda",
    "IsList",
    "IsNumber",
    "IsObject",
    "IsPlugin",
    "IsString",
    "IsUnit",
    "Length",
    "Less",
    "Let",
    "Ln",
    "Load",
    "Lowercase",
    "Module",
    "Mul",
    "Neg",
    "Not",
    "Object",
    "Or",
    "Plugin",
    "Power",
    "Prepend",
    "Print",
    "Range",
    "Read",
    "Set",
    "Sin",
    "Sinh",
    "Sub",
    "SubString",
    "Tail",
    "Tan",
    "Tanh",
    "ToString",
    "Trunc",
    "Unit",
    "Uppercase",
    "Use",
    "While",
    "Write",
];

#[derive(Debug)]
enum MathFunctionType {
    Abs,
    Cos,
    Cosh,
    Exp,
    Ln,
    Neg,
    Sin,
    Sinh,
    Tan,
    Tanh,
    Trunc,
}

#[derive(Debug)]
enum MultiFunctionType {
    Add,
    Concat,
    Mul,
}

#[derive(Debug)]
enum BiMathFunctionType {
    Div,
    Power,
    Sub,
}

#[derive(Debug)]
enum ValueType {
    Atom,
    Builtin,
    Integer,
    Lambda,
    List,
    Number,
    Object,
    Plugin,
    String,
    Unit,
}

/// Evaluate built-in functions.
pub(crate) fn eval_builtin(symbol: &str, args: &[Value], env: &Environment) -> Option<(Value, Environment)> {
    match symbol {
        "Abs" => math::builtin(args, MathFunctionType::Abs, env),
        "Add" => multi::builtin(args, MultiFunctionType::Add, env),
        "And" => ano::builtin(args, true, env),
        "Append" => pend::builtin(args, false, env),
        "Apply" => apply::builtin(args, env),
        "Block" => block::builtin(args, env),
        "Concat" => multi::builtin(args, MultiFunctionType::Concat, env),
        "Cos" => math::builtin(args, MathFunctionType::Cos, env),
        "Cosh" => math::builtin(args, MathFunctionType::Cosh, env),
        "Div" => bimath::builtin(args, BiMathFunctionType::Div, env),
        "Do" => do_::builtin(args, env),
        "Eq" => eq::builtin(args, env),
        "Exp" => math::builtin(args, MathFunctionType::Exp, env),
        "Fun" => fun::builtin(args, env),
        "Get" => get::builtin(args, env),
        "GetType" => get_type::builtin(args, env),
        "Greater" => glt::builtin(args, true, env),
        "Has" => has::builtin(args, env),
        "Head" => head::builtin(args, env),
        "If" => if_::builtin(args, env),
        "Index" => index::builtin(args, env),
        "IsAtom" => is::builtin(args, ValueType::Atom, env),
        "IsBuiltin" => is::builtin(args, ValueType::Builtin, env),
        "IsInteger" => is::builtin(args, ValueType::Integer, env),
        "IsLambda" => is::builtin(args, ValueType::Lambda, env),
        "IsList" => is::builtin(args, ValueType::List, env),
        "IsNumber" => is::builtin(args, ValueType::Number, env),
        "IsObject" => is::builtin(args, ValueType::Object, env),
        "IsPlugin" => is::builtin(args, ValueType::Plugin, env),
        "IsString" => is::builtin(args, ValueType::String, env),
        "IsUnit" => is::builtin(args, ValueType::Unit, env),
        "Length" => length::builtin(args, env),
        "Less" => glt::builtin(args, false, env),
        "Let" => let_::builtin(args, env),
        "Ln" => math::builtin(args, MathFunctionType::Ln, env),
        "Load" => load::builtin(args, env),
        "Lowercase" => string_case::builtin(args, false, env),
        "Module" => module::builtin(args, env),
        "Mul" => multi::builtin(args, MultiFunctionType::Mul, env),
        "Neg" => math::builtin(args, MathFunctionType::Neg, env),
        "Not" => not::builtin(args, env),
        "Object" => {
            if let [Value::Identity(type_name)] = &args[..] {
                Some((
                    Value::Object(type_name.clone(), Environment::new()),
                    Environment::new(),
                ))
            } else {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::Object]: ",
                        "Only accepts a symbol as argument, ",
                        "but {:?} were passed."
                    ),
                    args
                );
                None
            }
        }
        "Or" => ano::builtin(args, false, env),
        "Plugin" => plugin::builtin(args, env),
        "Power" => bimath::builtin(args, BiMathFunctionType::Power, env),
        "Prepend" => pend::builtin(args, true, env),
        "Print" => print::builtin(args, env),
        "Range" => range::builtin(args, env),
        "Read" => read::builtin(args, env),
        "Set" => set::builtin(args, env),
        "Sin" => math::builtin(args, MathFunctionType::Sin, env),
        "Sinh" => math::builtin(args, MathFunctionType::Sinh, env),
        "Sub" => bimath::builtin(args, BiMathFunctionType::Sub, env),
        "SubString" => substring::builtin(args, env),
        "Tail" => tail::builtin(args, env),
        "Tan" => math::builtin(args, MathFunctionType::Tan, env),
        "Tanh" => math::builtin(args, MathFunctionType::Tanh, env),
        "ToString" => to_string::builtin(args, env),
        "Trunc" => math::builtin(args, MathFunctionType::Trunc, env),
        "Unit" => {
            // Unit.
            if args.is_empty() {
                Some((Value::Unit, Environment::new()))
            } else {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::Unit]: ",
                        "Only accepts 0 arguments, ",
                        "but {} were passed."
                    ),
                    args.len()
                );
                None
            }
        }
        "Uppercase" => string_case::builtin(args, true, env),
        "Use" => use_::builtin(args, env),
        "While" => while_::builtin(args, env),
        "Write" => write::builtin(args, env),
        builtin_name => {
            eprintln!(
                concat!(
                    "Error[ksl::builtin::eval_builtin]: ",
                    "Built-in function `{}` is not implemented yet."
                ),
                builtin_name
            );
            None
        }
    }
}