talc/talc-lang/src/value/mod.rs

210 lines
5.3 KiB
Rust

use std::{cell::RefCell, collections::HashMap, fmt::Display, hash::Hash, rc::Rc};
pub use num_complex::Complex64;
pub use num_rational::Rational64;
use crate::symbol::{Symbol, SYM_HASH_ERROR};
use crate::exception::{Exception, throw};
use self::{range::{Range, RangeType}, function::{Function, NativeFunc}};
pub mod function;
pub mod ops;
pub mod range;
pub mod index;
type RcList = Rc<RefCell<Vec<Value>>>;
type RcTable = Rc<RefCell<HashMap<HashValue, Value>>>;
#[derive(Clone, Debug, Default)]
pub enum Value {
#[default]
Nil,
Bool(bool),
Symbol(Symbol),
Range(Range),
Int(i64),
Float(f64),
Ratio(Rational64),
Complex(Complex64),
Cell(Rc<RefCell<Value>>),
String(Rc<str>),
List(RcList),
Table(RcTable),
Function(Rc<Function>),
NativeFunc(Rc<NativeFunc>),
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Nil => write!(f, "nil"),
Self::Bool(b) => write!(f, "{b}"),
Self::Symbol(s) => write!(f, ":{}", s.name()),
Self::Range(r) => match r.ty {
RangeType::Open => write!(f, "{}..{}", r.start, r.stop),
RangeType::Closed => write!(f, "{}..={}", r.start, r.stop),
RangeType::Endless => write!(f, "{}..*", r.start),
},
Self::Int(n) => write!(f, "{n}"),
Self::Float(x) => write!(f, "{x:?}"),
Self::Ratio(r) => write!(f, "{}/{}", r.numer(), r.denom()),
Self::Complex(z) => write!(f, "{z}"),
Self::Cell(v) if f.alternate() => write!(f, "cell({:#})", v.borrow()),
Self::Cell(v) => write!(f, "{})", v.borrow()),
Self::String(s) if f.alternate() => write!(f, "{s:?}"),
Self::String(s) => write!(f, "{s}"),
Self::List(l) => {
write!(f, "[")?;
for (i, item) in l.borrow().iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{item:#}")?;
}
write!(f, "]")
},
Self::Table(t) => {
write!(f, "{{ ")?;
for (i, (k, v)) in t.borrow().iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "({:#}) = {v:#}", k.0)?;
}
write!(f, " }}")
},
Self::Function(g)
=> write!(f, "<function {:?}>", Rc::as_ptr(g)),
Self::NativeFunc(g)
=> write!(f, "<native function {:?}>", Rc::as_ptr(g)),
}
}
}
impl Value {
pub fn get_type(&self) -> Symbol {
use crate::symbol::*;
match self {
Value::Nil => *SYM_NIL,
Value::Bool(_) => *SYM_BOOL,
Value::Symbol(_) => *SYM_SYMBOL,
Value::Range(_) => *SYM_RANGE,
Value::Int(_) => *SYM_INT,
Value::Float(_) => *SYM_FLOAT,
Value::Ratio(_) => *SYM_RATIO,
Value::Complex(_) => *SYM_COMPLEX,
Value::Cell(_) => *SYM_CELL,
Value::String(_) => *SYM_STRING,
Value::List(_) => *SYM_LIST,
Value::Table(_) => *SYM_TABLE,
Value::Function(_) => *SYM_FUNCTION,
Value::NativeFunc(_) => *SYM_NATIVE_FUNC,
}
}
pub fn hashable(&self) -> bool {
matches!(
self,
Value::Nil | Value::Bool(_) | Value::Symbol(_)
| Value::Int(_) | Value::Ratio(_) | Value::String(_)
)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct HashValue(Value);
impl Eq for HashValue {}
impl TryFrom<Value> for HashValue {
type Error = Exception;
fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
if !value.hashable() {
throw!(*SYM_HASH_ERROR, "value {value:#} cannot be hashed")
}
Ok(Self(value))
}
}
impl HashValue {
pub fn into_inner(self) -> Value { self.0 }
}
impl Hash for HashValue {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::mem::discriminant(&self.0).hash(state);
match &self.0 {
Value::Nil => (),
Value::Bool(b) => b.hash(state),
Value::Symbol(s) => s.hash(state),
Value::Int(n) => n.hash(state),
Value::Ratio(r) => r.hash(state),
Value::String(s) => s.hash(state),
_ => unreachable!(),
}
}
}
macro_rules! impl_from {
($ty:ty, $var:ident) => {
impl From<$ty> for Value {
fn from(value: $ty) -> Self { Self::$var(value) }
}
};
($ty:ty, $var:ident, hash) => {
impl From<$ty> for Value {
fn from(value: $ty) -> Self { Self::$var(value) }
}
impl From<$ty> for HashValue {
fn from(value: $ty) -> Self { Self(Value::$var(value)) }
}
};
($ty:ty, $var:ident, rc) => {
impl From<$ty> for Value {
fn from(value: $ty) -> Self { Self::$var(Rc::new(value)) }
}
impl From<Rc<$ty>> for Value {
fn from(value: Rc<$ty>) -> Self { Self::$var(value) }
}
};
($ty:ty, $var:ident, rcref) => {
impl From<$ty> for Value {
fn from(value: $ty) -> Self { Self::$var(Rc::new(RefCell::new(value))) }
}
impl From<RefCell<$ty>> for Value {
fn from(value: RefCell<$ty>) -> Self { Self::$var(Rc::new(value)) }
}
impl From<Rc<RefCell<$ty>>> for Value {
fn from(value: Rc<RefCell<$ty>>) -> Self { Self::$var(value) }
}
};
($ty:ty, $var:ident, into) => {
impl From<$ty> for Value {
fn from(value: $ty) -> Self { Self::$var(value.into()) }
}
};
}
impl_from!(bool, Bool, hash);
impl_from!(Symbol, Symbol, hash);
impl_from!(Range, Range);
impl_from!(i64, Int, hash);
impl_from!(f64, Float);
impl_from!(Rational64, Ratio, hash);
impl_from!(Complex64, Complex);
impl_from!(HashMap<HashValue, Value>, Table, rcref);
impl_from!(Vec<Value>, List, rcref);
impl_from!(Function, Function, rc);
impl_from!(NativeFunc, NativeFunc, rc);
impl_from!(Rc<str>, String);
impl_from!(String, String, into);
impl_from!(&str, String, into);
impl_from!(Box<str>, String, into);
impl_from!(RefCell<Value>, Cell, rc);