Some steps forward, some back - add sanity testing that eval(e,x) == parial_eval(ctx, x.unval()), start fixing the bugs it reveals, split SuspendedLookup into SuspendedEnvLookup and SuspendedParamLookup

This commit is contained in:
2023-02-19 01:18:59 -05:00
parent fdaca7f807
commit 283c0232b0
2 changed files with 68 additions and 38 deletions

View File

@@ -105,25 +105,36 @@ impl Form {
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()?;
// TODO: pe-body, figure out wrap level, sequence params, etc
let se = Rc::clone(&ctx.e);
let (ctx, id) = ctx.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_env = if let Some(de) = &de {
massoc(de, Rc::new(MarkedForm::SuspendedEnvLookup { name: Some(de.clone()), id: id.clone() }), Rc::clone(&se))
} else { Rc::clone(&se) };
// not yet supporting sequence 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)
} 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 ids = ctx.e.ids().union(&body.ids());
let (ctx, id) = ctx.new_id();
let e = Rc::clone(&ctx.e);
Ok((ctx, PossibleMarkedTailCall::Result(Rc::new(
MarkedForm::DeriComb { ids, se: e, 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
"if" => Rc::new(MarkedForm::PrimComb { name: "if".to_owned(), wrap_level: 0, f: |ctx, p| {
let (ctx, cond) = partial_eval(ctx, p.car()?)?;
let (ctx, cond) = partial_eval(ctx, p.car()?.unval()?)?;
let e = Rc::clone(&ctx.e);
if cond.truthy()? {
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?)))
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.car()?.unval()?)))
} else {
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.cdr()?.car()?)))
Ok((ctx, PossibleMarkedTailCall::TailCall(e, p.cdr()?.cdr()?.car()?.unval()?)))
}
}}),
// TODO: handle these in the context of paritals
@@ -398,7 +409,11 @@ pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>),
}
return Ok((ctx, t.car()?.cdr()?));
},
MarkedForm::SuspendedLookup { name, id, cdr_num, car } => {
MarkedForm::SuspendedEnvLookup { name, id } => {
// lookup in stack
Ok((ctx, x))
},
MarkedForm::SuspendedParamLookup { name, id, cdr_num, car } => {
// lookup in stack
Ok((ctx, x))
},
@@ -446,7 +461,7 @@ pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>),
PossibleMarkedTailCall::Result(result) => return Ok((ctx, result)),
// Sigh, no tail-callin right now
PossibleMarkedTailCall::TailCall(new_env, next) => {
println!("Doing tail call of {} in {}", new_env, next);
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)) {
println!("Doing tail call result is {}", res);
return Ok((new_ctx.copy_with(&ctx.e), res));
@@ -499,7 +514,8 @@ pub enum MarkedForm {
Pair(NeededIds, Rc<MarkedForm>,Rc<MarkedForm>),
SuspendedSymbol(String),
SuspendedLookup { name: Option<String>, id: EnvID, cdr_num: i32, car: bool },
SuspendedParamLookup { name: Option<String>, id: EnvID, cdr_num: i32, car: bool },
SuspendedEnvLookup { name: Option<String>, id: EnvID },
// resume hash is folded into ids
SuspendedPair { ids: NeededIds, attempted: Attempted, car: Rc<MarkedForm>, cdr: Rc<MarkedForm>},
@@ -523,30 +539,32 @@ impl MarkedForm {
}
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(ids,car,cdr) => ids.clone(),
MarkedForm::SuspendedSymbol(name) => NeededIds::new_true(),
MarkedForm::SuspendedLookup { id, .. } => NeededIds::new_single(id.clone()),
MarkedForm::SuspendedPair{ ids, .. } => ids.clone(),
MarkedForm::PrimComb { .. } => NeededIds::new_none(),
MarkedForm::DeriComb { ids, .. } => ids.clone(),
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(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(),
}
}
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::SuspendedLookup { id, .. } => return false,
MarkedForm::SuspendedPair{ ids, .. } => return false,
MarkedForm::PrimComb { .. } => return true,
MarkedForm::Pair(ids,car,cdr) => ids.clone(),
MarkedForm::DeriComb { ids, .. } => ids.clone(),
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(ids,car,cdr) => ids.clone(),
MarkedForm::DeriComb { ids, .. } => ids.clone(),
} {
NeededIds::True(hashes) => false,
NeededIds::None(hashes) => true,
@@ -561,7 +579,8 @@ impl MarkedForm {
MarkedForm::Symbol(s) => Ok(Rc::new(MarkedForm::SuspendedSymbol(s.clone()))),
MarkedForm::Pair(ids,car,cdr) => Ok(Rc::new(MarkedForm::SuspendedPair { ids: NeededIds::new_true(), attempted: Attempted::False, car: car.unval()?, cdr: Rc::clone(cdr)})),
MarkedForm::SuspendedSymbol(name) => Err("trying to unval a suspended symbol"),
MarkedForm::SuspendedLookup { .. } => Err("trying to unval a suspended lookup"),
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)),
@@ -575,7 +594,8 @@ impl MarkedForm {
MarkedForm::Symbol(s) => Ok(true),
MarkedForm::Pair(ids,car,cdr) => Ok(true),
MarkedForm::SuspendedSymbol(name) => Err("trying to truthy a suspended symbol"),
MarkedForm::SuspendedLookup { .. } => Err("trying to truthy a suspended lookup"),
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),
@@ -634,9 +654,10 @@ impl fmt::Display for MarkedForm {
}
}
},
MarkedForm::SuspendedSymbol(name) => write!(f, "{}", name),
MarkedForm::SuspendedLookup { name, id, cdr_num, car } => write!(f, "{:?}({:?}{}{})", name, id, cdr_num, car),
MarkedForm::PrimComb { name, wrap_level, .. } => write!(f, "<{}{}>", name, wrap_level),
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),

View File

@@ -39,11 +39,20 @@ fn parse_test() {
}
fn eval_test<T: Into<Form>>(gram: &grammar::TermParser, e: &Rc<Form>, code: &str, expected: T) {
assert_eq!(*eval(Rc::clone(e), Rc::new(gram.parse(code).unwrap())), expected.into());
println!("Doing {}", code);
let parsed = Rc::new(gram.parse(code).unwrap());
let basic_result = eval(Rc::clone(e), Rc::clone(&parsed));
assert_eq!(*basic_result, expected.into());
let ctx = Ctx::default();
let (ctx, marked) = parsed.marked(ctx);
let unvaled = marked.unval().unwrap();
let (ctx, ped) = partial_eval(ctx, unvaled).unwrap();
let (ctx, marked_basic_result) = basic_result.marked(ctx);
println!("pe got {}", ped);
assert_eq!(*ped, *marked_basic_result);
}
fn partial_eval_test<T: Into<Form>>(gram: &grammar::TermParser, e: &Rc<Form>, code: &str, expected: T) {
assert_eq!(*eval(Rc::clone(e), Rc::new(gram.parse(code).unwrap())), expected.into());
fn partial_eval_test(gram: &grammar::TermParser, ctx: &Ctx, code: &str, expected: &str) {
}
#[test]