Split Ctx into BCtx (bi-directional ctx, must be returned) and DCtx (downwards-ctx, only passed down). Env goes in DCtx, so you don't have to play a replace-back game with ctx when returning from function calls.

This commit is contained in:
2023-02-19 12:37:12 -05:00
parent 283c0232b0
commit 91e0641045
2 changed files with 151 additions and 134 deletions

View File

@@ -71,42 +71,42 @@ impl Form {
} }
} }
pub fn marked(&self, ctx: Ctx) -> (Ctx, Rc<MarkedForm>) { pub fn marked(&self, bctx: BCtx) -> (BCtx, Rc<MarkedForm>) {
match &*self { match &*self {
Form::Nil => (ctx, Rc::new(MarkedForm::Nil)), Form::Nil => (bctx, Rc::new(MarkedForm::Nil)),
Form::Int(i) => (ctx, Rc::new(MarkedForm::Int(*i))), Form::Int(i) => (bctx, Rc::new(MarkedForm::Int(*i))),
Form::Bool(b) => (ctx, Rc::new(MarkedForm::Bool(*b))), Form::Bool(b) => (bctx, Rc::new(MarkedForm::Bool(*b))),
Form::Symbol(s) => (ctx, Rc::new(MarkedForm::Symbol(s.clone()))), Form::Symbol(s) => (bctx, Rc::new(MarkedForm::Symbol(s.clone()))),
Form::Pair(car, cdr) => { Form::Pair(car, cdr) => {
let (ctx, car) = car.marked(ctx); let (bctx, car) = car.marked(bctx);
let (ctx, cdr) = cdr.marked(ctx); let (bctx, cdr) = cdr.marked(bctx);
(ctx, Rc::new(MarkedForm::Pair(NeededIds::new_none(), car, cdr))) (bctx, Rc::new(MarkedForm::Pair(NeededIds::new_none(), car, cdr)))
}, },
Form::DeriComb { se, de, params, body } => { Form::DeriComb { se, de, params, body } => {
let (ctx, se) = se.marked(ctx); let (bctx, se) = se.marked(bctx);
let (ctx, body) = body.marked(ctx); let (bctx, body) = body.marked(bctx);
let (ctx, new_id) = ctx.new_id(); let (bctx, new_id) = bctx.new_id();
(ctx, Rc::new(MarkedForm::DeriComb { ids: NeededIds::new_none(), se, de: de.clone(), (bctx, Rc::new(MarkedForm::DeriComb { ids: NeededIds::new_none(), se, de: de.clone(),
id: new_id, wrap_level: 0, sequence_params: vec![], id: new_id, wrap_level: 0, sequence_params: vec![],
rest_params: Some(params.clone()), body })) rest_params: Some(params.clone()), body }))
}, },
Form::PrimComb(name, _f) => { Form::PrimComb(name, _f) => {
(ctx, match &name[..] { (bctx, match &name[..] {
// should be able to take in wrap_level != 1 and do stuff // should be able to take in wrap_level != 1 and do stuff
"eval" => Rc::new(MarkedForm::PrimComb { name: "eval".to_owned(), wrap_level: 1, f: |ctx, p| { "eval" => Rc::new(MarkedForm::PrimComb { name: "eval".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
// put in partial eval logic, maybe? // put in partial eval logic, maybe?
let b = p.car()?.unval()?; let b = p.car()?.unval()?;
let e = p.cdr()?.car()?; let e = p.cdr()?.car()?;
println!("Doing Eval (via tail call) of {} in {}", b, e); println!("Doing Eval (via tail call) of {} in {}", b, e);
Ok((ctx, PossibleMarkedTailCall::TailCall(e, b))) Ok((bctx, PossibleMarkedTailCall::TailCall(e, b)))
}}), }}),
// (vau de params body), should be able to take in wrap_level != 1 and do stuff // (vau de params body), should be able to take in wrap_level != 1 and do stuff
"vau" => Rc::new(MarkedForm::PrimComb { name: "vau".to_owned(), wrap_level: 0, f: |ctx, p| { "vau" => Rc::new(MarkedForm::PrimComb { name: "vau".to_owned(), wrap_level: 0, f: |bctx, dctx, p| {
let de = p.car()?.sym().map(|s| s.to_owned()).ok(); let de = p.car()?.sym().map(|s| s.to_owned()).ok();
let params = p.cdr()?.car()?.sym()?.to_owned(); let params = p.cdr()?.car()?.sym()?.to_owned();
let body = p.cdr()?.cdr()?.car()?.unval()?; let body = p.cdr()?.cdr()?.car()?.unval()?;
let se = Rc::clone(&ctx.e); let se = Rc::clone(&dctx.e);
let (ctx, id) = ctx.new_id(); let (bctx, id) = bctx.new_id();
// TODO: figure out wrap level, sequence params, etc // TODO: figure out wrap level, sequence params, etc
let wrap_level = 0; let wrap_level = 0;
let sequence_params = vec![]; let sequence_params = vec![];
@@ -119,159 +119,159 @@ impl Form {
let inner_env = if let Some(p) = &rest_params { let inner_env = if let Some(p) = &rest_params {
massoc(p, Rc::new(MarkedForm::SuspendedParamLookup { name: Some(p.clone()), id: id.clone(), cdr_num: 0, car: false }), inner_env) massoc(p, Rc::new(MarkedForm::SuspendedParamLookup { name: Some(p.clone()), id: id.clone(), cdr_num: 0, car: false }), inner_env)
} else { inner_env }; } else { inner_env };
let (ctx, body) = partial_eval(ctx.copy_with(&inner_env), Rc::clone(&body)).map(|(ictx, res)| { (ictx.copy_with(&ctx.e), res) })?; let (bctx, body) = partial_eval(bctx, dctx.copy_push_env(&inner_env), Rc::clone(&body))?;
// //
// //
let ids = ctx.e.ids().union(&body.ids()); let ids = dctx.e.ids().union(&body.ids());
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new( Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(
MarkedForm::DeriComb { ids, se, de, id, wrap_level, sequence_params, rest_params, body }, MarkedForm::DeriComb { ids, se, de, id, wrap_level, sequence_params, rest_params, body },
)))) ))))
}}), }}),
// TODO: handle vif etc // TODO: handle vif etc
"if" => Rc::new(MarkedForm::PrimComb { name: "if".to_owned(), wrap_level: 0, f: |ctx, p| { "if" => Rc::new(MarkedForm::PrimComb { name: "if".to_owned(), wrap_level: 0, f: |bctx, dctx, p| {
let (ctx, cond) = partial_eval(ctx, p.car()?.unval()?)?; let (bctx, cond) = partial_eval(bctx, dctx.clone(), p.car()?.unval()?)?;
let e = Rc::clone(&ctx.e); let e = Rc::clone(&dctx.e);
if cond.truthy()? { if cond.truthy()? {
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?.unval()?))) Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?.unval()?)))
} else { } else {
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.cdr()?.car()?.unval()?))) Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.cdr()?.car()?.unval()?)))
} }
}}), }}),
// TODO: handle these in the context of paritals // TODO: handle these in the context of paritals
"cons" => Rc::new(MarkedForm::PrimComb { name: "cons".to_owned(), wrap_level: 1, f: |ctx, p| { "cons" => Rc::new(MarkedForm::PrimComb { name: "cons".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let h = p.car()?; let h = p.car()?;
let t = p.cdr()?.car()?; let t = p.cdr()?.car()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Pair(h.ids().union(&t.ids()), h, t))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Pair(h.ids().union(&t.ids()), h, t)))))
}}), }}),
"car" => Rc::new(MarkedForm::PrimComb { name: "car".to_owned(), wrap_level: 1, f: |ctx, p| { "car" => Rc::new(MarkedForm::PrimComb { name: "car".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(p.car()?.car()?))) Ok((bctx, PossibleMarkedTailCall::Result(p.car()?.car()?)))
}}), }}),
"cdr" => Rc::new(MarkedForm::PrimComb { name: "cdr".to_owned(), wrap_level: 1, f: |ctx, p| { "cdr" => Rc::new(MarkedForm::PrimComb { name: "cdr".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(p.car()?.cdr()?))) Ok((bctx, PossibleMarkedTailCall::Result(p.car()?.cdr()?)))
}}), }}),
"quote" => Rc::new(MarkedForm::PrimComb { name: "quote".to_owned(), wrap_level: 0, f: |ctx, p| { "quote" => Rc::new(MarkedForm::PrimComb { name: "quote".to_owned(), wrap_level: 0, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(p.car()?))) Ok((bctx, PossibleMarkedTailCall::Result(p.car()?)))
}}), }}),
// This one needs to control eval to print debug before continuint // This one needs to control eval to print debug before continuint
// which is werid to PE // which is werid to PE
"debug" => Rc::new(MarkedForm::PrimComb { name: "debug".to_owned(), wrap_level: 0, f: |ctx, p| { "debug" => Rc::new(MarkedForm::PrimComb { name: "debug".to_owned(), wrap_level: 0, f: |bctx, dctx, p| {
let e = Rc::clone(&ctx.e); let e = Rc::clone(&dctx.e);
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?))) Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?)))
}}), }}),
// ditto // ditto
"assert" => Rc::new(MarkedForm::PrimComb { name: "assert".to_owned(), wrap_level: 0, f: |ctx, p| { "assert" => Rc::new(MarkedForm::PrimComb { name: "assert".to_owned(), wrap_level: 0, f: |bctx, dctx, p| {
let (ctx, cond) = partial_eval(ctx, p.car()?)?; let (bctx, cond) = partial_eval(bctx, dctx.clone(), p.car()?)?;
if !cond.truthy()? { if !cond.truthy()? {
println!("Assert failed: {:?}", cond); println!("Assert failed: {:?}", cond);
} }
assert!(cond.truthy()?); assert!(cond.truthy()?);
let e = Rc::clone(&ctx.e); let e = Rc::clone(&dctx.e);
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?))) Ok((bctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?)))
}}), }}),
// (vau de params body), should be able to take in wrap_level != 1 and do stuff // (vau de params body), should be able to take in wrap_level != 1 and do stuff
"=" => Rc::new(MarkedForm::PrimComb { name: "=".to_owned(), wrap_level: 1, f: |ctx, p| { "=" => Rc::new(MarkedForm::PrimComb { name: "=".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?; let a = p.car()?;
let b = p.cdr()?.car()?; let b = p.cdr()?.car()?;
println!("DOing (= {} {}) = {}", a, b, a==b); println!("DOing (= {} {}) = {}", a, b, a==b);
// TODO: double check that this ignores ids etc. It should, since // TODO: double check that this ignores ids etc. It should, since
// wrap_level=1 should mean that everything's a value // wrap_level=1 should mean that everything's a value
// also, it should just check by hash then? // also, it should just check by hash then?
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a == b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a == b)))))
}}), }}),
"<" => Rc::new(MarkedForm::PrimComb { name: "<".to_owned(), wrap_level: 1, f: |ctx, p| { "<" => Rc::new(MarkedForm::PrimComb { name: "<".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?; let a = p.car()?;
let b = p.cdr()?.car()?; let b = p.cdr()?.car()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? < b.int()?))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? < b.int()?)))))
}}), }}),
">" => Rc::new(MarkedForm::PrimComb { name: ">".to_owned(), wrap_level: 1, f: |ctx, p| { ">" => Rc::new(MarkedForm::PrimComb { name: ">".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?; let a = p.car()?;
let b = p.cdr()?.car()?; let b = p.cdr()?.car()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? > b.int()?))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? > b.int()?)))))
}}), }}),
"<=" => Rc::new(MarkedForm::PrimComb { name: "<=".to_owned(), wrap_level: 1, f: |ctx, p| { "<=" => Rc::new(MarkedForm::PrimComb { name: "<=".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?; let a = p.car()?;
let b = p.cdr()?.car()?; let b = p.cdr()?.car()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? <= b.int()?))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? <= b.int()?)))))
}}), }}),
">=" => Rc::new(MarkedForm::PrimComb { name: ">=".to_owned(), wrap_level: 1, f: |ctx, p| { ">=" => Rc::new(MarkedForm::PrimComb { name: ">=".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?; let a = p.car()?;
let b = p.cdr()?.car()?; let b = p.cdr()?.car()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? >= b.int()?))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(a.int()? >= b.int()?)))))
}}), }}),
"+" => Rc::new(MarkedForm::PrimComb { name: "+".to_owned(), wrap_level: 1, f: |ctx, p| { "+" => Rc::new(MarkedForm::PrimComb { name: "+".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a + b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a + b)))))
}}), }}),
"-" => Rc::new(MarkedForm::PrimComb { name: "-".to_owned(), wrap_level: 1, f: |ctx, p| { "-" => Rc::new(MarkedForm::PrimComb { name: "-".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a - b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a - b)))))
}}), }}),
"*" => Rc::new(MarkedForm::PrimComb { name: "*".to_owned(), wrap_level: 1, f: |ctx, p| { "*" => Rc::new(MarkedForm::PrimComb { name: "*".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a * b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a * b)))))
}}), }}),
"/" => Rc::new(MarkedForm::PrimComb { name: "/".to_owned(), wrap_level: 1, f: |ctx, p| { "/" => Rc::new(MarkedForm::PrimComb { name: "/".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a / b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a / b)))))
}}), }}),
"%" => Rc::new(MarkedForm::PrimComb { name: "%".to_owned(), wrap_level: 1, f: |ctx, p| { "%" => Rc::new(MarkedForm::PrimComb { name: "%".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a % b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a % b)))))
}}), }}),
"&" => Rc::new(MarkedForm::PrimComb { name: "&".to_owned(), wrap_level: 1, f: |ctx, p| { "&" => Rc::new(MarkedForm::PrimComb { name: "&".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a & b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a & b)))))
}}), }}),
"|" => Rc::new(MarkedForm::PrimComb { name: "|".to_owned(), wrap_level: 1, f: |ctx, p| { "|" => Rc::new(MarkedForm::PrimComb { name: "|".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a | b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a | b)))))
}}), }}),
"^" => Rc::new(MarkedForm::PrimComb { name: "^".to_owned(), wrap_level: 1, f: |ctx, p| { "^" => Rc::new(MarkedForm::PrimComb { name: "^".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
let a = p.car()?.int()?; let a = p.car()?.int()?;
let b = p.cdr()?.car()?.int()?; let b = p.cdr()?.car()?.int()?;
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a ^ b))))) Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Int(a ^ b)))))
}}), }}),
"comb?" => Rc::new(MarkedForm::PrimComb { name: "comb?".to_owned(), wrap_level: 1, f: |ctx, p| { "comb?" => Rc::new(MarkedForm::PrimComb { name: "comb?".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? {
MarkedForm::PrimComb { .. } => true, MarkedForm::PrimComb { .. } => true,
MarkedForm::DeriComb { .. } => true, MarkedForm::DeriComb { .. } => true,
_ => false, _ => false,
}))))) })))))
}}), }}),
"pair?" => Rc::new(MarkedForm::PrimComb { name: "pair?".to_owned(), wrap_level: 1, f: |ctx, p| { "pair?" => Rc::new(MarkedForm::PrimComb { name: "pair?".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? {
MarkedForm::Pair(_i, _a,_b) => true, MarkedForm::Pair(_i, _a,_b) => true,
_ => false, _ => false,
}))))) })))))
}}), }}),
"symbol?" => Rc::new(MarkedForm::PrimComb { name: "symbol?".to_owned(), wrap_level: 1, f: |ctx, p| { "symbol?" => Rc::new(MarkedForm::PrimComb { name: "symbol?".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? {
MarkedForm::Symbol(_) => true, MarkedForm::Symbol(_) => true,
_ => false, _ => false,
}))))) })))))
}}), }}),
"int?" => Rc::new(MarkedForm::PrimComb { name: "int?".to_owned(), wrap_level: 1, f: |ctx, p| { "int?" => Rc::new(MarkedForm::PrimComb { name: "int?".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? {
MarkedForm::Int(_) => true, MarkedForm::Int(_) => true,
_ => false, _ => false,
}))))) })))))
}}), }}),
// maybe bool? but also could be derived. Nil def // maybe bool? but also could be derived. Nil def
"bool?" => Rc::new(MarkedForm::PrimComb { name: "bool?".to_owned(), wrap_level: 1, f: |ctx, p| { "bool?" => Rc::new(MarkedForm::PrimComb { name: "bool?".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? {
MarkedForm::Bool(_) => true, MarkedForm::Bool(_) => true,
_ => false, _ => false,
}))))) })))))
}}), }}),
"nil?" => Rc::new(MarkedForm::PrimComb { name: "nil?".to_owned(), wrap_level: 1, f: |ctx, p| { "nil?" => Rc::new(MarkedForm::PrimComb { name: "nil?".to_owned(), wrap_level: 1, f: |bctx, dctx, p| {
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? { Ok((bctx, PossibleMarkedTailCall::Result(Rc::new(MarkedForm::Bool(match &* p.car()? {
MarkedForm::Nil => true, MarkedForm::Nil => true,
_ => false, _ => false,
}))))) })))))
@@ -377,66 +377,86 @@ pub enum PossibleMarkedTailCall {
Result(Rc<MarkedForm>), Result(Rc<MarkedForm>),
TailCall(Rc<MarkedForm>, Rc<MarkedForm>), TailCall(Rc<MarkedForm>, Rc<MarkedForm>),
} }
// force is for drop_redundent_eval
// memo is only for recording currently executing hashes (calls and if's)
// only_head is not currently used
//only_head env env_counter memo env_stack force
//
//I feel like ctx should only be used for things passed back up?
//or maybe we split into an upwards and downwards ctx
//bidirectional is only env_counter, though a true memoization would also count
//ok
//we have Ctx - env_counter (maybe true memoization eventually)
//and Dctx - env env_stack memo(currently_executing) force
#[derive(Clone)] #[derive(Clone)]
pub struct Ctx { pub struct BCtx {
e : Rc<MarkedForm>,
id_counter: i32 id_counter: i32
} }
impl Ctx { impl BCtx {
pub fn new_id(mut self) -> (Self, EnvID) { pub fn new_id(mut self) -> (Self, EnvID) {
let new_id = EnvID(self.id_counter); let new_id = EnvID(self.id_counter);
self.id_counter += 1; self.id_counter += 1;
(self, new_id) (self, new_id)
} }
pub fn copy_with(&self, e: &Rc<MarkedForm>) -> Self { }
Ctx { e: Rc::clone(e), id_counter: self.id_counter }
#[derive(Clone)]
pub struct DCtx {
e : Rc<MarkedForm>,
}
impl DCtx {
pub fn copy_push_env(&self, e: &Rc<MarkedForm>) -> Self {
DCtx { e: Rc::clone(e) }
} }
} }
impl Default for Ctx {
fn default() -> Ctx { pub fn new_base_ctxs() -> (BCtx,DCtx) {
let tmp_ctx = Ctx { e: Rc::new(MarkedForm::Nil), id_counter: 0 }; let bctx = BCtx { id_counter: 0 };
let (tmp_ctx, root_env) = root_env().marked(tmp_ctx); let (bctx, root_env) = root_env().marked(bctx);
Ctx { e: root_env, id_counter: tmp_ctx.id_counter } (bctx, DCtx { e: root_env } )
}
} }
pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>), String> {
pub fn partial_eval(bctx: BCtx, dctx: DCtx, x: Rc<MarkedForm>) -> Result<(BCtx,Rc<MarkedForm>), String> {
println!("PE: {}", x); println!("PE: {}", x);
match &*x { match &*x {
MarkedForm::SuspendedSymbol(name) => { MarkedForm::SuspendedSymbol(name) => {
let mut t = Rc::clone(&ctx.e); let mut t = Rc::clone(&dctx.e);
while name != t.car()?.car()?.sym()? { while name != t.car()?.car()?.sym()? {
t = t.cdr()?; t = t.cdr()?;
} }
return Ok((ctx, t.car()?.cdr()?)); return Ok((bctx, t.car()?.cdr()?));
}, },
MarkedForm::SuspendedEnvLookup { name, id } => { MarkedForm::SuspendedEnvLookup { name, id } => {
// lookup in stack // lookup in stack
Ok((ctx, x)) Ok((bctx, x))
}, },
MarkedForm::SuspendedParamLookup { name, id, cdr_num, car } => { MarkedForm::SuspendedParamLookup { name, id, cdr_num, car } => {
// lookup in stack // lookup in stack
Ok((ctx, x)) Ok((bctx, x))
}, },
MarkedForm::SuspendedPair { ids, attempted, car, cdr } => { MarkedForm::SuspendedPair { ids, attempted, car, cdr } => {
let ( ctx, mut car) = partial_eval(ctx, Rc::clone(car))?; let ( bctx, mut car) = partial_eval(bctx, dctx.clone(), Rc::clone(car))?;
let (mut ctx, mut cdr) = partial_eval(ctx, Rc::clone(cdr))?; let (mut bctx, mut cdr) = partial_eval(bctx, dctx.clone(), Rc::clone(cdr))?;
while let Some(wrap_level) = car.wrap_level() { while let Some(wrap_level) = car.wrap_level() {
if wrap_level > 0 { if wrap_level > 0 {
fn map_unval_peval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>),String> { fn map_unval_peval(bctx: BCtx, dctx: DCtx, x: Rc<MarkedForm>) -> Result<(BCtx,Rc<MarkedForm>),String> {
match &*x { match &*x {
MarkedForm::Pair(ids, x_car, x_cdr) => { MarkedForm::Pair(ids, x_car, x_cdr) => {
let (ctx, new_x_car) = partial_eval(ctx, x_car.unval()?)?; let (bctx, new_x_car) = partial_eval(bctx, dctx.clone(), x_car.unval()?)?;
let (ctx, new_x_cdr) = map_unval_peval(ctx, Rc::clone(x_cdr))?; let (bctx, new_x_cdr) = map_unval_peval(bctx, dctx.clone(), Rc::clone(x_cdr))?;
return Ok((ctx, Rc::new(MarkedForm::Pair(new_x_car.ids().union(&new_x_cdr.ids()), new_x_car, new_x_cdr)))); return Ok((bctx, Rc::new(MarkedForm::Pair(new_x_car.ids().union(&new_x_cdr.ids()), new_x_car, new_x_cdr))));
}, },
MarkedForm::Nil => return Ok((ctx,x)), MarkedForm::Nil => return Ok((bctx,x)),
_ => return Err("not a list".to_owned()), _ => return Err("not a list".to_owned()),
} }
} }
if let Ok((new_ctx, new_cdr)) = map_unval_peval(ctx.clone(), Rc::clone(&cdr)) { //asdf
if let Ok((new_bctx, new_cdr)) = map_unval_peval(bctx.clone(), dctx.clone(), Rc::clone(&cdr)) {
car = car.decrement_wrap_level().unwrap(); car = car.decrement_wrap_level().unwrap();
cdr = new_cdr; cdr = new_cdr;
ctx = new_ctx; bctx = new_bctx;
} else { } else {
break; break;
} }
@@ -445,30 +465,30 @@ pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>),
if !cdr.is_value() { if !cdr.is_value() {
break; break;
} }
if let Ok((ctx, r)) = match &*car { if let Ok((bctx, r)) = match &*car {
MarkedForm::PrimComb { name, wrap_level, f} => f(ctx.clone(), Rc::clone(&cdr)), MarkedForm::PrimComb { name, wrap_level, f} => f(bctx.clone(), dctx.clone(), Rc::clone(&cdr)),
MarkedForm::DeriComb { ids, se, de, id, wrap_level, sequence_params, rest_params, body } => { MarkedForm::DeriComb { ids, se, de, id, wrap_level, sequence_params, rest_params, body } => {
//DeriComb { ids: NeededIds, se: Rc<MarkedForm>, de: Option<String>, id: EnvID, wrap_level: i32, sequence_params: Vec<String>, rest_params: Option<String>, body: Rc<MarkedForm> }, //DeriComb { ids: NeededIds, se: Rc<MarkedForm>, de: Option<String>, id: EnvID, wrap_level: i32, sequence_params: Vec<String>, rest_params: Option<String>, body: Rc<MarkedForm> },
let inner_env = if let Some(de) = de { massoc(de, Rc::clone(&ctx.e), Rc::clone(se)) } else { Rc::clone(se) }; let inner_env = if let Some(de) = de { massoc(de, Rc::clone(&dctx.e), Rc::clone(se)) } else { Rc::clone(se) };
// not yet supporting sequence params // not yet supporting sequence params
let inner_env = if let Some(p) = rest_params { massoc(p, Rc::clone(&cdr), inner_env) } else { inner_env }; let inner_env = if let Some(p) = rest_params { massoc(p, Rc::clone(&cdr), inner_env) } else { inner_env };
// check for id in it? // check for id in it?
partial_eval(ctx.copy_with(&inner_env), Rc::clone(body)).map(|(ictx, res)| { (ictx.copy_with(&ctx.e), PossibleMarkedTailCall::Result(res)) }) partial_eval(bctx.clone(), dctx.copy_push_env(&inner_env), Rc::clone(body)).map(|(ibctx, res)| { (ibctx, PossibleMarkedTailCall::Result(res)) })
}, },
_ => break, _ => break,
} { } {
match r { match r {
PossibleMarkedTailCall::Result(result) => return Ok((ctx, result)), PossibleMarkedTailCall::Result(result) => return Ok((bctx, result)),
// Sigh, no tail-callin right now // Sigh, no tail-callin right now
PossibleMarkedTailCall::TailCall(new_env, next) => { PossibleMarkedTailCall::TailCall(new_env, next) => {
println!("Doing tail call of {} in {}", next, new_env); println!("Doing tail call of {} in {}", next, new_env);
if let Ok((new_ctx, res)) = partial_eval(ctx.copy_with(&new_env), Rc::clone(&next)) { if let Ok((new_bctx, res)) = partial_eval(bctx.clone(), dctx.copy_push_env(&new_env), Rc::clone(&next)) {
println!("Doing tail call result is {}", res); println!("Doing tail call result is {}", res);
return Ok((new_ctx.copy_with(&ctx.e), res)); return Ok((new_bctx, res));
} else { } else {
println!("Tail call failed"); println!("Tail call failed");
if new_env == ctx.e { if new_env == dctx.e {
return Ok((ctx, next)); return Ok((bctx, next));
} else { } else {
// maybe this should enplace the TailCall with an eval // maybe this should enplace the TailCall with an eval
break; // break out to reconstruction break; // break out to reconstruction
@@ -487,17 +507,17 @@ pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>),
// This would come from trying it again // This would come from trying it again
//let new_ids = if let Some(hash) = resume_hash { new_ids.add_hash(hash) } else { new_ids }; //let new_ids = if let Some(hash) = resume_hash { new_ids.add_hash(hash) } else { new_ids };
let new_attempted = attempted.clone(); let new_attempted = attempted.clone();
Ok((ctx, Rc::new(MarkedForm::SuspendedPair{ ids: new_ids, attempted: new_attempted, car, cdr }))) Ok((bctx, Rc::new(MarkedForm::SuspendedPair{ ids: new_ids, attempted: new_attempted, car, cdr })))
}, },
MarkedForm::Pair(ids,car,cdr) => { MarkedForm::Pair(ids,car,cdr) => {
let (ctx, car) = partial_eval(ctx, Rc::clone(car))?; let (bctx, car) = partial_eval(bctx, dctx.clone(), Rc::clone(car))?;
let (ctx, cdr) = partial_eval(ctx, Rc::clone(cdr))?; let (bctx, cdr) = partial_eval(bctx, dctx, Rc::clone(cdr))?;
Ok((ctx, Rc::new(MarkedForm::Pair(car.ids().union(&cdr.ids()),car, cdr)))) Ok((bctx, Rc::new(MarkedForm::Pair(car.ids().union(&cdr.ids()),car, cdr))))
}, },
MarkedForm::PrimComb { .. } => Ok((ctx, x)), MarkedForm::PrimComb { .. } => Ok((bctx, x)),
// Sub stuff // Sub stuff
MarkedForm::DeriComb { .. } => Ok((ctx, x)), MarkedForm::DeriComb { .. } => Ok((bctx, x)),
_ => Ok((ctx, x)), _ => Ok((bctx, x)),
} }
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@@ -519,7 +539,7 @@ pub enum MarkedForm {
// resume hash is folded into ids // resume hash is folded into ids
SuspendedPair { ids: NeededIds, attempted: Attempted, car: Rc<MarkedForm>, cdr: Rc<MarkedForm>}, SuspendedPair { ids: NeededIds, attempted: Attempted, car: Rc<MarkedForm>, cdr: Rc<MarkedForm>},
PrimComb { name: String, wrap_level: i32, f: fn(Ctx,Rc<MarkedForm>) -> Result<(Ctx,PossibleMarkedTailCall),String> }, PrimComb { name: String, wrap_level: i32, f: fn(BCtx,DCtx,Rc<MarkedForm>) -> Result<(BCtx,PossibleMarkedTailCall),String> },
DeriComb { ids: NeededIds, se: Rc<MarkedForm>, de: Option<String>, id: EnvID, wrap_level: i32, sequence_params: Vec<String>, rest_params: Option<String>, body: Rc<MarkedForm> }, DeriComb { ids: NeededIds, se: Rc<MarkedForm>, de: Option<String>, id: EnvID, wrap_level: i32, sequence_params: Vec<String>, rest_params: Option<String>, body: Rc<MarkedForm> },
} }
impl MarkedForm { impl MarkedForm {

View File

@@ -4,19 +4,19 @@ lalrpop_mod!(pub grammar);
use std::rc::Rc; use std::rc::Rc;
mod ast; mod ast;
use crate::ast::{partial_eval,Ctx,eval,root_env,MarkedForm,Form,PossibleTailCall}; use crate::ast::{partial_eval,new_base_ctxs,eval,root_env,MarkedForm,Form,PossibleTailCall};
fn main() { fn main() {
let input = "(= 17 ((vau d p (+ (eval (car p) d) 13)) (+ 1 3)))"; let input = "(= 17 ((vau d p (+ (eval (car p) d) 13)) (+ 1 3)))";
let parsed_input = Rc::new(grammar::TermParser::new().parse(input).unwrap()); let parsed_input = Rc::new(grammar::TermParser::new().parse(input).unwrap());
println!("Parsed input is {} - {:?}", parsed_input, parsed_input); println!("Parsed input is {} - {:?}", parsed_input, parsed_input);
let ctx = Ctx::default(); let (bctx, dctx) = new_base_ctxs();
let (ctx, marked) = parsed_input.marked(ctx); let (bctx, marked) = parsed_input.marked(bctx);
let unvaled = marked.unval().unwrap(); let unvaled = marked.unval().unwrap();
println!("Parsed unvaled that is {}", unvaled); println!("Parsed unvaled that is {}", unvaled);
match partial_eval(ctx, unvaled) { match partial_eval(bctx, dctx, unvaled) {
Ok((ctx, ped)) => println!("Parsed unvaled pe that is {}", ped), Ok((bctx, ped)) => println!("Parsed unvaled pe that is {}", ped),
Err(e) => println!("Partial evaluation error {}", e), Err(e) => println!("Partial evaluation error {}", e),
}; };
let result = eval(root_env(), parsed_input); let result = eval(root_env(), parsed_input);
@@ -43,18 +43,15 @@ fn eval_test<T: Into<Form>>(gram: &grammar::TermParser, e: &Rc<Form>, code: &str
let parsed = Rc::new(gram.parse(code).unwrap()); let parsed = Rc::new(gram.parse(code).unwrap());
let basic_result = eval(Rc::clone(e), Rc::clone(&parsed)); let basic_result = eval(Rc::clone(e), Rc::clone(&parsed));
assert_eq!(*basic_result, expected.into()); assert_eq!(*basic_result, expected.into());
let ctx = Ctx::default(); let (bctx, dctx) = new_base_ctxs();
let (ctx, marked) = parsed.marked(ctx); let (bctx, marked) = parsed.marked(bctx);
let unvaled = marked.unval().unwrap(); let unvaled = marked.unval().unwrap();
let (ctx, ped) = partial_eval(ctx, unvaled).unwrap(); let (bctx, ped) = partial_eval(bctx, dctx, unvaled).unwrap();
let (ctx, marked_basic_result) = basic_result.marked(ctx); let (bctx, marked_basic_result) = basic_result.marked(bctx);
println!("pe got {}", ped); println!("pe got {}", ped);
assert_eq!(*ped, *marked_basic_result); assert_eq!(*ped, *marked_basic_result);
} }
fn partial_eval_test(gram: &grammar::TermParser, ctx: &Ctx, code: &str, expected: &str) {
}
#[test] #[test]
fn basic_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); fn basic_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(&g, &e, "(+ 2 (car (cons 4 '(1 2))))", 6); eval_test(&g, &e, "(+ 2 (car (cons 4 '(1 2))))", 6);