use crate::base::BaseFn; use crate::compiler::Chunk; use crate::parser::Ast; use crate::spans::Spanned; use imbl::{HashMap, Vector}; 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>, chunks: Vec<(u8, Chunk)>, closed: RefCell>, }, } impl LFn { pub fn close(&self, value: Value) { match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { closed, .. } => { closed.borrow_mut().push(value); } } } pub fn doc(&self) -> Value { match self { LFn::Declared { name } => { Value::String(Rc::new(format!("fn {name}: undefined function"))) } LFn::Defined { name, doc: Some(doc), .. } => Value::String(Rc::new(format!("fn {name}\n{doc}"))), LFn::Defined { name, .. } => { Value::String(Rc::new(format!("fn {name}: no documentation"))) } } } pub fn name(&self) -> &'static str { match self { LFn::Declared { name } | LFn::Defined { name, .. } => name, } } pub fn chunk(&self, arity: u8) -> &Chunk { // println!("Getting chunk of {arity} from {:?}", self); match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { chunks, .. } => &chunks.iter().find(|(a, _)| *a == arity).unwrap().1, } } 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)] 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), Partial(Rc), } 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}"), 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(_) => write!(f, "base fn"), Partial(partial) => write!(f, "fn {}/partial", partial.name), } } } 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.name()), Partial(partial) => format!("fn {}/partial", partial.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) => format!("fn {}", lfn.name()), _ => 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", Partial(..) => "fn", } } }