use crate::base::BaseFn; use crate::compiler::Chunk; use crate::parser::Ast; use crate::spans::Spanned; use imbl::{HashMap, Vector}; use std::cell::{OnceCell, RefCell}; use std::rc::Rc; #[derive(Clone, Debug, PartialEq)] pub struct LFn { pub name: &'static str, pub doc: Option<&'static str>, // pub enclosing: Vec<(usize, Value)>, // pub has_run: bool, // pub input: &'static str, // pub src: &'static str, pub chunks: Vec<(u8, Chunk)>, pub closed: Vec, } impl LFn { pub fn close(&mut self, val: Value) { self.closed.push(val); } } #[derive(Clone, Debug)] pub enum Value { Nothing, Nil, True, False, Keyword(&'static str), Interned(&'static str), String(Rc), Number(f64), Tuple(Rc>), List(Box>), Dict(Box>), Box(Rc>), Fn(Rc>), BaseFn(BaseFn), } 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)) => x == y, (BaseFn(x), BaseFn(y)) => std::ptr::eq(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}"), 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.get().unwrap().name), BaseFn(_) => write!(f, "base fn"), } } } impl Value { pub fn show(&self) -> String { use Value::*; match &self { Nil => "nil".to_string(), True => "true".to_string(), False => "false".to_string(), Number(n) => format!("{n}"), Interned(str) => format!("\"{str}\""), String(str) => { let str_str = str.to_string(); format!("\"{str_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 key_show = Value::Keyword(k).show(); let value_show = v.show(); format!("{key_show} {value_show}") }) .collect::>() .join(", "); format!("#{{{members}}}") } Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()), Fn(lfn) => format!("fn {}", lfn.get().unwrap().name), BaseFn(_) => "base fn".to_string(), Nothing => unreachable!(), } } pub fn stringify(&self) -> String { use Value::*; match &self { Nil => "nil".to_string(), True => "true".to_string(), False => "false".to_string(), Number(n) => format!("{n}"), Interned(str) => str.to_string(), Keyword(str) => str.to_string(), Tuple(t) => { let members = t .iter() .map(|e| e.stringify()) .collect::>() .join(", "); members.to_string() } List(l) => { let members = l .iter() .map(|e| e.stringify()) .collect::>() .join(", "); members.to_string() } Dict(d) => { let members = d .iter() .map(|(k, v)| { let key_show = Value::Keyword(k).stringify(); let value_show = v.stringify(); format!("{key_show} {value_show}") }) .collect::>() .join(", "); members.to_string() } String(s) => s.as_ref().clone(), Box(x) => x.as_ref().borrow().stringify(), Fn(lfn) => lfn.get().unwrap().name.to_string(), _ => todo!(), } } 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", } } }