use std::any::Any;
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use tatara_lisp::{Sexp, Span, Spanned};
use crate::env::Env;
use crate::ffi::Arity;
#[derive(Clone)]
pub enum Value {
Nil,
Bool(bool),
Int(i64),
Float(f64),
Str(Arc<str>),
Symbol(Arc<str>),
Keyword(Arc<str>),
List(Arc<Vec<Value>>),
Map(Arc<HashMap<MapKey, Value>>),
Closure(Arc<Closure>),
NativeFn(Arc<NativeFn>),
Promise(Arc<std::sync::Mutex<PromiseState>>),
Error(Arc<ErrorObj>),
Sexp(Sexp, Span),
Foreign(Arc<dyn Any + Send + Sync>),
}
#[derive(Debug, Clone)]
pub struct ErrorObj {
pub tag: Arc<str>,
pub message: Arc<str>,
pub data: Vec<(Value, Value)>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MapKey {
Nil,
Bool(bool),
Int(i64),
Float(u64),
Str(Arc<str>),
Symbol(Arc<str>),
Keyword(Arc<str>),
}
impl MapKey {
pub fn from_value(v: &Value) -> Option<Self> {
Some(match v {
Value::Nil => Self::Nil,
Value::Bool(b) => Self::Bool(*b),
Value::Int(n) => Self::Int(*n),
Value::Float(n) => Self::Float(n.to_bits()),
Value::Str(s) => Self::Str(s.clone()),
Value::Symbol(s) => Self::Symbol(s.clone()),
Value::Keyword(s) => Self::Keyword(s.clone()),
_ => return None,
})
}
pub fn to_value(&self) -> Value {
match self {
Self::Nil => Value::Nil,
Self::Bool(b) => Value::Bool(*b),
Self::Int(n) => Value::Int(*n),
Self::Float(b) => Value::Float(f64::from_bits(*b)),
Self::Str(s) => Value::Str(s.clone()),
Self::Symbol(s) => Value::Symbol(s.clone()),
Self::Keyword(s) => Value::Keyword(s.clone()),
}
}
}
impl fmt::Display for MapKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_value())
}
}
pub enum PromiseState {
Pending(Arc<Closure>),
Forced(Value),
}
impl fmt::Debug for PromiseState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Pending(_) => f.write_str("Pending(…)"),
Self::Forced(v) => write!(f, "Forced({v:?})"),
}
}
}
pub struct Closure {
pub params: Vec<Arc<str>>,
pub rest: Option<Arc<str>>,
pub body: Vec<Spanned>,
pub captured_env: Env,
pub source: Span,
}
#[derive(Clone, Debug)]
pub struct NativeFn {
pub name: Arc<str>,
pub arity: Arity,
}
impl Value {
pub fn symbol(s: impl Into<Arc<str>>) -> Self {
Self::Symbol(s.into())
}
pub fn keyword(s: impl Into<Arc<str>>) -> Self {
Self::Keyword(s.into())
}
pub fn string(s: impl Into<Arc<str>>) -> Self {
Self::Str(s.into())
}
pub fn list<I: IntoIterator<Item = Value>>(xs: I) -> Self {
Self::List(Arc::new(xs.into_iter().collect()))
}
pub fn is_truthy(&self) -> bool {
!matches!(self, Self::Nil | Self::Bool(false))
}
pub fn type_name(&self) -> &'static str {
match self {
Self::Nil => "nil",
Self::Bool(_) => "bool",
Self::Int(_) => "int",
Self::Float(_) => "float",
Self::Str(_) => "string",
Self::Symbol(_) => "symbol",
Self::Keyword(_) => "keyword",
Self::List(_) => "list",
Self::Map(_) => "map",
Self::Closure(_) => "closure",
Self::NativeFn(_) => "native-fn",
Self::Promise(_) => "promise",
Self::Error(_) => "error",
Self::Sexp(..) => "sexp",
Self::Foreign(_) => "foreign",
}
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Nil => f.write_str("Nil"),
Self::Bool(b) => write!(f, "Bool({b})"),
Self::Int(n) => write!(f, "Int({n})"),
Self::Float(n) => write!(f, "Float({n})"),
Self::Str(s) => write!(f, "Str({s:?})"),
Self::Symbol(s) => write!(f, "Symbol({s})"),
Self::Keyword(s) => write!(f, "Keyword(:{s})"),
Self::List(xs) => f.debug_list().entries(xs.iter()).finish(),
Self::Map(m) => write!(f, "Map({} entries)", m.len()),
Self::Closure(_) => f.write_str("Closure(…)"),
Self::NativeFn(n) => write!(f, "NativeFn({})", n.name),
Self::Promise(_) => f.write_str("Promise(…)"),
Self::Error(e) => write!(f, "Error({}: {})", e.tag, e.message),
Self::Sexp(s, sp) => write!(f, "Sexp({s} @ {sp})"),
Self::Foreign(_) => f.write_str("Foreign(…)"),
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Nil => f.write_str("()"),
Self::Bool(true) => f.write_str("#t"),
Self::Bool(false) => f.write_str("#f"),
Self::Int(n) => write!(f, "{n}"),
Self::Float(n) => write!(f, "{n}"),
Self::Str(s) => write!(f, "{s:?}"),
Self::Symbol(s) => f.write_str(s),
Self::Keyword(s) => write!(f, ":{s}"),
Self::List(xs) => {
f.write_str("(")?;
for (i, v) in xs.iter().enumerate() {
if i > 0 {
f.write_str(" ")?;
}
write!(f, "{v}")?;
}
f.write_str(")")
}
Self::Map(m) => {
f.write_str("{")?;
for (i, (k, v)) in m.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{k} {v}")?;
}
f.write_str("}")
}
Self::Closure(c) => {
write!(f, "#<closure")?;
if !c.params.is_empty() {
write!(f, " ({}", c.params.join(" "))?;
if let Some(rest) = &c.rest {
write!(f, " . {rest}")?;
}
write!(f, ")")?;
}
write!(f, ">")
}
Self::NativeFn(n) => write!(f, "#<native {}>", n.name),
Self::Promise(p) => {
let state = p.lock().unwrap();
match &*state {
PromiseState::Pending(_) => f.write_str("#<promise pending>"),
PromiseState::Forced(v) => write!(f, "#<promise {v}>"),
}
}
Self::Error(e) => {
write!(f, "#<error :{} {:?}", e.tag, e.message.as_ref())?;
if !e.data.is_empty() {
f.write_str(" {")?;
for (i, (k, v)) in e.data.iter().enumerate() {
if i > 0 {
f.write_str(" ")?;
}
write!(f, "{k} {v}")?;
}
f.write_str("}")?;
}
f.write_str(">")
}
Self::Sexp(s, _) => write!(f, "'{s}"),
Self::Foreign(_) => f.write_str("#<foreign>"),
}
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Self::Bool(b)
}
}
impl From<i64> for Value {
fn from(n: i64) -> Self {
Self::Int(n)
}
}
impl From<f64> for Value {
fn from(n: f64) -> Self {
Self::Float(n)
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Self::Str(Arc::from(s))
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Self::Str(Arc::from(s))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn truthiness() {
assert!(Value::Bool(true).is_truthy());
assert!(!Value::Bool(false).is_truthy());
assert!(!Value::Nil.is_truthy());
assert!(Value::Int(0).is_truthy(), "zero is truthy (Scheme-ish)");
assert!(Value::list(std::iter::empty::<Value>()).is_truthy());
}
#[test]
fn display_primitives() {
assert_eq!(Value::Int(42).to_string(), "42");
assert_eq!(Value::Bool(true).to_string(), "#t");
assert_eq!(Value::Bool(false).to_string(), "#f");
assert_eq!(Value::symbol("foo").to_string(), "foo");
assert_eq!(Value::keyword("k").to_string(), ":k");
assert_eq!(Value::Nil.to_string(), "()");
}
#[test]
fn display_list() {
let v = Value::list([Value::Int(1), Value::Int(2), Value::Int(3)]);
assert_eq!(v.to_string(), "(1 2 3)");
}
#[test]
fn type_names() {
assert_eq!(Value::Int(0).type_name(), "int");
assert_eq!(Value::Str(Arc::from("x")).type_name(), "string");
assert_eq!(Value::Nil.type_name(), "nil");
}
}