use std::fmt; use std::boxed::Box; use std::rc::Rc; use std::cell::RefCell; use std::convert::From; pub trait FormT: std::fmt::Debug { fn sym(&self) -> Option<&str>; fn pair(&self) -> Option<(Rc,Rc)>; fn car(&self) -> Option>; fn cdr(&self) -> Option>; fn is_nil(&self) -> bool; fn call(&self, p: Rc, e: Rc, nc: Box>, metac: Cont) -> Cursor; fn impl_prim(ins: PrimCombI, e: Rc, ps: Vec>, c: Cont, metac: Cont) -> Cursor; } #[derive(Debug, Eq, PartialEq)] pub enum Cont { Exit, MetaRet, CatchRet { nc: Box>, restore_meta: Box> }, Eval { e: Rc, nc: Box> }, Call { p: Rc, e: Rc, nc: Box> }, PramEval { eval_limit: i32, to_eval: Rc, collected: Option>>, e: Rc, ins: PrimCombI, nc: Box> }, } impl Clone for Cont { fn clone(&self) -> Self { match self { Cont::Exit => Cont::Exit, Cont::MetaRet => Cont::MetaRet, Cont::CatchRet { nc, restore_meta } => Cont::CatchRet { nc: nc.clone(), restore_meta: restore_meta.clone() }, Cont::Eval { e, nc } => Cont::Eval { e: Rc::clone(e), nc: nc.clone() }, Cont::Call { p, e, nc } => Cont::Call { p: Rc::clone(p), e: Rc::clone(e), nc: nc.clone() }, Cont::PramEval { eval_limit, to_eval, collected, e, ins, nc} => Cont::PramEval { eval_limit: *eval_limit, to_eval: Rc::clone(to_eval), collected: collected.as_ref().map(|x| x.iter().map(|x| Rc::clone(x)).collect()), e: Rc::clone(e), ins: ins.clone(), nc: nc.clone() }, } } } pub struct Cursor { pub f: Rc, pub c: Cont, pub metac: Cont } pub fn eval(e: Rc, f: Rc) -> Rc { let mut cursor = Cursor:: { f, c: Cont::Eval { e, nc: Box::new(Cont::MetaRet) }, metac: Cont::Exit }; loop { let Cursor { f, c, metac } = cursor; match c { Cont::Exit => { return f; }, Cont::MetaRet => { cursor = Cursor { f: f, c: metac.clone(), metac: metac }; }, Cont::CatchRet { nc, restore_meta } => { cursor = Cursor { f: f, c: *nc, metac: *restore_meta }; }, Cont::Eval { e, nc } => { if let Some((comb, p)) = f.pair() { cursor = Cursor { f: comb, c: Cont::Eval { e: Rc::clone(&e), nc: Box::new(Cont::Call { p, e, nc }) }, metac } } else if let Some(s) = f.sym() { let mut t = Rc::clone(&e); while s != t.car().unwrap().car().unwrap().sym().unwrap() { t = t.cdr().unwrap(); } cursor = Cursor { f: t.car().unwrap().cdr().unwrap(), c: *nc, metac }; } else { cursor = Cursor { f: Rc::clone(&f), c: *nc, metac }; } }, Cont::PramEval { eval_limit, to_eval, collected, e, ins, nc } => { let mut next_collected = if let Some(mut collected) = collected { collected.push(f); collected } else { vec![] }; if eval_limit == 0 || to_eval.is_nil() { let mut traverse = to_eval; while !traverse.is_nil() { next_collected.push(traverse.car().unwrap()); traverse = traverse.cdr().unwrap(); } cursor = F::impl_prim(ins, e, next_collected, *nc, metac); } else { cursor = Cursor { f: to_eval.car().unwrap(), c: Cont::Eval { e: Rc::clone(&e), nc: Box::new(Cont::PramEval { eval_limit: eval_limit - 1, to_eval: to_eval.cdr().unwrap(), collected: Some(next_collected), e, ins, nc }) }, metac }; } }, Cont::Call { p, e, nc } => { cursor = f.call(p, e, nc, metac); }, } } } #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum PrimCombI { Eval, Vau, If, Reset, Shift, Cell, Set, Get, Cons, Car, Cdr, Quote, Assert, Eq, Lt, LEq, Gt, GEq, Plus, Minus, Mult, Div, Mod, And, Or, Xor, CombP, CellP, PairP, SymbolP, IntP, BoolP, NilP, }