use std::fmt; use std::rc::Rc; use std::convert::From; use std::collections::{BTreeSet,BTreeMap,hash_map::DefaultHasher}; use std::result::Result; use std::iter; use std::hash::{Hash,Hasher}; // TODO: // -extend vau & env logic and SuspendedPair PE with sequence_params & wrap_level // -add veval and vif & -1 wrap_level handling to SuspendedPair // -add current-hashes to if, DeriComb Calls, and DCtx-push/can_progress, and Hash to *everything* // -expand combiner_Return_ok with (veval body {env}) and (func ...params) | func doesn't take de and func+params are return ok // -add drop redundent veval // -add compiler impl From for Form { fn from(item: i32) -> Self { Form::Int(item) } } impl From for Form { fn from(item: bool) -> Self { Form::Bool(item) } } // 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, 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())) } } pub enum PossibleTailCall { Result(Rc), TailCall(Rc, Rc), } #[derive(Debug, Eq, PartialEq)] pub enum Form { Nil, Int(i32), Bool(bool), Symbol(String), Pair(Rc,Rc), PrimComb(String, fn(Rc, Rc) -> PossibleTailCall), DeriComb { se: Rc, de: Option, params: String, body: Rc }, } impl Form { pub fn truthy(&self) -> bool { match self { Form::Bool(b) => *b, Form::Nil => false, _ => true, } } pub fn int(&self) -> Option { match self { Form::Int(i) => Some(*i), _ => None, } } pub fn sym(&self) -> Option<&str> { match self { Form::Symbol(s) => Some(s), _ => None, } } pub fn car(&self) -> Option> { match self { Form::Pair(car, _cdr) => Some(Rc::clone(car)), _ => None, } } pub fn cdr(&self) -> Option> { match self { Form::Pair(_car, cdr) => Some(Rc::clone(cdr)), _ => None, } } pub fn append(&self, x: Rc) -> Option { match self { Form::Pair(car, cdr) => cdr.append(x).map(|x| Form::Pair(Rc::clone(car), Rc::new(x))), Form::Nil => Some(Form::Pair(x, Rc::new(Form::Nil))), _ => None, } } pub fn marked(&self, bctx: BCtx) -> (BCtx, Rc) { match &*self { Form::Nil => (bctx, Rc::new(MarkedForm::Nil)), Form::Int(i) => (bctx, Rc::new(MarkedForm::Int(*i))), Form::Bool(b) => (bctx, Rc::new(MarkedForm::Bool(*b))), Form::Symbol(s) => (bctx, Rc::new(MarkedForm::Symbol(s.clone()))), Form::Pair(car, cdr) => { let (bctx, car) = car.marked(bctx); let (bctx, cdr) = cdr.marked(bctx); (bctx, MarkedForm::new_pair(car, cdr)) }, Form::DeriComb { se, de, params, body } => { // this is a bit sus, but we don't run into it as of yet panic!(); //let (bctx, se) = se.marked(bctx); //let (bctx, body) = body.marked(bctx); //let (bctx, new_id) = bctx.new_id(); //(bctx, Rc::new(MarkedForm::DeriComb { ids: NeededIds::new_none(), se, de: de.clone(), // id: new_id, wrap_level: 0, sequence_params: vec![], // rest_params: Some(params.clone()), body })) }, Form::PrimComb(name, _f) => { (bctx, match &name[..] { "eval" => Rc::new(MarkedForm::PrimComb { name: "eval".to_owned(), takes_de: true, wrap_level: 1, f: |bctx, dctx, p| { // put in partial eval logic, // and veval let b = p.car()?.unval()?; let e = p.cdr()?.car()?; //println!("Doing Eval (via tail call) of {} in {}", b, e); Ok((bctx, PossibleMarkedTailCall::TailCall(e, b))) }}), "vau" => Rc::new(MarkedForm::PrimComb { name: "vau".to_owned(), takes_de: true, wrap_level: 0, f: |bctx, dctx, p| { let de = p.car()?.sym().map(|s| s.to_owned()).ok(); let params = p.cdr()?.car()?.sym()?.to_owned(); let body = p.cdr()?.cdr()?.car()?.unval()?; let se = Rc::clone(&dctx.e); let (bctx, id) = bctx.new_id(); // TODO: figure out wrap level, sequence params, etc let wrap_level = 0; let sequence_params = vec![]; let rest_params = Some(params); // let inner_dctx = dctx.copy_push_frame(id.clone(), &se, &de, None, &rest_params, None, &body).unwrap(); let (bctx, body) = partial_eval(bctx, inner_dctx, Rc::clone(&body))?; Ok((bctx, PossibleMarkedTailCall::Result(MarkedForm::new_deri_comb( se, None, de, id, wrap_level, sequence_params, rest_params, body )))) }}), // TODO: handle vif, partial eval branches "if" => Rc::new(MarkedForm::PrimComb { name: "if".to_owned(), takes_de: true, wrap_level: 0, f: |bctx, dctx, p| { let (bctx, cond) = partial_eval(bctx, dctx.clone(), p.car()?.unval()?)?; let e = Rc::clone(&dctx.e); if cond.truthy()? { Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?.unval()?))) } else { Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.cdr()?.car()?.unval()?))) } }}), // TODO: handle these in the context of paritals "cons" => Rc::new(MarkedForm::PrimComb { name: "cons".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let h = p.car()?; let t = p.cdr()?.car()?; Ok((bctx, PossibleMarkedTailCall::Result(MarkedForm::new_pair(h, t)))) }}), "car" => Rc::new(MarkedForm::PrimComb { name: "car".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(p.car()?.car()?))) }}), "cdr" => Rc::new(MarkedForm::PrimComb { name: "cdr".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(p.car()?.cdr()?))) }}), "quote" => Rc::new(MarkedForm::PrimComb { name: "quote".to_owned(), takes_de: false, wrap_level: 0, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(p.car()?))) }}), // This one needs to control eval to print debug before continuint // which is werid to PE "debug" => Rc::new(MarkedForm::PrimComb { name: "debug".to_owned(), takes_de: true, wrap_level: 0, f: |bctx, dctx, p| { panic!(); let e = Rc::clone(&dctx.e); Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?))) }}), // ditto "assert" => Rc::new(MarkedForm::PrimComb { name: "assert".to_owned(), takes_de: true, wrap_level: 0, f: |bctx, dctx, p| { //panic!(); println!("Assert test {:?}", p.car()); let (bctx, cond) = partial_eval(bctx, dctx.clone(), p.car()?.unval()?)?; println!("\tAssert result {}", cond); if !cond.truthy()? { println!("Assert failed: {:?}", cond); } assert!(cond.truthy()?); let e = Rc::clone(&dctx.e); Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?.unval()?))) }}), // (vau de params body), should be able to take in wrap_level != 1 and do stuff "=" => Rc::new(MarkedForm::PrimComb { name: "=".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?; let b = p.cdr()?.car()?; //println!("DOing (= {} {}) = {}", a, b, a==b); // TODO: double check that this ignores ids etc. It should, since // wrap_level=1 should mean that everything's a value // also, it should just check by hash then? Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a == b))))) }}), "<" => Rc::new(MarkedForm::PrimComb { name: "<".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?; let b = p.cdr()?.car()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? < b.int()?))))) }}), ">" => Rc::new(MarkedForm::PrimComb { name: ">".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?; let b = p.cdr()?.car()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? > b.int()?))))) }}), "<=" => Rc::new(MarkedForm::PrimComb { name: "<=".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?; let b = p.cdr()?.car()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? <= b.int()?))))) }}), ">=" => Rc::new(MarkedForm::PrimComb { name: ">=".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?; let b = p.cdr()?.car()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? >= b.int()?))))) }}), "+" => Rc::new(MarkedForm::PrimComb { name: "+".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a + b))))) }}), "-" => Rc::new(MarkedForm::PrimComb { name: "-".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a - b))))) }}), "*" => Rc::new(MarkedForm::PrimComb { name: "*".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a * b))))) }}), "/" => Rc::new(MarkedForm::PrimComb { name: "/".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a / b))))) }}), "%" => Rc::new(MarkedForm::PrimComb { name: "%".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a % b))))) }}), "&" => Rc::new(MarkedForm::PrimComb { name: "&".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a & b))))) }}), "|" => Rc::new(MarkedForm::PrimComb { name: "|".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a | b))))) }}), "^" => Rc::new(MarkedForm::PrimComb { name: "^".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { let a = p.car()?.int()?; let b = p.cdr()?.car()?.int()?; Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a ^ b))))) }}), "comb?" => Rc::new(MarkedForm::PrimComb { name: "comb?".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { MarkedForm::PrimComb { .. } => true, MarkedForm::DeriComb { .. } => true, _ => false, }))))) }}), "pair?" => Rc::new(MarkedForm::PrimComb { name: "pair?".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { MarkedForm::Pair(_h, _i, _a,_b) => true, _ => false, }))))) }}), "symbol?" => Rc::new(MarkedForm::PrimComb { name: "symbol?".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { MarkedForm::Symbol(_) => true, _ => false, }))))) }}), "int?" => Rc::new(MarkedForm::PrimComb { name: "int?".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { MarkedForm::Int(_) => true, _ => false, }))))) }}), // maybe bool? but also could be derived. Nil def "bool?" => Rc::new(MarkedForm::PrimComb { name: "bool?".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { MarkedForm::Bool(_) => true, _ => false, }))))) }}), "nil?" => Rc::new(MarkedForm::PrimComb { name: "nil?".to_owned(), takes_de: false, wrap_level: 1, f: |bctx, dctx, p| { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { MarkedForm::Nil => true, _ => false, }))))) }}), _ => panic!("gah! don't have partial eval version of {}", name), }) }, } } } impl fmt::Display for Form { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { 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) => { write!(f, "({}", car)?; let mut traverse: Rc = Rc::clone(cdr); loop { match &*traverse { Form::Pair(ref carp, ref cdrp) => { write!(f, " {}", carp)?; traverse = Rc::clone(cdrp); }, Form::Nil => { write!(f, ")")?; return Ok(()); }, x => { write!(f, ". {})", x)?; return Ok(()); }, } } }, Form::PrimComb(name, _f) => write!(f, "<{}>", name), Form::DeriComb { se, de, params, body } => { write!(f, "<{} {} {}>", de.as_ref().unwrap_or(&"".to_string()), params, body) }, } } } #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct EnvID(i32); #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct MFHash(u64); impl MFHash { pub fn combine(&self, other: &MFHash) -> Self { let mut h = DefaultHasher::new(); "combine/".hash(&mut h); self.0.hash(&mut h); other.hash(&mut h); MFHash(h.finish()) } } #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub enum NeededIds { True(BTreeSet), None(BTreeSet), Some(BTreeSet,BTreeSet), } impl NeededIds { fn new_true() -> Self { NeededIds::True( BTreeSet::new()) } fn new_none() -> Self { NeededIds::None( BTreeSet::new()) } fn new_single(i: EnvID) -> Self { NeededIds::Some(iter::once(i).collect(), BTreeSet::new()) } fn needs_nothing(&self) -> bool { match self { NeededIds::True(hashes) => false, NeededIds::None(hashes) => hashes.is_empty(), NeededIds::Some(set,hashes) => false, } } fn hashes(&self) -> &BTreeSet { match self { NeededIds::True(hashes) => hashes, NeededIds::None(hashes) => hashes, NeededIds::Some(set,hashes) => hashes, } } fn union(&self, other: &NeededIds) -> Self { match self { NeededIds::True(hashes) => NeededIds::True(hashes.union(other.hashes()).cloned().collect()), NeededIds::None(hashes) => other.union_hashes(hashes), NeededIds::Some(set, hashes) => match other { NeededIds::True(ohashes) => NeededIds::True(hashes.union(ohashes).cloned().collect()), NeededIds::None(ohashes) => NeededIds::Some(set.clone(), hashes.union(ohashes).cloned().collect()), NeededIds::Some(oset,ohashes) => NeededIds::Some(set.union(oset).cloned().collect(), hashes.union(ohashes).cloned().collect()), }, } } fn union_without(&self, other: &NeededIds, without: EnvID) -> Self { self.union(other).without(without) } fn without(self, without: EnvID) -> Self { match self { NeededIds::True(_) => self, NeededIds::None(_) => self, NeededIds::Some(set, hashes) => { let new: BTreeSet = set.into_iter().filter(|x| *x != without).collect(); if new.is_empty() { NeededIds::None(hashes) } else { NeededIds::Some(new, hashes) } }, } } fn union_hashes(&self, other: &BTreeSet) -> Self { match self { NeededIds::True(hashes) => NeededIds::True( other.union(hashes).cloned().collect()), NeededIds::None(hashes) => NeededIds::None( other.union(hashes).cloned().collect()), NeededIds::Some(set, hashes) => NeededIds::Some(set.clone(), other.union(hashes).cloned().collect()), } } fn add_hash(&self, h: MFHash) -> Self { match self { NeededIds::True(hashes) => NeededIds::True( hashes.iter().cloned().chain(iter::once(h)).collect()), NeededIds::None(hashes) => NeededIds::None( hashes.iter().cloned().chain(iter::once(h)).collect()), NeededIds::Some(set, hashes) => NeededIds::Some(set.clone(), hashes.iter().cloned().chain(iter::once(h)).collect()), } } fn add_id(&self, i: EnvID) -> Self { match self { NeededIds::True(hashes) => NeededIds::True( hashes.clone()), NeededIds::None(hashes) => NeededIds::Some(iter::once(i).collect(), hashes.clone()), NeededIds::Some(set, hashes) => NeededIds::Some(set.iter().cloned().chain(iter::once(i)).collect(), hashes.clone()), } } } pub enum PossibleMarkedTailCall { Result(Rc), TailCall(Rc, Rc), } #[derive(Clone)] pub struct BCtx { id_counter: i32 } impl BCtx { pub fn new_id(mut self) -> (Self, EnvID) { let new_id = EnvID(self.id_counter); self.id_counter += 1; (self, new_id) } } // force is for drop_redundent_eval // memo is only for recording currently executing hashes (calls and if's, current for us) // only_head is not currently used //only_head env env_counter memo env_stack force #[derive(Clone)] pub struct DCtx { e : Rc, sus_env_stack: Rc>>, sus_prm_stack: Rc>>, real_set: Rc>, force: bool, current: Rc>, ident: usize, } impl DCtx { pub fn copy_set_env(&self, e: &Rc) -> Self { DCtx { e: Rc::clone(e), sus_env_stack: Rc::clone(&self.sus_env_stack), sus_prm_stack: Rc::clone(&self.sus_prm_stack), real_set: Rc::clone(&self.real_set), force: self.force, current: Rc::clone(&self.current), ident: self.ident+1 } } pub fn copy_push_frame(&self, id: EnvID, se: &Rc, de: &Option, e: Option>, rest_params: &Option, prms: Option>, body: &Rc) -> Result { let mut sus_env_stack = Rc::clone(&self.sus_env_stack); let mut sus_prm_stack = Rc::clone(&self.sus_prm_stack); let mut real_set = Rc::clone(&self.real_set); if (e.is_some() || prms.is_some()) { Rc::make_mut(&mut real_set).insert(id.clone()); } let inner_env = if let Some(de) = de { let de_val = if let Some(e) = e { Rc::make_mut(&mut sus_env_stack).insert(id.clone(), Rc::clone(&e)); e } else { Rc::new(MarkedForm::SuspendedEnvLookup { name: Some(de.clone()), id: id.clone() }) }; massoc(de, de_val, Rc::clone(se)) } else { Rc::clone(se) }; // not yet supporting sequence params let inner_env = if let Some(p) = rest_params { let p_val = if let Some(prms) = prms { Rc::make_mut(&mut sus_prm_stack).insert(id.clone(), Rc::clone(&prms)); prms } else { Rc::new(MarkedForm::SuspendedParamLookup { name: Some(p.clone()), id: id.clone(), cdr_num: 0, car: false }) }; massoc(p, p_val, inner_env) } else { inner_env }; // Push on current frame hash let new_hash = inner_env.hash().combine(&body.hash()); if self.current.contains(&new_hash) { println!("Hash Rec Stop!"); Err(new_hash) } else { let new_current = Rc::new(self.current.iter().cloned().chain(iter::once(new_hash)).collect()); Ok(DCtx { e: inner_env, sus_env_stack, sus_prm_stack, real_set, force: self.force, current: new_current, ident: self.ident+1 }) } } pub fn can_progress(&self, ids: NeededIds) -> bool { // check if ids is true || ids intersection EnvIDs in our stacks is non empty || ids.hashes - current is non empty match ids { NeededIds::True(hashes) => true, NeededIds::None(hashes) => !self.current.is_superset(&hashes), NeededIds::Some(ids,hashes) => (!self.real_set.is_disjoint(&ids)) || (!self.current.is_superset(&hashes)), } } } pub fn new_base_ctxs() -> (BCtx,DCtx) { let bctx = BCtx { id_counter: 0 }; let (bctx, root_env) = root_env().marked(bctx); (bctx, DCtx { e: root_env, sus_env_stack: Rc::new(BTreeMap::new()), sus_prm_stack: Rc::new(BTreeMap::new()), real_set: Rc::new(BTreeSet::new()), force: false, current: Rc::new(BTreeSet::new()), ident: 0 } ) } pub fn combiner_return_ok(x: Rc, check_id: EnvID) -> bool { match match &*x { MarkedForm::Nil => return true, MarkedForm::Int(_) => return true, MarkedForm::Bool(_) => return true, MarkedForm::Symbol(_) => return true, MarkedForm::Pair(h,ids,_,_) => ids, MarkedForm::SuspendedSymbol(_) => return false, MarkedForm::SuspendedParamLookup { id, .. } => return *id != check_id, MarkedForm::SuspendedEnvLookup { id, .. } => return *id != check_id, MarkedForm::SuspendedPair { .. } => { // expand with (veval body {env}) and (func ...params) | func doesn't take de and func+params are return ok return false }, MarkedForm::PrimComb { .. } => return true, MarkedForm::DeriComb { ids, .. } => ids, } { NeededIds::True(_hashes) => false, NeededIds::None(_hashes) => true, NeededIds::Some(ids,_hashes) => !ids.contains(&check_id), } //; Handles let 4.3 through macro level leaving it as ( 13) //; need handling of symbols (which is illegal for eval but ok for calls) to push it farther //(combiner_return_ok (rec-lambda combiner_return_ok (func_result env_id) // (cond ((not (later_head? func_result)) (not (check_for_env_id_in_result env_id func_result))) // ; special cases now // ; *(veval body {env}) => (combiner_return_ok {env}) // ; The reason we don't have to check body is that this form is only creatable in ways that body was origionally a value and only need {env} // ; Either it's created by eval, in which case it's fine, or it's created by something like (eval (array veval x de) de2) and the array has checked it, // ; or it's created via literal vau invocation, in which case the body is a value. // ((and (marked_array? func_result) // (prim_comb? (idx (.marked_array_values func_result) 0)) // (= 'veval (.prim_comb_sym (idx (.marked_array_values func_result) 0))) // (= 3 (len (.marked_array_values func_result))) // (combiner_return_ok (idx (.marked_array_values func_result) 2) env_id)) true) // ; (func ...params) => (and (doesn't take de func) (foldl combiner_return_ok (cons func params))) // ; // ((and (marked_array? func_result) // (not (comb_takes_de? (idx (.marked_array_values func_result) 0) (len (.marked_array_values func_result)))) // (foldl (lambda (a x) (and a (combiner_return_ok x env_id))) true (.marked_array_values func_result))) true) // ; So that's enough for macro like, but we would like to take it farther // ; For like (let1 a 12 (wrap (vau (x) (let1 y (+ a 1) (+ y x a))))) // ; we get to (+ 13 x 12) not being a value, and it reconstructs // ; ( 13) // ; and that's what eval gets, and eval then gives up as well. // ; That will get caught by the above cases to remain the expansion ( 13), // ; but ideally we really want another case to allow (+ 13 x 12) to bubble up // ; I think it would be covered by the (func ...params) case if a case is added to allow symbols to be bubbled up if their // ; needed for progress wasn't true or the current environment, BUT this doesn't work for eval, just for functions, // ; since eval changes the entire env chain (but that goes back to case 1, and might be eliminated at compile if it's an env reachable from the func). // ; // ; // ; Do note a key thing to be avoided is allowing any non-val inside a comb, since that can cause a fake env's ID to // ; reference the wrong env/comb in the chain. // ; We do allow calling eval with a fake env, but since it's only callable withbody value and is strict (by calling this) // ; about it's return conditions, and the env it's called with must be ok in the chain, and eval doesn't introduce a new scope, it works ok. // ; We do have to be careful about allowing returned later symbols from it though, since it could be an entirely different env chain. // (true false) // ) //)) } pub fn partial_eval(bctx: BCtx, dctx: DCtx, x: Rc) -> Result<(BCtx,Rc), String> { //println!("{:ident$}PE: {}", "", x, ident=dctx.ident*4); let should_go = dctx.force || dctx.can_progress(x.ids()); if !should_go { //println!("{:ident$}Shouldn't go!", "", ident=dctx.ident*4); return Ok((bctx, x)); } match &*x { MarkedForm::SuspendedSymbol(name) => { let mut t = Rc::clone(&dctx.e); while name != t.car()?.car()?.sym()? { t = t.cdr()?; } Ok((bctx, t.car()?.cdr()?.tag_name(name))) }, MarkedForm::SuspendedEnvLookup { name, id } => { if let Some(v) = dctx.sus_env_stack.get(id) { if let Some(name) = name { Ok((bctx, v.tag_name(name))) } else { Ok((bctx, Rc::clone(v))) } } else { Ok((bctx, x)) } }, MarkedForm::SuspendedParamLookup { name, id, cdr_num, car } => { if let Some(v) = dctx.sus_prm_stack.get(id) { if let Some(name) = name { Ok((bctx, v.tag_name(name))) } else { Ok((bctx, Rc::clone(v))) } } else { Ok((bctx, x)) } }, MarkedForm::SuspendedPair { hash, ids, attempted, car, cdr } => { let ( bctx, mut car) = partial_eval(bctx, dctx.clone(), Rc::clone(car))?; let (mut bctx, mut cdr) = partial_eval(bctx, dctx.clone(), Rc::clone(cdr))?; let mut new_attempted = attempted.clone(); let mut maybe_rec_hash = None; while let Some(wrap_level) = car.wrap_level() { if wrap_level > 0 { fn map_unval_peval(bctx: BCtx, dctx: DCtx, x: Rc) -> Result<(BCtx,Rc),String> { match &*x { MarkedForm::Pair(h, ids, x_car, x_cdr) => { let (bctx, new_x_car) = partial_eval(bctx, dctx.clone(), x_car.unval()?)?; let (bctx, new_x_cdr) = map_unval_peval(bctx, dctx.clone(), Rc::clone(x_cdr))?; return Ok((bctx, MarkedForm::new_pair(new_x_car, new_x_cdr))); }, MarkedForm::Nil => return Ok((bctx,x)), _ => return Err("not a list".to_owned()), } } if let Ok((new_bctx, new_cdr)) = map_unval_peval(bctx.clone(), dctx.clone(), Rc::clone(&cdr)) { car = car.decrement_wrap_level().unwrap(); cdr = new_cdr; bctx = new_bctx; } else { break; } } else { // check to see if can do call // not pure values are fine for -1 wraps, which we need to add? veval and vif? if !cdr.is_value() { break; } match &*car { MarkedForm::PrimComb { name, takes_de, wrap_level, f} => { new_attempted = Attempted::True(if *takes_de { Some(dctx.e.ids()) } else { None }); let ident_amount = dctx.ident*4; //println!("{:ident$}doing a call eval of {}", "", name, ident=ident_amount); match f(bctx.clone(), dctx.clone(), Rc::clone(&cdr)) { Ok((bctx, r)) => { match r { PossibleMarkedTailCall::Result(result) => return Ok((bctx, result)), // Sigh, no tail-callin right now PossibleMarkedTailCall::TailCall(new_env, next) => { //println!("{:ident$}doing a tail call of {} in {}", "", next, new_env, ident=ident_amount); if let Ok((new_bctx, res)) = partial_eval(bctx.clone(), dctx.copy_set_env(&new_env), Rc::clone(&next)) { //println!("{:ident$}doing a tail call result is {}", "", res, ident=ident_amount); return Ok((new_bctx, res)); } else { //println!("Tail call failed"); if new_env == dctx.e { //println!("{:ident$}Tail call failed, but can emplace", "", ident=ident_amount); return Ok((bctx, next)); } else { //println!("{:ident$}Tail call failed, can't emplace", "", ident=ident_amount); // maybe this should enplace the TailCall with an eval break; // break out to reconstruction } } } } }, Err(msg) => { //println!("{:ident$}failed {:?}", "", msg, ident=ident_amount); break; }, } } MarkedForm::DeriComb { hash, lookup_name, ids, se, de, id, wrap_level, sequence_params, rest_params, body } => { new_attempted = Attempted::True(if de.is_some() { Some(dctx.e.ids()) } else { None }); // not yet supporting sequence params // needs to check hash match dctx.copy_push_frame(id.clone(), &se, &de, Some(Rc::clone(&dctx.e)), &rest_params, Some(Rc::clone(&cdr)), body) { Ok(inner_dctx) => { //println!("{:ident$}doing a call eval of {} in {}", "", body, inner_dctx.e, ident=inner_dctx.ident*4); let ident_amount = inner_dctx.ident*4; //println!("{:ident$}doing a call eval of {:?}", "", lookup_name, ident=ident_amount); //if let Ok((bctx, r)) = partial_eval(bctx.clone(), inner_dctx, Rc::clone(body)) { // if combiner_return_ok(Rc::clone(&r), id.clone()) { // return Ok((bctx, r)); // } //} match partial_eval(bctx.clone(), inner_dctx, Rc::clone(body)) { Ok((bctx, r)) => { if combiner_return_ok(Rc::clone(&r), id.clone()) { return Ok((bctx, r)); } else { //println!("{:ident$}combiner return not ok {}", "", r, ident=ident_amount); } } Err(msg) => { //println!("{:ident$}failed {:?}", "", msg, ident=ident_amount); } } }, Err(rec_stop_hash) => { maybe_rec_hash = Some(rec_stop_hash); }, } break; // failed call for one reason or the other }, _ => break, } } } Ok((bctx, MarkedForm::new_suspended_pair( new_attempted, car, cdr, maybe_rec_hash ))) }, MarkedForm::Pair(h,ids,car,cdr) => { let (bctx, car) = partial_eval(bctx, dctx.clone(), Rc::clone(car))?; let (bctx, cdr) = partial_eval(bctx, dctx, Rc::clone(cdr))?; Ok((bctx, MarkedForm::new_pair(car, cdr))) }, MarkedForm::DeriComb { hash, lookup_name, ids, se, de, id, wrap_level, sequence_params, rest_params, body } => { if !se.ids().needs_nothing() { // the current env is our new se let se = Rc::clone(&dctx.e); let inner_dctx = dctx.copy_push_frame(id.clone(), &se, &de, None, &rest_params, None, body).expect("Not sure if this can ever fail or not... maybe for Y comb recursion?"); let (bctx, body) = partial_eval(bctx, inner_dctx, Rc::clone(&body))?; Ok((bctx, MarkedForm::new_deri_comb( se, lookup_name.clone(), de.clone(), id.clone(), *wrap_level, sequence_params.clone(), rest_params.clone(), body ))) } else { Ok((bctx, x)) } }, MarkedForm::PrimComb { .. } => Ok((bctx, x)), _ => Ok((bctx, x)), } } #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub enum Attempted { True(Option), False, } #[derive(Debug, Clone, Eq, PartialEq)] pub enum MarkedForm { Nil, Int(i32), Bool(bool), Symbol(String), Pair(MFHash, NeededIds, Rc,Rc), SuspendedSymbol(String), SuspendedParamLookup { name: Option, id: EnvID, cdr_num: i32, car: bool }, SuspendedEnvLookup { name: Option, id: EnvID }, // resume hash is folded into ids SuspendedPair { hash: MFHash, ids: NeededIds, attempted: Attempted, car: Rc, cdr: Rc}, PrimComb { name: String, takes_de: bool, wrap_level: i32, f: fn(BCtx,DCtx,Rc) -> Result<(BCtx,PossibleMarkedTailCall),String> }, DeriComb { hash: MFHash, lookup_name: Option, ids: NeededIds, se: Rc, de: Option, id: EnvID, wrap_level: i32, sequence_params: Vec, rest_params: Option, body: Rc }, } impl MarkedForm { pub fn new_pair(car: Rc, cdr: Rc) -> Rc { let mut h = DefaultHasher::new(); "Pair(ids,car,cdr)".hash(&mut h); car.hash().hash(&mut h); cdr.hash().hash(&mut h); Rc::new(MarkedForm::Pair(MFHash(h.finish()), car.ids().union(&cdr.ids()), car, cdr)) } pub fn new_suspended_pair(attempted: Attempted, car: Rc, cdr: Rc, rec_hash: Option) -> Rc { let mut h = DefaultHasher::new(); "SuspendedPair".hash(&mut h); attempted.hash(&mut h); car.hash().hash(&mut h); cdr.hash().hash(&mut h); let ids = car.ids().union(&cdr.ids()); let ids = match ids { NeededIds::True(_) => ids, NeededIds::None(hashes) => match &attempted { Attempted::False => NeededIds::True(hashes), Attempted::True(Some(oids)) => oids.union_hashes(&hashes), Attempted::True(None) => NeededIds::None(hashes), }, NeededIds::Some(_,_) => ids, }; if let Some(rec_hash) = rec_hash { ids.add_hash(rec_hash); } Rc::new(MarkedForm::SuspendedPair{ hash: MFHash(h.finish()), attempted, ids, car, cdr }) } pub fn new_deri_comb(se: Rc, lookup_name: Option, de: Option, id: EnvID, wrap_level: i32, sequence_params: Vec, rest_params: Option, body: Rc) -> Rc { let mut h = DefaultHasher::new(); "DeriComb".hash(&mut h); se.hash().hash(&mut h); de.hash(&mut h); id.hash(&mut h); wrap_level.hash(&mut h); sequence_params.hash(&mut h); rest_params.hash(&mut h); body.hash().hash(&mut h); let ids = se.ids().union_without(&body.ids(), id.clone()); Rc::new(MarkedForm::DeriComb{ hash: MFHash(h.finish()), lookup_name, ids, se, de, id, wrap_level, sequence_params, rest_params, body }) } pub fn tag_name(self: &Rc, name: &str) -> Rc { match &**self { MarkedForm::DeriComb { hash, lookup_name, ids, se, de, id, wrap_level, sequence_params, rest_params, body } => MarkedForm::new_deri_comb(Rc::clone(se), Some(name.to_owned()), de.clone(), id.clone(), *wrap_level, sequence_params.clone(), rest_params.clone(), Rc::clone(body)), _ => Rc::clone(self), } } pub fn hash(&self) -> MFHash { let mut h = DefaultHasher::new(); { let state = &mut h; match self { MarkedForm::Nil => { "Nil".hash(state); }, MarkedForm::Int(i) => { "Int(i)".hash(state); i.hash(state); }, MarkedForm::Bool(b) => { "Bool(b)".hash(state); b.hash(state); }, MarkedForm::Symbol(s) => { "Symbol(s)".hash(state); s.hash(state); }, MarkedForm::Pair(hash,ids,car,cdr) => { return *hash; }, MarkedForm::SuspendedSymbol(name) => { "SuspendedSymbol(name)".hash(state); name.hash(state); }, MarkedForm::SuspendedParamLookup { name, id, cdr_num, car }=> { "SuspendedParamLookup".hash(state); name.hash(state); id.hash(state); cdr_num.hash(state); car.hash(state); }, MarkedForm::SuspendedEnvLookup { name, id } => { "SuspendedEnvLookup".hash(state); name.hash(state); id.hash(state); }, MarkedForm::SuspendedPair{ hash, .. } => { return *hash; }, MarkedForm::PrimComb { name, wrap_level, .. } => { "PrimComb".hash(state); name.hash(state); wrap_level.hash(state); }, MarkedForm::DeriComb { hash, .. } => { return *hash; }, } } MFHash(h.finish()) } pub fn wrap_level(&self) -> Option { match self { MarkedForm::PrimComb { wrap_level, .. } => Some(*wrap_level), MarkedForm::DeriComb { wrap_level, .. } => Some(*wrap_level), _ => None, } } pub fn decrement_wrap_level(&self) -> Option> { match self { MarkedForm::PrimComb { name, takes_de, wrap_level, f } => Some(Rc::new(MarkedForm::PrimComb { name: name.clone(), takes_de: *takes_de, wrap_level: wrap_level-1, f: *f })), MarkedForm::DeriComb { hash, lookup_name, ids, se, de, id, wrap_level, sequence_params, rest_params, body } => Some(MarkedForm::new_deri_comb(Rc::clone(se), lookup_name.clone(), de.clone(), id.clone(), wrap_level-1, sequence_params.clone(), rest_params.clone(), Rc::clone(body))), _ => None, } } pub fn ids(&self) -> NeededIds { match self { MarkedForm::Nil => NeededIds::new_none(), MarkedForm::Int(i) => NeededIds::new_none(), MarkedForm::Bool(b) => NeededIds::new_none(), MarkedForm::Symbol(s) => NeededIds::new_none(), MarkedForm::Pair(hash,ids,car,cdr) => ids.clone(), MarkedForm::SuspendedSymbol(name) => NeededIds::new_true(), MarkedForm::SuspendedEnvLookup { id, .. } => NeededIds::new_single(id.clone()), MarkedForm::SuspendedParamLookup { id, .. } => NeededIds::new_single(id.clone()), MarkedForm::SuspendedPair{ ids, .. } => ids.clone(), MarkedForm::PrimComb { .. } => NeededIds::new_none(), MarkedForm::DeriComb { ids, .. } => ids.clone(), } } // TODO: this might be essentially the same as NeededIds.nothing_needed() pub fn is_value(&self) -> bool { match match self { MarkedForm::Nil => return true, MarkedForm::Int(i) => return true, MarkedForm::Bool(b) => return true, MarkedForm::Symbol(s) => return true, MarkedForm::SuspendedSymbol(name) => return false, MarkedForm::SuspendedEnvLookup { id, .. } => return false, MarkedForm::SuspendedParamLookup { id, .. } => return false, MarkedForm::SuspendedPair{ ids, .. } => return false, MarkedForm::PrimComb { .. } => return true, MarkedForm::Pair(hash,ids,car,cdr) => ids.clone(), MarkedForm::DeriComb { ids, .. } => ids.clone(), } { NeededIds::True(hashes) => false, NeededIds::None(hashes) => true, NeededIds::Some(ids,hashes) => false, } } pub fn unval(self: &Rc) -> Result, &'static str> { match &**self { MarkedForm::Nil => Ok(Rc::clone(self)), MarkedForm::Int(i) => Ok(Rc::clone(self)), MarkedForm::Bool(b) => Ok(Rc::clone(self)), MarkedForm::Symbol(s) => Ok(Rc::new(MarkedForm::SuspendedSymbol(s.clone()))), MarkedForm::Pair(hash,ids,car,cdr) => Ok(MarkedForm::new_suspended_pair( Attempted::False, car.unval()?, Rc::clone(cdr), None)), MarkedForm::SuspendedSymbol(name) => Err("trying to unval a suspended symbol"), MarkedForm::SuspendedEnvLookup { .. } => Err("trying to unval a suspended env lookup"), MarkedForm::SuspendedParamLookup { .. } => Err("trying to unval a suspended param lookup"), MarkedForm::SuspendedPair{ ids, .. } => Err("trying to unval a suspended pair"), MarkedForm::PrimComb { .. } => Ok(Rc::clone(self)), MarkedForm::DeriComb { .. } => Ok(Rc::clone(self)), } } pub fn truthy(&self) -> Result { match self { MarkedForm::Nil => Ok(false), MarkedForm::Int(i) => Ok(true), MarkedForm::Bool(b) => Ok(*b), MarkedForm::Symbol(s) => Ok(true), MarkedForm::Pair(hash,ids,car,cdr) => Ok(true), MarkedForm::SuspendedSymbol(name) => Err("trying to truthy a suspended symbol"), MarkedForm::SuspendedEnvLookup { .. } => Err("trying to truthy a suspended env lookup"), MarkedForm::SuspendedParamLookup { .. } => Err("trying to truthy a suspended param lookup"), MarkedForm::SuspendedPair{ ids, .. } => Err("trying to truthy a suspended pair"), MarkedForm::PrimComb { .. } => Ok(true), MarkedForm::DeriComb { .. } => Ok(true), } } pub fn sym(&self) -> Result<&str,&'static str> { match self { MarkedForm::Symbol(s) => Ok(s), _ => Err("not a symbol"), } } pub fn int(&self) -> Result { match self { MarkedForm::Int(i) => Ok(*i), _ => Err("not a int"), } } pub fn car(&self) -> Result, &'static str> { match self { MarkedForm::Pair(hash,ids,car,cdr) => Ok(Rc::clone(car)), _ => Err("not a pair"), } } pub fn cdr(&self) -> Result, &'static str> { match self { MarkedForm::Pair(hash,ids,car,cdr) => Ok(Rc::clone(cdr)), _ => Err("not a pair"), } } } impl fmt::Display for MarkedForm { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MarkedForm::Nil => write!(f, "nil"), MarkedForm::Int(i) => write!(f, "{}", i), MarkedForm::Bool(b) => write!(f, "{}", b), MarkedForm::Symbol(s) => write!(f, "{}", s), MarkedForm::Pair(hash, ids, car, cdr) => { //write!(f, "{:?}#({}", ids, car)?; write!(f, "({}", car)?; let mut traverse: Rc = Rc::clone(cdr); loop { match &*traverse { MarkedForm::Pair(ref hash, ref ids, ref carp, ref cdrp) => { write!(f, " {}", carp)?; traverse = Rc::clone(cdrp); }, MarkedForm::Nil => { write!(f, ")")?; return Ok(()); }, x => { write!(f, ". {})", x)?; return Ok(()); }, } } }, MarkedForm::SuspendedSymbol(name) => write!(f, "{}", name), MarkedForm::SuspendedEnvLookup { name, id } => write!(f, "{:?}({:?}env)", name, id), MarkedForm::SuspendedParamLookup { name, id, cdr_num, car } => write!(f, "{:?}({:?}{}{})", name, id, cdr_num, car), MarkedForm::PrimComb { name, wrap_level, .. } => write!(f, "<{}{}>", name, wrap_level), //MarkedForm::DeriComb { ids, se, de, id, wrap_level, sequence_params, rest_params, body } => write!(f, "{:?}#[{}/{:?}/{:?}/{}/{:?}/{:?}/{}]", ids, se, de, id, wrap_level, sequence_params, rest_params, body), MarkedForm::DeriComb { hash, lookup_name, ids, se, de, id, wrap_level, sequence_params, rest_params, body } => write!(f, "{:?}#[{:?}/{:?}/{:?}/{}/{:?}/{:?}/{}]", ids, lookup_name, de, id, wrap_level, sequence_params, rest_params, body), MarkedForm::SuspendedPair{ hash, ids, attempted, car, cdr } => { //write!(f, "{:?}{:?}#{{{}", ids, attempted, car)?; write!(f, "{{{}", car)?; let mut traverse: Rc = Rc::clone(cdr); loop { match &*traverse { MarkedForm::Pair(ref hash, ref ids, ref carp, ref cdrp) => { write!(f, " {}", carp)?; traverse = Rc::clone(cdrp); }, MarkedForm::Nil => { write!(f, "}}")?; return Ok(()); }, x => { write!(f, ". {}}}", x)?; return Ok(()); }, } } }, } } } pub fn eval(e: Rc, f: Rc) -> Rc { let mut e = e; let mut x = Option::Some(f); loop { let cur = x.take().unwrap(); //println!("Evaluating {:?} in {:?}", cur, e); match *cur { Form::Symbol(ref s) => { let mut t = e; //println!("Looking up {} in {:?}", s, t); //println!("Looking up {}", s); while s != t.car().unwrap().car().unwrap().sym().unwrap() { t = t.cdr().unwrap(); } return t.car().unwrap().cdr().unwrap(); }, Form::Pair(ref c, ref p) => { let comb = eval(Rc::clone(&e), Rc::clone(c)); match *comb { Form::PrimComb(ref _n, ref f) => match f(e, Rc::clone(p)) { PossibleTailCall::Result(r) => return r, PossibleTailCall::TailCall(ne, nx) => { e = ne; x = Some(nx); }, }, Form::DeriComb{ref se, ref de, ref params, ref body } => { let mut new_e = Rc::clone(se); if let Some(de) = de { new_e = assoc(de, Rc::clone(&e), new_e); } new_e = assoc(params, Rc::clone(p), new_e); // always a tail call e = new_e; x = Some(Rc::clone(body)); }, _ => panic!("Tried to call not a Prim/DeriComb {:?}", comb), } }, _ => return cur, } } } fn massoc(k: &str, v: Rc, l: Rc) -> Rc { MarkedForm::new_pair( MarkedForm::new_pair( Rc::new(MarkedForm::Symbol(k.to_owned())), v), l) } fn assoc(k: &str, v: Rc, l: Rc) -> Rc { Rc::new(Form::Pair( Rc::new(Form::Pair( Rc::new(Form::Symbol(k.to_owned())), v)), l)) } fn assoc_vec(kvs: Vec<(&str, Rc)>) -> Rc { let mut to_ret = Rc::new(Form::Nil); for (k, v) in kvs { to_ret = assoc(k, v, to_ret); } to_ret } pub fn root_env() -> Rc { assoc_vec(vec![ // TODO: Should be properly tail recursive ("eval", Rc::new(Form::PrimComb("eval".to_owned(), |e, p| { let b = eval(Rc::clone(&e), p.car().unwrap()); let e = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::TailCall(e, b) }))), // (vau de params body) ("vau", Rc::new(Form::PrimComb("vau".to_owned(), |e, p| { let de = p.car().unwrap().sym().map(|s| s.to_owned()); let params = p.cdr().unwrap().car().unwrap().sym().unwrap().to_owned(); let body = p.cdr().unwrap().cdr().unwrap().car().unwrap(); PossibleTailCall::Result(Rc::new(Form::DeriComb { se: e, de, params, body })) }))), ("=", Rc::new(Form::PrimComb("=".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()); let b = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::Result(Rc::new(Form::Bool(a == b))) }))), ("<", Rc::new(Form::PrimComb("<".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()); let b = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() < b.int().unwrap()))) }))), (">", Rc::new(Form::PrimComb(">".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()); let b = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() > b.int().unwrap()))) }))), ("<=", Rc::new(Form::PrimComb("<=".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()); let b = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() <= b.int().unwrap()))) }))), (">=", Rc::new(Form::PrimComb(">=".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()); let b = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() >= b.int().unwrap()))) }))), ("if", Rc::new(Form::PrimComb("if".to_owned(), |e, p| { if eval(Rc::clone(&e), p.car().unwrap()).truthy() { PossibleTailCall::TailCall(e, p.cdr().unwrap().car().unwrap()) } else { PossibleTailCall::TailCall(e, p.cdr().unwrap().cdr().unwrap().car().unwrap()) } }))), ("cons", Rc::new(Form::PrimComb("cons".to_owned(), |e, p| { let h = eval(Rc::clone(&e), p.car().unwrap()); let t = eval(e, p.cdr().unwrap().car().unwrap()); PossibleTailCall::Result(Rc::new(Form::Pair(h, t))) }))), ("car", Rc::new(Form::PrimComb("car".to_owned(), |e, p| { PossibleTailCall::Result(eval(Rc::clone(&e), p.car().unwrap()).car().unwrap()) }))), ("cdr", Rc::new(Form::PrimComb("cdr".to_owned(), |e, p| { PossibleTailCall::Result(eval(Rc::clone(&e), p.car().unwrap()).cdr().unwrap()) }))), ("quote", Rc::new(Form::PrimComb("quote".to_owned(), |_e, p| { PossibleTailCall::Result(p.car().unwrap()) }))), ("debug", Rc::new(Form::PrimComb("debug".to_owned(), |e, p| { //println!("Debug: {:?}", eval(Rc::clone(&e), p.car().unwrap())); println!("Debug: {}", eval(Rc::clone(&e), p.car().unwrap())); PossibleTailCall::TailCall(e, p.cdr().unwrap().car().unwrap()) }))), ("assert", Rc::new(Form::PrimComb("assert".to_owned(), |e, p| { let thing = eval(Rc::clone(&e), p.car().unwrap()); if !thing.truthy() { println!("Assert failed: {:?}", thing); } assert!(thing.truthy()); PossibleTailCall::TailCall(e, p.cdr().unwrap().car().unwrap()) }))), ("+", Rc::new(Form::PrimComb("+".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a + b))) }))), ("-", Rc::new(Form::PrimComb("-".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a - b))) }))), ("*", Rc::new(Form::PrimComb("*".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a * b))) }))), ("/", Rc::new(Form::PrimComb("/".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a / b))) }))), ("%", Rc::new(Form::PrimComb("%".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a % b))) }))), ("&", Rc::new(Form::PrimComb("&".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a & b))) }))), ("|", Rc::new(Form::PrimComb("|".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a | b))) }))), ("^", Rc::new(Form::PrimComb("^".to_owned(), |e, p| { let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); PossibleTailCall::Result(Rc::new(Form::Int(a ^ b))) }))), ("comb?", Rc::new(Form::PrimComb("comb?".to_owned(), |e, p| { PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { Form::PrimComb(_n, _f) => true, Form::DeriComb { .. } => true, _ => false, }))) }))), ("pair?", Rc::new(Form::PrimComb("pair?".to_owned(), |e, p| { PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { Form::Pair(_a,_b) => true, _ => false, }))) }))), ("symbol?", Rc::new(Form::PrimComb("symbol?".to_owned(), |e, p| { PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { Form::Symbol(_) => true, _ => false, }))) }))), ("int?", Rc::new(Form::PrimComb("int?".to_owned(), |e, p| { PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { Form::Int(_) => true, _ => false, }))) }))), // maybe bool? but also could be derived. Nil def ("bool?", Rc::new(Form::PrimComb("bool?".to_owned(), |e, p| { PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { Form::Bool(_) => true, _ => false, }))) }))), ("nil?", Rc::new(Form::PrimComb("nil?".to_owned(), |e, p| { PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { Form::Nil => true, _ => false, }))) }))), // consts ("true", Rc::new(Form::Bool(true))), ("false", Rc::new(Form::Bool(false))), ("nil", Rc::new(Form::Nil)), ]) }