mod closures;
mod dicts;
mod impls;
mod lists;
mod structs;
mod traits;
use std::{any::Any, borrow::Cow, cmp::Ordering, fmt, fmt::Write, marker::PhantomData, ops::Deref};
pub use closures::*;
pub use dicts::*;
use impls::ValueImpl;
pub use lists::*;
pub use structs::*;
pub use traits::*;
use crate::ll::{bytecode::DispatchTable, error::LanguageErrorKind, gc::GcRaw};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ValueKind {
Nil,
Boolean,
Number,
String,
Function,
Struct,
Trait,
List,
Dict,
UserData,
}
trait ValueCommon: Clone + PartialEq {
fn new_nil() -> Self;
fn new_boolean(b: bool) -> Self;
fn new_number(n: f64) -> Self;
fn new_string(s: GcRaw<String>) -> Self;
fn new_function(f: GcRaw<Closure>) -> Self;
fn new_struct(s: GcRaw<Struct>) -> Self;
fn new_trait(s: GcRaw<Trait>) -> Self;
fn new_list(s: GcRaw<List>) -> Self;
fn new_dict(d: GcRaw<Dict>) -> Self;
fn new_user_data(u: GcRaw<Box<dyn UserData>>) -> Self;
fn kind(&self) -> ValueKind;
unsafe fn get_boolean_unchecked(&self) -> bool;
unsafe fn get_number_unchecked(&self) -> &f64;
unsafe fn get_raw_string_unchecked(&self) -> GcRaw<String>;
unsafe fn get_raw_function_unchecked(&self) -> GcRaw<Closure>;
unsafe fn get_raw_struct_unchecked(&self) -> GcRaw<Struct>;
unsafe fn get_raw_trait_unchecked(&self) -> GcRaw<Trait>;
unsafe fn get_raw_list_unchecked(&self) -> GcRaw<List>;
unsafe fn get_raw_dict_unchecked(&self) -> GcRaw<Dict>;
unsafe fn get_raw_user_data_unchecked(&self) -> GcRaw<Box<dyn UserData>>;
}
fn _check_implementations() {
fn check_value<T: ValueCommon>() {}
check_value::<ValueImpl>();
}
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct RawValue(ValueImpl, PhantomData<*const ()>);
impl RawValue {
pub fn kind(&self) -> ValueKind {
self.0.kind()
}
fn type_name(&self) -> Cow<'static, str> {
match self.0.kind() {
ValueKind::Nil => "Nil".into(),
ValueKind::Boolean => "Boolean".into(),
ValueKind::Number => "Number".into(),
ValueKind::String => "String".into(),
ValueKind::Function => "Function".into(),
ValueKind::List => "List".into(),
ValueKind::Dict => "Dict".into(),
ValueKind::Struct => unsafe { self.0.get_raw_struct_unchecked().get().dtable() }
.type_name
.deref()
.to_owned()
.into(),
ValueKind::Trait => unsafe { self.0.get_raw_trait_unchecked().get().dtable() }
.type_name
.deref()
.to_owned()
.into(),
ValueKind::UserData => unsafe { self.0.get_raw_user_data_unchecked().get().dtable() }
.type_name
.deref()
.to_owned()
.into(),
}
}
fn type_error(&self, expected: &'static str) -> LanguageErrorKind {
LanguageErrorKind::TypeError { expected: Cow::from(expected), got: self.type_name() }
}
pub unsafe fn get_boolean_unchecked(&self) -> bool {
self.0.get_boolean_unchecked()
}
pub unsafe fn get_number_unchecked(&self) -> &f64 {
self.0.get_number_unchecked()
}
pub unsafe fn get_raw_string_unchecked(&self) -> GcRaw<String> {
self.0.get_raw_string_unchecked()
}
pub unsafe fn get_raw_function_unchecked(&self) -> GcRaw<Closure> {
self.0.get_raw_function_unchecked()
}
pub unsafe fn get_raw_struct_unchecked(&self) -> GcRaw<Struct> {
self.0.get_raw_struct_unchecked()
}
pub unsafe fn get_raw_trait_unchecked(&self) -> GcRaw<Trait> {
self.0.get_raw_trait_unchecked()
}
pub unsafe fn get_raw_list_unchecked(&self) -> GcRaw<List> {
self.0.get_raw_list_unchecked()
}
pub unsafe fn get_raw_dict_unchecked(&self) -> GcRaw<Dict> {
self.0.get_raw_dict_unchecked()
}
pub unsafe fn get_raw_user_data_unchecked(&self) -> GcRaw<Box<dyn UserData>> {
self.0.get_raw_user_data_unchecked()
}
pub fn ensure_nil(&self) -> Result<(), LanguageErrorKind> {
if self.0.kind() == ValueKind::Nil {
Ok(())
} else {
Err(self.type_error("Nil"))
}
}
pub fn ensure_boolean(&self) -> Result<bool, LanguageErrorKind> {
if self.0.kind() == ValueKind::Boolean {
Ok(unsafe { self.0.get_boolean_unchecked() })
} else {
Err(self.type_error("Boolean"))
}
}
pub fn ensure_number(&self) -> Result<f64, LanguageErrorKind> {
if self.0.kind() == ValueKind::Number {
Ok(unsafe { *self.0.get_number_unchecked() })
} else {
Err(self.type_error("Number"))
}
}
pub fn ensure_raw_string(&self) -> Result<GcRaw<String>, LanguageErrorKind> {
if self.0.kind() == ValueKind::String {
Ok(unsafe { self.0.get_raw_string_unchecked() })
} else {
Err(self.type_error("String"))
}
}
pub fn ensure_raw_function(&self) -> Result<GcRaw<Closure>, LanguageErrorKind> {
if self.0.kind() == ValueKind::Function {
Ok(unsafe { self.0.get_raw_function_unchecked() })
} else {
Err(self.type_error("Function"))
}
}
pub fn ensure_raw_struct(&self) -> Result<GcRaw<Struct>, LanguageErrorKind> {
if self.0.kind() == ValueKind::Struct {
Ok(unsafe { self.0.get_raw_struct_unchecked() })
} else {
Err(self.type_error("any struct"))
}
}
pub fn ensure_raw_trait(&self) -> Result<GcRaw<Trait>, LanguageErrorKind> {
if self.0.kind() == ValueKind::Trait {
Ok(unsafe { self.0.get_raw_trait_unchecked() })
} else {
Err(self.type_error("any trait"))
}
}
pub fn get_raw_user_data<T>(&self) -> Option<GcRaw<Box<dyn UserData>>>
where
T: UserData,
{
if self.0.kind() == ValueKind::UserData {
Some(unsafe { self.0.get_raw_user_data_unchecked() })
} else {
None
}
}
pub fn is_truthy(&self) -> bool {
!self.is_falsy()
}
pub fn is_falsy(&self) -> bool {
self.0.kind() == ValueKind::Nil
|| (self.0.kind() == ValueKind::Boolean && unsafe { !self.0.get_boolean_unchecked() })
}
pub fn try_partial_cmp(&self, other: &Self) -> Result<Option<Ordering>, LanguageErrorKind> {
if self.0.kind() != other.0.kind() {
Err(LanguageErrorKind::TypeError { expected: self.type_name(), got: other.type_name() })
} else {
match self.0.kind() {
ValueKind::Nil => Ok(Some(Ordering::Equal)),
ValueKind::Boolean => {
let a = unsafe { self.0.get_boolean_unchecked() };
let b = unsafe { other.0.get_boolean_unchecked() };
Ok(Some(a.cmp(&b)))
}
ValueKind::Number => {
let a = unsafe { self.0.get_number_unchecked() };
let b = unsafe { other.0.get_number_unchecked() };
Ok(a.partial_cmp(b))
}
ValueKind::String => unsafe {
let a = self.0.get_raw_string_unchecked();
let b = other.0.get_raw_string_unchecked();
Ok(Some(a.get().cmp(b.get())))
},
ValueKind::Function => Ok(None),
ValueKind::Struct => Ok(None),
ValueKind::Trait => Ok(None),
ValueKind::List => unsafe {
let a = self.0.get_raw_list_unchecked();
let b = other.0.get_raw_list_unchecked();
a.get().try_partial_cmp(b.get())
},
ValueKind::Dict => todo!(),
ValueKind::UserData => Ok(None),
}
}
}
}
impl Default for RawValue {
fn default() -> Self {
Self(ValueImpl::new_nil(), PhantomData)
}
}
impl From<()> for RawValue {
fn from(_: ()) -> Self {
Self(ValueImpl::new_nil(), PhantomData)
}
}
impl From<bool> for RawValue {
fn from(b: bool) -> Self {
Self(ValueImpl::new_boolean(b), PhantomData)
}
}
impl From<f64> for RawValue {
fn from(x: f64) -> Self {
Self(ValueImpl::new_number(x), PhantomData)
}
}
impl From<GcRaw<String>> for RawValue {
fn from(s: GcRaw<String>) -> Self {
Self(ValueImpl::new_string(s), PhantomData)
}
}
impl From<GcRaw<Closure>> for RawValue {
fn from(f: GcRaw<Closure>) -> Self {
Self(ValueImpl::new_function(f), PhantomData)
}
}
impl From<GcRaw<Struct>> for RawValue {
fn from(s: GcRaw<Struct>) -> Self {
Self(ValueImpl::new_struct(s), PhantomData)
}
}
impl From<GcRaw<Trait>> for RawValue {
fn from(t: GcRaw<Trait>) -> Self {
Self(ValueImpl::new_trait(t), PhantomData)
}
}
impl From<GcRaw<List>> for RawValue {
fn from(s: GcRaw<List>) -> Self {
Self(ValueImpl::new_list(s), PhantomData)
}
}
impl From<GcRaw<Dict>> for RawValue {
fn from(s: GcRaw<Dict>) -> Self {
Self(ValueImpl::new_dict(s), PhantomData)
}
}
impl From<GcRaw<Box<dyn UserData>>> for RawValue {
fn from(u: GcRaw<Box<dyn UserData>>) -> Self {
Self(ValueImpl::new_user_data(u), PhantomData)
}
}
impl fmt::Debug for RawValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn dtable(f: &mut fmt::Formatter, dtable: &DispatchTable) -> fmt::Result {
let type_name = &dtable.pretty_name;
write!(f, "<[{type_name}]>")
}
unsafe {
match self.0.kind() {
ValueKind::Nil => f.write_str("nil"),
ValueKind::Boolean => write!(f, "{}", self.0.get_boolean_unchecked()),
ValueKind::Number => write!(f, "{}", self.0.get_number_unchecked()),
ValueKind::String => {
write!(f, "{:?}", self.0.get_raw_string_unchecked().get().deref())
}
ValueKind::Function => {
write!(f, "<func {:?}>", self.0.get_raw_function_unchecked().get_raw())
}
ValueKind::List => {
f.write_char('[')?;
let list = self.0.get_raw_list_unchecked();
let elements = list.get().as_slice();
for (i, element) in elements.iter().enumerate() {
if i != 0 {
f.write_str(", ")?;
}
fmt::Debug::fmt(element, f)?;
}
f.write_char(']')?;
Ok(())
}
ValueKind::Dict => {
let dict = self.0.get_raw_dict_unchecked();
let dict = dict.get();
if dict.is_empty() {
f.write_str("[:]")?;
} else {
f.write_char('[')?;
for (i, (key, value)) in dict.iter().enumerate() {
if i != 0 {
f.write_str(", ")?;
}
fmt::Debug::fmt(&key, f)?;
f.write_str(": ")?;
fmt::Debug::fmt(&value, f)?;
}
f.write_char(']')?;
}
Ok(())
}
ValueKind::Struct => dtable(f, self.0.get_raw_struct_unchecked().get().dtable()),
ValueKind::Trait => dtable(f, self.0.get_raw_trait_unchecked().get().dtable()),
ValueKind::UserData => {
dtable(f, self.0.get_raw_user_data_unchecked().get().dtable())
}
}
}
}
}
impl fmt::Display for RawValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
match self.0.kind() {
ValueKind::String => write!(f, "{}", self.0.get_raw_string_unchecked().get()),
_ => fmt::Debug::fmt(&self, f),
}
}
}
}
pub trait UserData: Any {
fn dtable_gcraw(&self) -> GcRaw<DispatchTable>;
unsafe fn dtable(&self) -> &DispatchTable {
self.dtable_gcraw().get()
}
fn visit_references(&self, _visit: &mut dyn FnMut(RawValue)) {}
fn as_any(&self) -> &dyn Any;
}