use std::fmt::Debug;
use std::fmt::Display;
use crate::eval::encode::alkyne::UclEncoding;
use crate::eval::encode::Encoder;
#[macro_use]
pub mod native_macros;
pub mod fns;
pub use fns::Fn;
pub use fns::NativeFn;
pub mod seq;
pub use seq::List;
pub use seq::Str;
pub mod object;
pub use object::Object;
pub mod convert;
pub use convert::IntoValue;
#[derive(Clone, Debug)]
pub enum Value<'i> {
Null,
Bool(bool),
Number(f64),
String(Str<'i>),
List(List<'i>),
Object(Object<'i>),
Fn(Fn<'i>),
NativeFn(NativeFn<'i>),
Std,
Range { start: i64, end: i64, step: i64 },
}
impl<'i> Value<'i> {
pub fn ty(&self) -> Type {
match self {
Value::Null => Type::Null,
Value::Bool(..) => Type::Bool,
Value::Number(..) => Type::Number,
Value::String(..) => Type::String,
Value::List(..) => Type::List,
Value::Object(..) => Type::Object,
Value::Fn(..) | Value::NativeFn(..) => Type::Fn,
_ => Type::Opaque,
}
}
pub const EPSILON: f64 = 1e-12;
pub fn as_int(&self) -> Result<i64, Type> {
match self {
Value::Number(f) if f.fract().abs() < Self::EPSILON => Ok(*f as i64),
v => Err(v.ty()),
}
}
}
impl Display for Value<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let buf = Encoder::<UclEncoding>::new().encode(self);
write!(
f,
"{}",
buf
.as_ref()
.map(|s| s.as_str())
.unwrap_or("<encoding error>")
)
}
}
pub trait DebugInfo {
type Info: Display;
fn debug_info(&self) -> Self::Info;
}
#[derive(Copy, Clone, Debug)]
pub struct DebugInfoScalar {
pub bytes: u64,
}
impl Display for DebugInfoScalar {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "<{:#x}>", self.bytes)
}
}
impl DebugInfo for () {
type Info = DebugInfoScalar;
fn debug_info(&self) -> Self::Info {
DebugInfoScalar { bytes: 0 }
}
}
impl DebugInfo for bool {
type Info = DebugInfoScalar;
fn debug_info(&self) -> Self::Info {
DebugInfoScalar { bytes: *self as _ }
}
}
impl DebugInfo for f64 {
type Info = DebugInfoScalar;
fn debug_info(&self) -> Self::Info {
DebugInfoScalar {
bytes: self.to_bits(),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Type {
Null,
Bool,
Number,
String,
List,
Object,
Fn,
Opaque,
}
impl Type {
pub fn name(self) -> &'static str {
match self {
Type::Null => "null",
Type::Bool => "bool",
Type::Number => "number",
Type::String => "string",
Type::List => "list",
Type::Object => "object",
Type::Fn => "function",
Type::Opaque => "opaque",
}
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
pub trait Native: Send + Sync {
#[allow(unused)]
fn index<'i>(&self, args: &[Value<'i>]) -> Option<Value<'i>> {
None
}
#[allow(unused)]
fn call<'i>(&self, args: &[Value<'i>]) -> Option<Value<'i>> {
None
}
#[allow(unused)]
fn iter<'i>(&self) -> Option<Box<dyn Iterator<Item = Vec<Value<'i>>>>> {
None
}
}