333 lines
8.0 KiB
Rust
333 lines
8.0 KiB
Rust
use std::any::Any;
|
|
use std::borrow::Cow;
|
|
use std::io;
|
|
use std::{cell::RefCell, collections::HashMap, fmt::Display, hash::Hash, rc::Rc};
|
|
|
|
pub use num_complex::Complex64;
|
|
use num_complex::ComplexFloat;
|
|
pub use num_rational::Rational64;
|
|
|
|
use crate::lstring::{LStr, LString};
|
|
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<LStr>),
|
|
List(RcList),
|
|
Table(RcTable),
|
|
Function(Rc<Function>),
|
|
NativeFunc(Rc<NativeFunc>),
|
|
|
|
Native(Rc<dyn NativeValue>),
|
|
}
|
|
|
|
pub trait NativeValue: std::fmt::Debug + Any {
|
|
fn get_type(&self) -> Symbol;
|
|
fn as_any(&self) -> &dyn Any;
|
|
|
|
fn to_lstring(&self, w: &mut LString, _repr: bool) -> io::Result<()> {
|
|
w.extend(b"<native value>");
|
|
Ok(())
|
|
}
|
|
fn partial_eq(&self, _other: &Value) -> bool {
|
|
false
|
|
}
|
|
fn copy_value(&self) -> Result<Option<Value>, Exception> {
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
impl Display for Value {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let s = if f.alternate() { Cow::Owned(self.repr()) } else { self.str() };
|
|
write!(f, "{s}")
|
|
}
|
|
}
|
|
|
|
impl Value {
|
|
pub fn new_list(f: impl FnOnce(&mut Vec<Value>)) -> Self {
|
|
let mut list = Vec::new();
|
|
f(&mut list);
|
|
list.into()
|
|
}
|
|
|
|
pub fn new_table(f: impl FnOnce(&mut HashMap<HashValue, Value>)) -> Self {
|
|
let mut table = HashMap::new();
|
|
f(&mut table);
|
|
table.into()
|
|
}
|
|
|
|
pub fn write_to_lstring(&self, w: &mut LString, repr: bool) -> io::Result<()> {
|
|
use std::io::Write;
|
|
match self {
|
|
Self::Nil => write!(w, "nil"),
|
|
Self::Bool(b) => write!(w, "{b}"),
|
|
Self::Symbol(s) => {
|
|
let name = s.name();
|
|
w.push_byte(b':');
|
|
if name.is_identifier() {
|
|
w.extend(name.as_bytes());
|
|
} else {
|
|
write!(w, "{name:?}")?;
|
|
}
|
|
Ok(())
|
|
},
|
|
Self::Range(r) => match r.ty {
|
|
RangeType::Open => write!(w, "{}..{}", r.start, r.stop),
|
|
RangeType::Closed => write!(w, "{}..={}", r.start, r.stop),
|
|
RangeType::Endless => write!(w, "{}..*", r.start),
|
|
},
|
|
Self::Int(i) => write!(w, "{i}"),
|
|
Self::Float(x) => write!(w, "{x:?}"),
|
|
Self::Ratio(r) => write!(w, "{}/{}", r.numer(), r.denom()),
|
|
Self::Complex(z) => {
|
|
write!(w, "{:?}", z.re())?;
|
|
if z.im() >= 0.0 || z.im.is_nan() {
|
|
w.push_byte(b'+');
|
|
}
|
|
write!(w, "{:?}i", z.im())
|
|
},
|
|
Self::Cell(v) if repr => {
|
|
w.write_all(b"cell(")?;
|
|
v.borrow().write_to_lstring(w, repr)?;
|
|
w.write_all(b")")
|
|
},
|
|
Self::Cell(v) => v.borrow().write_to_lstring(w, false),
|
|
|
|
Self::String(s) if repr => write!(w, "{s:?}"),
|
|
Self::String(s) => w.write_all(s.as_bytes()),
|
|
|
|
Self::List(l) => {
|
|
w.write_all(b"[")?;
|
|
for (i, item) in l.borrow().iter().enumerate() {
|
|
if i != 0 {
|
|
w.write_all(b", ")?;
|
|
}
|
|
item.write_to_lstring(w, true)?;
|
|
}
|
|
w.write_all(b"]")
|
|
},
|
|
Self::Table(t) => {
|
|
w.write_all(b"{ ")?;
|
|
for (i, (k, v)) in t.borrow().iter().enumerate() {
|
|
if i != 0 {
|
|
w.write_all(b", ")?;
|
|
}
|
|
k.0.write_table_key_repr(w)?;
|
|
w.write_all(b" = ")?;
|
|
v.write_to_lstring(w, true)?;
|
|
}
|
|
w.write_all(b" }")
|
|
},
|
|
Self::Function(g)
|
|
=> write!(w, "<function {:?}>", Rc::as_ptr(g)),
|
|
Self::NativeFunc(g)
|
|
=> write!(w, "<native function {:?}>", Rc::as_ptr(g)),
|
|
Self::Native(n) => n.to_lstring(w, repr),
|
|
}
|
|
}
|
|
|
|
fn write_table_key_repr(&self, w: &mut LString) -> std::io::Result<()> {
|
|
match self {
|
|
Self::Nil | Self::Bool(_)
|
|
| Self::Int(_) | Self::String(_)
|
|
=> self.write_to_lstring(w, true),
|
|
Self::Symbol(s) => {
|
|
let name = s.name();
|
|
if name.is_identifier() {
|
|
w.push_lstr(name);
|
|
Ok(())
|
|
} else {
|
|
self.write_to_lstring(w, true)
|
|
}
|
|
},
|
|
_ => {
|
|
w.push_byte(b'(');
|
|
self.write_to_lstring(w, true)?;
|
|
w.push_byte(b')');
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn str(&self) -> Cow<'_, LStr> {
|
|
if let Value::String(s) = self {
|
|
Cow::Borrowed(s)
|
|
} else {
|
|
let mut s = LString::new();
|
|
self.write_to_lstring(&mut s, false).expect("write_to_lstring failed");
|
|
Cow::Owned(s)
|
|
}
|
|
}
|
|
|
|
pub fn repr(&self) -> LString {
|
|
let mut s = LString::new();
|
|
self.write_to_lstring(&mut s, true).expect("write_to_lstring failed");
|
|
s
|
|
}
|
|
|
|
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,
|
|
Value::Native(n) => n.get_type(),
|
|
}
|
|
}
|
|
|
|
pub fn hashable(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
Value::Nil | Value::Bool(_) | Value::Symbol(_)
|
|
| Value::Int(_) | Value::Ratio(_) | Value::String(_)
|
|
)
|
|
}
|
|
|
|
pub fn downcast_native<T: NativeValue>(&self) -> Option<&T> {
|
|
match self {
|
|
Value::Native(n) => n.as_any().downcast_ref(),
|
|
_ => None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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 }
|
|
pub fn 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<LStr>, String);
|
|
impl_from!(LString, String, into);
|
|
impl_from!(&LStr, String, into);
|
|
impl_from!(Box<LStr>, String, into);
|
|
impl_from!(Cow<'_, LStr>, String, into);
|
|
impl_from!(RefCell<Value>, Cell, rc);
|
|
|
|
impl From<Rc<dyn NativeValue>> for Value {
|
|
fn from(value: Rc<dyn NativeValue>) -> Self {
|
|
Self::Native(value)
|
|
}
|
|
}
|
|
|
|
impl<T: NativeValue + 'static> From<T> for Value {
|
|
fn from(value: T) -> Self {
|
|
Self::Native(Rc::new(value))
|
|
}
|
|
}
|