Files
kraken/kv/src/eval.rs

137 lines
5.4 KiB
Rust

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<Self>,Rc<Self>)>;
fn car(&self) -> Option<Rc<Self>>;
fn cdr(&self) -> Option<Rc<Self>>;
fn is_nil(&self) -> bool;
fn call(&self, p: Rc<Self>, e: Rc<Self>, nc: Box<Cont<Self>>, metac: Cont<Self>) -> Cursor<Self>;
fn impl_prim(ins: PrimCombI, e: Rc<Self>, ps: Vec<Rc<Self>>, c: Cont<Self>, metac: Cont<Self>) -> Cursor<Self>;
}
#[derive(Debug, Eq, PartialEq)]
pub enum Cont<F: FormT + ?Sized> {
Exit,
MetaRet,
CatchRet { nc: Box<Cont<F>>, restore_meta: Box<Cont<F>> },
Eval { e: Rc<F>, nc: Box<Cont<F>> },
Call { p: Rc<F>, e: Rc<F>, nc: Box<Cont<F>> },
PramEval { eval_limit: i32, to_eval: Rc<F>, collected: Option<Vec<Rc<F>>>, e: Rc<F>, ins: PrimCombI, nc: Box<Cont<F>> },
}
impl<F: FormT> Clone for Cont<F> {
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<F: FormT + ?Sized> { pub f: Rc<F>, pub c: Cont<F>, pub metac: Cont<F> }
pub fn eval<F: FormT>(e: Rc<F>, f: Rc<F>) -> Rc<F> {
let mut cursor = Cursor::<F> { 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,
}