diff --git a/sl/src/grammar.lalrpop b/sl/src/grammar.lalrpop index b308c59..94639db 100644 --- a/sl/src/grammar.lalrpop +++ b/sl/src/grammar.lalrpop @@ -6,17 +6,17 @@ grammar; pub Term: Rc
= { NUM => Rc::new(Form::Int(i32::from_str(<>).unwrap())), - SYM => Rc::new(Form::Symbol(<>.to_owned())), + SYM => Rc::new(Form::Symbol(<>.to_owned(),None)), "(" ")" => <>.unwrap_or(Rc::new(Form::Nil)), - "'" => Rc::new(Form::Pair(Rc::new(Form::Symbol("quote".to_owned())), Rc::new(Form::Pair(<>, Rc::new(Form::Nil))))), + "'" => Rc::new(Form::Pair(Rc::new(Form::Symbol("quote".to_owned(),None)), Rc::new(Form::Pair(<>, Rc::new(Form::Nil),None)),None)), "!" => { h.append(t).unwrap() }, }; ListInside: Rc = { - => Rc::new(Form::Pair(<>, Rc::new(Form::Nil))), - => Rc::new(Form::Pair(h, t)), - "." => Rc::new(Form::Pair(a, d)), + => Rc::new(Form::Pair(<>, Rc::new(Form::Nil),None)), + => Rc::new(Form::Pair(h, t,None)), + "." => Rc::new(Form::Pair(a, d,None)), } match { "(", diff --git a/sl/src/lib.rs b/sl/src/lib.rs index b862149..4b1d45b 100644 --- a/sl/src/lib.rs +++ b/sl/src/lib.rs @@ -1,27 +1,52 @@ use std::rc::Rc; use std::collections::BTreeMap; use std::fmt; +use std::cell::RefCell; -use anyhow::{anyhow,Result}; +use anyhow::{anyhow,bail,Result}; -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub struct ID { + id: i64 +} + +#[derive(Debug)] pub enum Form { Nil, Int(i32), Bool(bool), - Symbol(String), - Pair(Rc,Rc), + Symbol(String, Option>), + Pair(Rc, Rc, Option>), + Closure(Vec, Rc>, Rc, Option>), Prim(Prim), } #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Prim { Add, + Sub, Mul, Eq, + Cons, + Car, + Cdr, } impl Form { + fn my_eq(&self, o: &Rc) -> bool { + match self { + Form::Nil => o.is_nil(), + Form::Int(i) => if let Ok(oi) = o.int() { *i == oi } else { false }, + Form::Bool(b) => if let Ok(ob) = o.bool() { *b == ob } else { false }, + Form::Symbol(s, _id) => if let Ok(os) = o.sym() { s == os } else { false }, + Form::Pair(a,b,_id) => if let Ok((oa,ob)) = o.pair() { a.my_eq(&oa) && b.my_eq(&ob) } else { false }, + Form::Closure(_, _, _, _) => false, + Form::Prim(p) => match &**o { Form::Prim(op) => p == op, _ => false }, + } + } + fn new_pair(car: Rc, cdr: Rc) -> Rc { + Rc::new(Form::Pair(car, cdr, None)) + } fn new_nil() -> Rc { Rc::new(Form::Nil) } @@ -31,6 +56,9 @@ impl Form { fn new_bool(b: bool) -> Rc { Rc::new(Form::Bool(b)) } + fn new_closure(params: Vec, env: Rc>, body: Rc) -> Rc { + Rc::new(Form::Closure(params, env, body, None)) + } fn truthy(&self) -> bool { match self { Form::Bool(b) => *b, @@ -38,6 +66,12 @@ impl Form { _ => true, } } + fn bool(&self) -> Result { + match self { + Form::Bool(b) => Ok(*b), + _ => Err(anyhow!("bool on not a bool")), + } + } fn int(&self) -> Result { match self { Form::Int(i) => Ok(*i), @@ -52,25 +86,25 @@ impl Form { } fn sym(&self) -> Result<&str> { match self { - Form::Symbol(s) => Ok(s), + Form::Symbol(s, _id) => Ok(s), _ => Err(anyhow!("sym on not a sym")), } } fn pair(&self) -> Result<(Rc,Rc)> { match self { - Form::Pair(car, cdr) => Ok((Rc::clone(car),Rc::clone(cdr))), + Form::Pair(car, cdr, _id) => Ok((Rc::clone(car),Rc::clone(cdr))), _ => Err(anyhow!("pair on not a pair")), } } fn car(&self) -> Result> { match self { - Form::Pair(car, _cdr) => Ok(Rc::clone(car)), + Form::Pair(car, _cdr, _id) => Ok(Rc::clone(car)), _ => Err(anyhow!("car on not a pair")), } } fn cdr(&self) -> Result> { match self { - Form::Pair(_car, cdr) => Ok(Rc::clone(cdr)), + Form::Pair(_car, cdr, _id) => Ok(Rc::clone(cdr)), _ => Err(anyhow!("cdr on not a pair")), } } @@ -82,52 +116,150 @@ impl Form { } pub fn append(&self, x: Rc) -> Result> { match self { - Form::Pair(car, cdr) => cdr.append(x).map(|x| Rc::new(Form::Pair(Rc::clone(car), x))), - Form::Nil => Ok(Rc::new(Form::Pair(x, Rc::new(Form::Nil)))), + Form::Pair(car, cdr, _id) => cdr.append(x).map(|x| Rc::new(Form::Pair(Rc::clone(car), x, None))), + Form::Nil => Ok(Rc::new(Form::Pair(x, Rc::new(Form::Nil), None))), _ => Err(anyhow!("append to not a pair")), } } } +#[derive(Debug)] pub struct Env { + u: Option>>, m: BTreeMap> } impl Env { - pub fn root_env() -> Env { - Env { + pub fn root_env() -> Rc> { + Rc::new(RefCell::new(Env { + u: None, m: [ ("+", Rc::new(Form::Prim(Prim::Add))), + ("-", Rc::new(Form::Prim(Prim::Sub))), ("*", Rc::new(Form::Prim(Prim::Mul))), + ("cons", Rc::new(Form::Prim(Prim::Cons))), + ("cdr", Rc::new(Form::Prim(Prim::Cdr))), + ("car", Rc::new(Form::Prim(Prim::Car))), ("=", Rc::new(Form::Prim(Prim::Eq))), + ("nil", Form::new_nil()), ].into_iter().map(|(s,p)| (s.to_owned(), p)).collect() - } + })) + } + pub fn chain(o: &Rc>) -> Rc> { + Rc::new(RefCell::new(Env { + u: Some(Rc::clone(o)), + m: BTreeMap::new(), + })) } pub fn lookup(&self, s: &str) -> Result> { - Ok(Rc::clone(self.m.get(s).ok_or(anyhow!("lookup failed"))?)) + if let Some(r) = self.m.get(s) { + Ok(Rc::clone(r)) + } else if let Some(u) = &self.u { + u.borrow().lookup(s) + } else { + bail!("lookup of {s} failed") + } + } + pub fn define(&mut self, s: String, v: Rc) { + self.m.insert(s, v); } } -pub fn tree_walker_eval(f: Rc, e: &mut Env) -> Result> { +// add functions +// variables +// optimized as a function based off side table of id keyed -> opt +// that id might be nice for debugging too +// Symbol ID's could actually be used for environment lookups +// this is just interning + +pub fn tree_walker_eval(f: Rc, e: Rc>) -> Result> { + println!("tree_walker_eval({f})"); Ok(match &*f { - Form::Symbol(s) => e.lookup(s)?, - Form::Pair(car, cdr) => { + Form::Symbol(s, _id) => e.borrow().lookup(s)?, + Form::Pair(car, cdr, _id) => { match &**car { - Form::Symbol(s) if s == "if" => { - if tree_walker_eval(cdr.car()?, e)?.truthy() { + Form::Symbol(s, _id) if s == "if" => { + if tree_walker_eval(cdr.car()?, Rc::clone(&e))?.truthy() { tree_walker_eval(cdr.cdr()?.car()?, e)? } else { tree_walker_eval(cdr.cdr()?.cdr()?.car()?, e)? } } + Form::Symbol(s, _id) if s == "begin" => { + let mut last_result = Form::new_nil(); + let mut traverse = Rc::clone(cdr); + while let Ok((ncar, ncdr)) = traverse.pair() { + traverse = ncdr; + last_result = tree_walker_eval(ncar, Rc::clone(&e))?; + } + last_result + + } + Form::Symbol(s, _id) if s == "debug" => { + println!("debug: {}", tree_walker_eval(cdr.car()?, e)?); + Form::new_nil() + } + // This is a fast and loose ~simple lisp~, so just go for it + // and can have convention that this is always top levelish + Form::Symbol(s, _id) if s == "define" => { + let v = tree_walker_eval(cdr.cdr()?.car()?, Rc::clone(&e))?; + e.borrow_mut().define(cdr.car()?.sym()?.to_string(), v); + Form::new_nil() + } + Form::Symbol(s, _id) if s == "quote" => { + cdr.car()? + } + // (lambda (a b) body) + Form::Symbol(s, _id) if s == "lambda" => { + let mut params_vec = vec![]; + let mut params = cdr.car()?; + while let Ok((ncar, ncdr)) = params.pair() { + params_vec.push(ncar.sym()?.to_string()); + params = ncdr; + } + let body = cdr.cdr()?.car()?; + Form::new_closure(params_vec, Rc::clone(&e), body) + } _ => { - let comb = tree_walker_eval(Rc::clone(car), e)?; - let a = tree_walker_eval(cdr.car()?, e)?; - let b = tree_walker_eval(cdr.cdr()?.car()?, e)?; - match comb.prim().unwrap() { - Prim::Add => Form::new_int(a.int()? + b.int()?), - Prim::Mul => Form::new_int(a.int()? * b.int()?), - Prim::Eq => Form::new_bool(a == b), + let comb = tree_walker_eval(Rc::clone(car), Rc::clone(&e))?; + match &*comb { + Form::Closure(ps, ie, b, id) => { + let mut arguments_vec = vec![]; + let mut arguments = Rc::clone(cdr); + while let Ok((ncar, ncdr)) = arguments.pair() { + arguments_vec.push(tree_walker_eval(ncar, Rc::clone(&e))?); + arguments = ncdr; + } + if ps.len() != arguments_vec.len() { + bail!("arguments length doesn't match"); + } + let new_env = Env::chain(&e); + for (name, value) in ps.iter().zip(arguments_vec.into_iter()) { + new_env.borrow_mut().define(name.to_string(), value); + } + tree_walker_eval(Rc::clone(b), new_env)? + }, + Form::Prim(p) => { + let a = tree_walker_eval(cdr.car()?, Rc::clone(&e))?; + match comb.prim().unwrap() { + Prim::Car => a.car()?, + Prim::Cdr => a.cdr()?, + _ => { + let b = tree_walker_eval(cdr.cdr()?.car()?, Rc::clone(&e))?; + match comb.prim().unwrap() { + Prim::Add => Form::new_int(a.int()? + b.int()?), + Prim::Sub => Form::new_int(a.int()? - b.int()?), + Prim::Mul => Form::new_int(a.int()? * b.int()?), + Prim::Cons => Form::new_pair(a, b), + Prim::Eq => Form::new_bool(a.my_eq(&b)), + _ => unreachable!(), + } + } + } + }, + _ => { + bail!("tried to call a non-comb {}", comb) + }, } } } @@ -137,13 +269,13 @@ pub fn tree_walker_eval(f: Rc, e: &mut Env) -> Result> { } // todo, strings not symbols? -impl From for Form { fn from(item: String) -> Self { Form::Symbol(item) } } -impl From<&str> for Form { fn from(item: &str) -> Self { Form::Symbol(item.to_owned()) } } +impl From for Form { fn from(item: String) -> Self { Form::Symbol(item, None) } } +impl From<&str> for Form { fn from(item: &str) -> Self { Form::Symbol(item.to_owned(), None) } } impl From for Form { fn from(item: i32) -> Self { Form::Int(item) } } impl From for Form { fn from(item: bool) -> Self { Form::Bool(item) } } impl, B: Into> From<(A, B)> for Form { fn from(item: (A, B)) -> Self { - Form::Pair(Rc::new(item.0.into()), Rc::new(item.1.into())) + Form::Pair(Rc::new(item.0.into()), Rc::new(item.1.into()), None) } } @@ -153,13 +285,13 @@ impl fmt::Display for Form { Form::Nil => write!(f, "nil"), Form::Int(i) => write!(f, "{i}"), Form::Bool(b) => write!(f, "{b}"), - Form::Symbol(s) => write!(f, "'{s}"), - Form::Pair(car, cdr) => { + Form::Symbol(s, _id) => write!(f, "'{s}"), + Form::Pair(car, cdr, _id) => { write!(f, "({}", car)?; let mut traverse: Rc = Rc::clone(cdr); loop { match &*traverse { - Form::Pair(ref carp, ref cdrp) => { + Form::Pair(ref carp, ref cdrp, ref _id) => { write!(f, " {}", carp)?; traverse = Rc::clone(cdrp); }, @@ -174,10 +306,17 @@ impl fmt::Display for Form { } } }, + Form::Closure(params, inner_env, code, id) => { + write!(f, "", params) + } Form::Prim(p) => { match p { Prim::Add => write!(f, "+"), + Prim::Sub => write!(f, "-"), Prim::Mul => write!(f, "*"), + Prim::Cons => write!(f, "cons"), + Prim::Car => write!(f, "car"), + Prim::Cdr => write!(f, "cdr"), Prim::Eq => write!(f, "="), } } diff --git a/sl/src/main.rs b/sl/src/main.rs index cd90476..b733987 100644 --- a/sl/src/main.rs +++ b/sl/src/main.rs @@ -7,12 +7,29 @@ use anyhow::Result; use sl::{tree_walker_eval, Env}; fn main() -> Result<()> { - let input = "(if (= 1 2) (+ 2 3) (* 2 2))"; + let input = " + (begin + (debug 1) + (debug (= 1 2)) + (debug (+ 2 3)) + (define a (+ 1 (* 3 4))) + (define fact (lambda (n) (if (= n 1) 1 (* n (fact (- n 1)))))) + (debug 'gonna_fact_it) + (debug fact) + (debug (fact 5)) + (debug a) + (define b (cons 1 (cons 2 (cons 3 nil)))) + (debug b) + (debug (car b)) + (debug (cdr b)) + (if (= 1 2) (+ 2 3) (* 2 2)) + ) + "; let parsed_input = Rc::new(grammar::TermParser::new().parse(input)?); //println!("Hello, world: {parsed_input:?}"); println!("Hello, world: {parsed_input}"); - let mut e = Env::root_env(); - let tree_walker_evaled = tree_walker_eval(Rc::clone(&parsed_input), &mut e)?; + let e = Env::root_env(); + let tree_walker_evaled = tree_walker_eval(Rc::clone(&parsed_input), e)?; println!("tree walker evaled: {tree_walker_evaled}"); Ok(()) }