ksl 0.1.5

KSL core library and interpreter
Documentation
use crate::{Environment, is_number_eq};

#[derive(Clone)]
pub enum Value {
    Unit,
    Module(String, Environment),
    Identity(String),
    Atom(String),
    String(String),
    Number(f64),
    List(Vec<Value>),
    Lambda(Vec<String>, Box<Value>, Environment),
    Builtin(&'static str),
    Plugin(String, String),
    Object(String, Environment),
    Apply(Vec<Value>, Box<Value>),
}

impl Value {
    pub fn into_string(&self, is_list: bool) -> String {
        match self {
            Value::Unit => String::from("()"),
            Value::Module(name, binds) => format!("Module[{}, {:?}]", name, binds.keys()),
            Value::Identity(id) => format!("{}", id),
            Value::Atom(a) => format!("#{}", a),
            Value::String(s) => {
                if is_list {
                    s.clone()
                } else {
                    format!("\"{}\"", s)
                }
            }
            Value::Number(n) => format!("{}", n),
            Value::List(elements) => format!(
                "{{{}}}",
                elements
                    .iter()
                    .map(|element| format!("{}", element.into_string(true)))
                    .collect::<Vec<String>>()
                    .join(", ")
            ),
            Value::Lambda(params, _, _) => {
                format!("λ({}) => <lambda>", params.join(", "),)
            }
            Value::Builtin(name) => format!("<<{}>>", name),
            Value::Plugin(lib, name) => format!("<${}:{}>", lib, name),
            Value::Object(type_name, env) => {
                format!(
                    "#({}){{{}}}",
                    type_name,
                    env.keys().cloned().collect::<Vec<String>>().join(", ")
                )
            }
            Value::Apply(arguments, func) => format!(
                "({})[{}]",
                func.into_string(false),
                arguments
                    .iter()
                    .map(|val| format!("{}", val.into_string(false)))
                    .collect::<Vec<String>>()
                    .join(", ")
            ),
        }
    }
}

/// modules and lambdas cannot compare to each other,
/// applies will never do comparison
impl std::cmp::PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Value::Unit, Value::Unit) => true,
            (Value::Identity(id1), Value::Identity(id2)) => id1 == id2,
            (Value::Atom(a1), Value::Atom(a2)) => a1 == a2,
            (Value::String(s1), Value::String(s2)) => s1 == s2,
            (Value::Number(n1), Value::Number(n2)) => is_number_eq(*n1, *n2),
            (Value::List(v1), Value::List(v2)) => {
                v1.len() == v2.len() && v1.iter().zip(v2.iter()).all(|(e1, e2)| e1 == e2)
            }
            (Value::Builtin(n1), Value::Builtin(n2)) => n1 == n2,
            _ => false,
        }
    }
}

impl std::fmt::Debug for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Value::List(elements) => write!(
                f,
                "{{{}}}",
                elements
                    .iter()
                    .map(|element| format!("{}", element.into_string(false)))
                    .collect::<Vec<String>>()
                    .join(", ")
            ),
            e => write!(f, "{}", e.into_string(false)),
        }
    }
}

impl std::fmt::Display for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Value::String(s) => write!(f, "{}", s),
            e => write!(f, "{:?}", e),
        }
    }
}