use crate::base::BaseFn; use crate::chunk::Chunk; use imbl::{HashMap, Vector}; use ordered_float::NotNan; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; use std::cell::RefCell; use std::rc::Rc; #[derive(Clone, Debug)] pub enum LFn { Declared { name: &'static str, }, Defined { name: &'static str, doc: Option<&'static str>, arities: Vec, chunks: Vec, splat: u8, closed: RefCell>, patterns: Vec, }, } impl LFn { pub fn close(&self, value: Value) { match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { closed, .. } => { let shown = value.show(); closed.borrow_mut().push(value); let pos = closed.borrow().len(); if crate::DEBUG_SCRIPT_RUN { println!("closing over in {} at {pos}: {shown}", self.name(),); } } } } pub fn patterns(&self) -> Value { match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { patterns, .. } => Value::from_string( patterns .iter() .map(|pattern| format!(" {pattern}")) .collect::>() .join("\n"), ), } } pub fn doc(&self) -> Value { match self { LFn::Declared { name } => { Value::String(Rc::new(format!("fn {name}: undefined function"))) } LFn::Defined { doc: Some(doc), .. } => Value::String(Rc::new(doc.to_string())), LFn::Defined { .. } => Value::String(Rc::new("no documentation found".to_string())), } } pub fn accepts(&self, arity: u8) -> bool { match self { LFn::Defined { arities, splat, .. } => { if arities.contains(&arity) { return true; } if *splat == 0 { return false; } let max_arity = arities.iter().fold(0, |a, b| a.max(*b)); arity > max_arity } LFn::Declared { .. } => unreachable!(), } } pub fn splat_arity(&self) -> u8 { match self { LFn::Defined { splat, .. } => *splat, LFn::Declared { .. } => unreachable!(), } } pub fn name(&self) -> &'static str { match self { LFn::Declared { name } | LFn::Defined { name, .. } => name, } } pub fn chunk(&self, arity: u8) -> &Chunk { match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { arities, splat, chunks, .. } => { let chunk_pos = arities.iter().position(|a| arity == *a); match chunk_pos { Some(pos) => &chunks[pos], None => &chunks[*splat as usize], } } } } pub fn upvalue(&self, idx: u8) -> Value { match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { closed, .. } => closed.borrow()[idx as usize].clone(), } } } #[derive(Clone, Debug, PartialEq)] pub struct Partial { pub args: Vec, pub name: &'static str, pub function: Value, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Key { Keyword(&'static str), Interned(&'static str), String(Rc), } impl std::fmt::Display for Key { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Key::Keyword(s) => write!(f, ":{s}"), Key::Interned(s) => write!(f, "\"{s}\""), Key::String(s) => write!(f, "\"{s}\""), } } } impl Serialize for Key { fn serialize(&self, srlzr: S) -> Result where S: Serializer, { match self { Key::Keyword(s) => srlzr.serialize_str(s), Key::Interned(s) => srlzr.serialize_str(s), Key::String(s) => srlzr.serialize_str(s.as_str()), } } } impl Key { pub fn to_value(&self) -> Value { match self { Key::Keyword(s) => Value::Keyword(s), Key::Interned(s) => Value::Interned(s), Key::String(s) => Value::String(s.clone()), } } pub fn from_value(value: Value) -> Key { match value { Value::Keyword(s) => Key::Keyword(s), Value::Interned(s) => Key::Interned(s), Value::String(s) => Key::String(s.clone()), _ => unreachable!("dict keys must be keywords or strings"), } } } #[derive(Clone, Debug)] pub enum Value { Nothing, Nil, True, False, Keyword(&'static str), Interned(&'static str), String(Rc), Number(NotNan), Tuple(Rc>), List(Box>), Dict(Box>), // not hashable b/c why? Box(Rc>), // not hashable b/c refcell Fn(Rc), // not hashable b/c refcell BaseFn(Box), Partial(Rc), Process, } impl PartialEq for Value { fn eq(&self, other: &Value) -> bool { use Value::*; match (self, other) { (Nothing, Nothing) | (Nil, Nil) | (True, True) | (False, False) => true, (Keyword(str1), Keyword(str2)) | (Interned(str1), Interned(str2)) => str1 == str2, (String(x), String(y)) => x == y, (String(x), Interned(y)) => x.as_ref() == y, (Interned(x), String(y)) => x == y.as_ref(), (Number(x), Number(y)) => x == y, (Tuple(x), Tuple(y)) => x == y, (List(x), List(y)) => x == y, (Dict(x), Dict(y)) => x == y, (Box(x), Box(y)) => std::ptr::eq(x.as_ref().as_ptr(), y.as_ref().as_ptr()), (Fn(x), Fn(y)) => std::ptr::eq(x, y), (BaseFn(x), BaseFn(y)) => std::ptr::eq(x, y), (Partial(x), Partial(y)) => x == y, _ => false, } } } impl std::fmt::Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { use Value::*; match self { Nothing => write!(f, "_"), Nil => write!(f, "nil"), True => write!(f, "true"), False => write!(f, "false"), Keyword(str) => write!(f, ":{str}"), Interned(str) => write!(f, "\"{str}\""), String(str) => write!(f, "\"{str}\""), Number(n) => write!(f, "{n}"), Process => write!(f, "Process"), Tuple(members) => write!( f, "({})", members .iter() .map(|x| x.to_string()) .collect::>() .join(", ") ), List(members) => write!( f, "[{}]", members .iter() .map(|x| x.to_string()) .collect::>() .join(", ") ), Dict(members) => write!( f, "#{{{}}}", members .iter() .map(|(k, v)| format!("{k} {v}")) .collect::>() .join(", ") ), Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()), Fn(lfn) => write!(f, "fn {}", lfn.name()), BaseFn(inner) => { let name = match **inner { crate::base::BaseFn::Nullary(name, _) | crate::base::BaseFn::Unary(name, _) | crate::base::BaseFn::Binary(name, _) | crate::base::BaseFn::Ternary(name, _) => name, }; write!(f, "fn {name}/base") } Partial(partial) => write!(f, "fn {}/partial", partial.name), } } } impl Serialize for Value { fn serialize(&self, srlzr: S) -> Result where S: Serializer, { use Value::*; match self { Nil => srlzr.serialize_none(), True => srlzr.serialize_bool(true), False => srlzr.serialize_bool(false), Number(n) => srlzr.serialize_f64(f64::from(*n)), Interned(s) => srlzr.serialize_str(s), Keyword(k) => srlzr.serialize_str(k), String(s) => srlzr.serialize_str(s.as_str()), Tuple(t) => { let mut seq = srlzr.serialize_seq(Some(t.len()))?; for e in t.iter() { seq.serialize_element(e)?; } seq.end() } List(l) => { let mut seq = srlzr.serialize_seq(Some(l.len()))?; for e in l.iter() { seq.serialize_element(e)?; } seq.end() } Dict(d) => { let mut map = srlzr.serialize_map(Some(d.len()))?; for (k, v) in d.iter() { map.serialize_entry(k, v)?; } map.end() } Box(b) => { let boxed = b.borrow(); (*boxed).serialize(srlzr) } Fn(..) | BaseFn(..) | Partial(..) => unreachable!(), Process | Nothing => unreachable!(), } } } impl Value { pub fn show(&self) -> String { use Value::*; let mut out = match &self { Process => "Process".to_string(), Nil => "nil".to_string(), True => "true".to_string(), False => "false".to_string(), Number(n) => format!("{n}"), Interned(str) => format!("\"{str}\""), String(str) => format!("\"{str}\""), Keyword(str) => format!(":{str}"), Tuple(t) => { let members = t.iter().map(|e| e.show()).collect::>().join(", "); format!("({members})") } List(l) => { let members = l.iter().map(|e| e.show()).collect::>().join(", "); format!("[{members}]") } Dict(d) => { let members = d .iter() .map(|(k, v)| { let value_show = v.show(); format!("{k} {value_show}") }) .collect::>() .join(", "); format!("#{{{members}}}") } Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()), Fn(lfn) => format!("fn {}", lfn.name()), Partial(partial) => format!("fn {}/partial", partial.name), BaseFn(_) => format!("{self}"), Nothing => "_".to_string(), }; if out.len() > 1000 { out.truncate(997); format!("{out}...") } else { out } } pub fn stringify(&self) -> String { use Value::*; match &self { Process => "process".to_string(), Nil => "nil".to_string(), True => "true".to_string(), False => "false".to_string(), Number(n) => format!("{n}"), Interned(str) => str.to_string(), Keyword(str) => format!(":{str}"), Tuple(t) => { let members = t .iter() .map(|e| e.stringify()) .collect::>() .join(", "); format!("({members})") } List(l) => { let members = l .iter() .map(|e| e.stringify()) .collect::>() .join(", "); format!("[{members}]") } Dict(d) => { let members = d .iter() .map(|(k, v)| { let value_show = v.stringify(); format!("{k} {value_show}") }) .collect::>() .join(", "); format!("#{{{members}}}") } String(s) => s.as_ref().clone(), Box(x) => x.as_ref().borrow().stringify(), Fn(lfn) => format!("fn {}", lfn.name()), Partial(partial) => format!("fn {}/partial", partial.name), BaseFn(_) => format!("{self}"), Nothing => unreachable!(), } } pub fn type_of(&self) -> &'static str { use Value::*; match self { Nothing => unreachable!(), Nil => "nil", True => "bool", False => "bool", Keyword(..) => "keyword", Interned(..) => "string", String(..) => "string", Number(..) => "number", Tuple(..) => "tuple", List(..) => "list", Dict(..) => "dict", Box(..) => "box", Fn(..) => "fn", BaseFn(..) => "fn", Partial(..) => "fn", Process => "process", } } pub fn as_fn(&self) -> &LFn { match self { Value::Fn(ref inner) => inner, _ => unreachable!("expected value to be fn"), } } pub fn as_list(&self) -> &Vector { match self { Value::List(ref inner) => inner, _ => unreachable!("expected value to be list"), } } pub fn as_box(&self) -> Rc> { match self { Value::Box(inner) => inner.clone(), _ => unreachable!("expected value to be a box"), } } pub fn as_string(&self) -> Rc { match self { Value::String(str) => str.clone(), Value::Interned(str) => Rc::new(str.to_string()), _ => unreachable!("expected value to be a string"), } } pub fn as_tuple(&self) -> Rc> { match self { Value::Tuple(members) => members.clone(), _ => unreachable!("expected value to be a tuple"), } } pub fn from_string(str: String) -> Value { Value::String(Rc::new(str)) } pub fn list(list: Vector) -> Value { Value::List(Box::new(list)) } pub fn new_list() -> Value { Value::list(Vector::new()) } pub fn r#box(value: Value) -> Value { Value::Box(Rc::new(RefCell::new(value))) } pub fn tuple(vec: Vec) -> Value { Value::Tuple(Rc::new(vec)) } pub fn from_f64(f: f64) -> Value { Value::Number(NotNan::new(f).unwrap()) } pub fn from_usize(n: usize) -> Value { Value::Number(NotNan::new(n as f64).unwrap()) } pub fn as_f64(&self) -> f64 { match self { Value::Number(n) => f64::from(*n), _ => unreachable!("expected value to be a number"), } } // pub fn get_shared_box(&self, name: &'static str) -> Value { // match self { // Value::Dict(dict) => dict // .get(name) // .expect("expected dict to have requested value") // .clone(), // _ => unreachable!("expected dict"), // } // } }