From fdaca7f80742fdc3f46fed212bdd6765b56f7b52 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 19 Feb 2023 00:46:54 -0500 Subject: [PATCH] Implement basic derived calls, and fix eval not unvaling bug --- kr/src/ast.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++-- kr/src/main.rs | 5 +++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/kr/src/ast.rs b/kr/src/ast.rs index 30894bf..ad09c24 100644 --- a/kr/src/ast.rs +++ b/kr/src/ast.rs @@ -95,8 +95,9 @@ impl Form { // 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| { // put in partial eval logic, maybe? - let b = p.car()?; + let b = p.car()?.unval()?; let e = p.cdr()?.car()?; + println!("Doing Eval (via tail call) of {} in {}", b, e); Ok((ctx, PossibleMarkedTailCall::TailCall(e, b))) }}), // (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| { let a = p.car()?; let b = p.cdr()?.car()?; + println!("DOing (= {} {}) = {}", a, b, a==b); // TODO: double check that this ignores ids etc. It should, since // wrap_level=1 should mean that everything's a value // also, it should just check by hash then? @@ -387,6 +389,7 @@ impl Default for Ctx { } } pub fn partial_eval(ctx: Ctx, x: Rc) -> Result<(Ctx,Rc), String> { + println!("PE: {}", x); match &*x { MarkedForm::SuspendedSymbol(name) => { let mut t = Rc::clone(&ctx.e); @@ -424,18 +427,31 @@ pub fn partial_eval(ctx: Ctx, x: Rc) -> Result<(Ctx,Rc), } } else { // check to see if can do call + if !cdr.is_value() { + break; + } if let Ok((ctx, r)) = match &*car { 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, de: Option, id: EnvID, wrap_level: i32, sequence_params: Vec, rest_params: Option, body: Rc }, + 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, } { match r { 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); 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)); } else { + println!("Tail call failed"); if new_env == ctx.e { return Ok((ctx, next)); } else { @@ -519,6 +535,24 @@ impl MarkedForm { 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) -> Result, &'static str> { match &**self { MarkedForm::Nil => Ok(Rc::clone(self)), @@ -674,6 +708,15 @@ pub fn eval(e: Rc
, f: Rc) -> Rc { } } } +fn massoc(k: &str, v: Rc, l: Rc) -> Rc { + 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, l: Rc) -> Rc { Rc::new(Form::Pair( Rc::new(Form::Pair( diff --git a/kr/src/main.rs b/kr/src/main.rs index 6905f37..659505a 100644 --- a/kr/src/main.rs +++ b/kr/src/main.rs @@ -37,10 +37,15 @@ fn parse_test() { } assert!(g.parse("((22)").is_err()); } + fn eval_test>(gram: &grammar::TermParser, e: &Rc, 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, e: &Rc, code: &str, expected: T) { + assert_eq!(*eval(Rc::clone(e), Rc::new(gram.parse(code).unwrap())), expected.into()); +} + #[test] fn basic_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); eval_test(&g, &e, "(+ 2 (car (cons 4 '(1 2))))", 6);