Implement basic derived calls, and fix eval not unvaling bug

This commit is contained in:
2023-02-19 00:46:54 -05:00
parent c5f7a52a38
commit fdaca7f807
2 changed files with 50 additions and 2 deletions

View File

@@ -95,8 +95,9 @@ impl Form {
// 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: |ctx, p| {
// put in partial eval logic, maybe? // put in partial eval logic, maybe?
let b = p.car()?; 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);
Ok((ctx, PossibleMarkedTailCall::TailCall(e, b))) Ok((ctx, 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
@@ -160,6 +161,7 @@ impl Form {
"=" => Rc::new(MarkedForm::PrimComb { name: "=".to_owned(), wrap_level: 1, f: |ctx, p| { "=" => Rc::new(MarkedForm::PrimComb { name: "=".to_owned(), wrap_level: 1, f: |ctx, 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);
// 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?
@@ -387,6 +389,7 @@ impl Default for Ctx {
} }
} }
pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>), String> { pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>), String> {
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(&ctx.e);
@@ -424,18 +427,31 @@ pub fn partial_eval(ctx: Ctx, x: Rc<MarkedForm>) -> Result<(Ctx,Rc<MarkedForm>),
} }
} else { } else {
// check to see if can do call // check to see if can do call
if !cdr.is_value() {
break;
}
if let Ok((ctx, r)) = match &*car { if let Ok((ctx, r)) = match &*car {
MarkedForm::PrimComb { name, wrap_level, f} => f(ctx.clone(), Rc::clone(&cdr)), MarkedForm::PrimComb { name, wrap_level, f} => f(ctx.clone(), Rc::clone(&cdr)),
MarkedForm::DeriComb { ids, se, de, id, wrap_level, sequence_params, rest_params, body } => break, 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> },
let inner_env = if let Some(de) = de { massoc(de, Rc::clone(&ctx.e), Rc::clone(se)) } else { Rc::clone(se) };
// not yet supporting sequence params
let inner_env = if let Some(p) = rest_params { massoc(p, Rc::clone(&cdr), inner_env) } else { inner_env };
// 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)) })
},
_ => break, _ => break,
} { } {
match r { match r {
PossibleMarkedTailCall::Result(result) => return Ok((ctx, result)), PossibleMarkedTailCall::Result(result) => return Ok((ctx, 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 {}", new_env, next);
if let Ok((new_ctx, res)) = partial_eval(ctx.copy_with(&new_env), Rc::clone(&next)) { 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)); return Ok((new_ctx.copy_with(&ctx.e), res));
} else { } else {
println!("Tail call failed");
if new_env == ctx.e { if new_env == ctx.e {
return Ok((ctx, next)); return Ok((ctx, next));
} else { } else {
@@ -519,6 +535,24 @@ impl MarkedForm {
MarkedForm::DeriComb { ids, .. } => ids.clone(), 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(),
} {
NeededIds::True(hashes) => false,
NeededIds::None(hashes) => true,
NeededIds::Some(ids,hashes) => false,
}
}
pub fn unval(self: &Rc<MarkedForm>) -> Result<Rc<MarkedForm>, &'static str> { pub fn unval(self: &Rc<MarkedForm>) -> Result<Rc<MarkedForm>, &'static str> {
match &**self { match &**self {
MarkedForm::Nil => Ok(Rc::clone(self)), MarkedForm::Nil => Ok(Rc::clone(self)),
@@ -674,6 +708,15 @@ pub fn eval(e: Rc<Form>, f: Rc<Form>) -> Rc<Form> {
} }
} }
} }
fn massoc(k: &str, v: Rc<MarkedForm>, l: Rc<MarkedForm>) -> Rc<MarkedForm> {
Rc::new(MarkedForm::Pair(
l.ids().union(&v.ids()),
Rc::new(MarkedForm::Pair(
v.ids(),
Rc::new(MarkedForm::Symbol(k.to_owned())),
v)),
l))
}
fn assoc(k: &str, v: Rc<Form>, l: Rc<Form>) -> Rc<Form> { fn assoc(k: &str, v: Rc<Form>, l: Rc<Form>) -> Rc<Form> {
Rc::new(Form::Pair( Rc::new(Form::Pair(
Rc::new(Form::Pair( Rc::new(Form::Pair(

View File

@@ -37,10 +37,15 @@ fn parse_test() {
} }
assert!(g.parse("((22)").is_err()); assert!(g.parse("((22)").is_err());
} }
fn eval_test<T: Into<Form>>(gram: &grammar::TermParser, e: &Rc<Form>, code: &str, expected: T) { 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()); assert_eq!(*eval(Rc::clone(e), Rc::new(gram.parse(code).unwrap())), expected.into());
} }
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());
}
#[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);