use std::{hash::Hash, rc::Rc};
use ordered_float::OrderedFloat;
use ordered_hash_map::OrderedHashMap;
use crate::parser::Atom;
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Value {
Int(i64),
UInt(u64),
Float(OrderedFloat<f64>),
Null,
Bool(bool),
Bytes(Rc<Vec<u8>>),
String(Rc<String>),
Map(Rc<OrderedHashMap<Value, Value>>),
List(Rc<Vec<Value>>),
Function(Rc<FnValue>)
}
#[derive(PartialEq, Eq, Debug)]
pub struct FnValue {
pub name: &'static str,
pub overloads: &'static [Overload],
}
pub type Func = fn(lhs: &Value, rhs: &Value) -> Value;
#[derive(PartialEq, Eq, Debug)]
pub struct Overload {
pub key: &'static str,
pub func: Func
}
impl Into<bool> for Value {
fn into(self) -> bool {
match self {
Value::Int(v) => v != 0,
Value::UInt(v) => v != 0,
Value::Float(v) => v != 0.0,
Value::Null => false,
Value::Bool(v) => v,
Value::Bytes(v) => v.len() > 0,
Value::String(v) => v.len() > 0,
Value::Map(v) => v.len() > 0,
Value::List(v) => v.len() > 0,
Value::Function(_) => true,
}
}
}
impl Hash for Value {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);
}
}
impl From<Atom> for Value {
fn from(atom: Atom) -> Self {
match atom {
Atom::Int(i) => Value::Int(i),
Atom::UInt(ui) => Value::UInt(ui),
Atom::Float(f) => Value::Float(f.into()),
Atom::Bool(b) => Value::Bool(b),
Atom::Null => Value::Null,
Atom::Bytes(b) => Value::Bytes(b),
Atom::String(s) => Value::String(s),
}
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Int(v) => write!(f, "int({})", v),
Value::UInt(v) => write!(f, "uint({})", v),
Value::Float(v) => write!(f, "float({})", v),
Value::Null => write!(f, "null"),
Value::Bool(v) => write!(f, "bool({})", v),
Value::Bytes(v) => write!(f, "bytes(len = {})", v.len()),
Value::String(v) => write!(f, "string({})", v),
Value::Map(v) => write!(f, "map(len = {})", v.len()),
Value::List(v) => write!(f, "list(len = {})", v.len()),
Value::Function(v) => write!(f, "function(name = {})", v.name),
}
}
}
impl std::ops::Mul for Value {
type Output = Value;
fn mul(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Value::Int(l), Value::Int(r)) => Value::Int(l * r),
(a, b) => todo!("mul {} {}", a, b),
}
}
}
impl std::ops::Div for Value {
type Output = Value;
fn div(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Value::Int(l), Value::Int(r)) => Value::Int(l / r),
(a, b) => todo!("div {} {}", a, b),
}
}
}
impl std::ops::Add<Value> for Value {
type Output = Value;
fn add(self, o: Value) -> Self::Output {
match (self, o) {
(Value::Int(l), Value::Int(r)) => Value::Int(l + r),
(a, b) => todo!("add {} {}", a, b),
}
}
}
impl std::ops::Sub<Value> for Value {
type Output = Value;
fn sub(self, o: Value) -> Self::Output {
match (self, o) {
(Value::Int(l), Value::Int(r)) => Value::Int(l - r),
(a, b) => todo!("sub {} {}", a, b),
}
}
}