210 lines
5.3 KiB
Rust
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);
|