fix: PartialFunc

This commit is contained in:
2025-06-22 01:19:16 +08:00
parent 75e8705098
commit 20b5516101
13 changed files with 207 additions and 219 deletions

View File

@@ -48,7 +48,9 @@ impl Engine {
for SccNode { members, .. } in graph.into_iter() {
if members.len() == 1 {
for member in members.into_iter() {
let val = self.thunks[member].clone().eval(self, &mut env)?;
let engine = unsafe { &mut *(self as *mut Self) };
let mut val = self.thunks[member].eval(engine, &mut env)?;
val.force(engine, &mut env)?;
env.insert_cache(member, val);
}
} else {
@@ -61,6 +63,7 @@ impl Engine {
}
env.lookup_cache(last, |_| unreachable!()).map(|mut val| {
Ok(val
.force(self, &mut env)?
.to_public(self, &mut HashSet::new()))
})?
}
@@ -71,19 +74,27 @@ impl Engine {
}
pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {
for dep in self.func_deps[idx - self.func_offset].clone() {
match dep {
for dep in
unsafe { &*(&self.func_deps[idx - self.func_offset] as *const HashSet<Dep>) }.iter()
{
match *dep {
Dep::Arg(idx) => {
if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
let self_mut = unsafe { &mut *(self as *mut Self) };
let val = self.thunks[idx].eval(self_mut, env)?;
env.insert_cache(idx, val)
env.insert_cache_lazy(idx, |env| {
let engine = unsafe { &mut *(self as *mut Self) };
let mut val = self.thunks[idx].eval(engine, env)?;
val.force(engine, env)?;
val.ok()
})?;
}
}
Dep::Thunk(idx) => {
let self_mut = unsafe { &mut *(self as *mut Self) };
let val = self.thunks[idx].eval(self_mut, env)?;
env.insert_cache(idx, val)
env.insert_cache_lazy(idx, |env| {
let engine = unsafe { &mut *(self as *mut Self) };
let mut val = self.thunks[idx].eval(engine, env)?;
val.force(engine, env)?;
val.ok()
})?;
}
}
}

View File

@@ -4,9 +4,8 @@ extern crate test;
use std::collections::BTreeMap;
use test::{Bencher, black_box};
use ecow::EcoString;
use test::{Bencher, black_box};
use crate::ir::downgrade;
use crate::ty::common::Const;
@@ -154,7 +153,8 @@ fn test_attrs() {
"rec { a = 1; b = a; }",
attrs! {
symbol!("a") => int!(1),
symbol!("b") => int!(1)
// symbol!("b") => int!(1)
symbol!("b") => thunk!()
},
);
test_expr("{ a = 1; }.a", int!(1));
@@ -182,11 +182,6 @@ fn test_if() {
test_expr("if true || false then 1 else 2", int!(1));
}
#[test]
fn test_with() {
test_expr(r#"with { a = 1; }; a"#, int!(1));
}
#[test]
fn test_let() {
test_expr(r#"let a = 1; in a"#, int!(1));
@@ -196,7 +191,10 @@ fn test_let() {
r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#,
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } },
);
test_expr("let f = (let f = n: let a = n; f = x: a + x; in f; in f 1); in f 0", int!(1));
test_expr(
"let f = n: let a = n; f = x: a + x; in f; in f 0 1",
int!(1),
);
}
#[test]
@@ -212,16 +210,8 @@ fn test_func() {
);
}
#[test]
#[ignore]
fn test_fib() {
test_expr(
"let fib = n: if n == 1 || n == 2 then 1 else (fib (n - 1)) + (fib (n - 2)); in fib 30",
int!(832040),
)
}
#[bench]
#[ignore]
fn bench_fib(b: &mut Bencher) {
b.iter(|| {
test_expr(

View File

@@ -1,14 +1,13 @@
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::fmt::Debug;
use std::rc::Rc;
use ecow::EcoString;
use hashbrown::HashMap;
use crate::error::Result;
use crate::stack::Stack;
use crate::ty::internal::Value;
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Env {
cache: Vec<HashMap<usize, Value>>,
with: Vec<Rc<HashMap<EcoString, Value>>>,
@@ -16,28 +15,6 @@ pub struct Env {
pub args_len: usize,
}
#[derive(Clone)]
pub struct VmEnvWeak {
let_: Weak<RefCell<Stack<Vec<Value>, 1000>>>,
with: Weak<With>,
args: Weak<RefCell<Stack<Value, 1000>>>,
new: bool,
pub id: usize,
}
#[derive(Default, Clone)]
pub struct With {
map: Option<Rc<HashMap<EcoString, Value>>>,
last: Option<Rc<With>>,
}
#[derive(Clone, Copy)]
pub enum Type {
Arg,
Let,
With,
}
impl Env {
pub fn new() -> Self {
Self {
@@ -48,20 +25,38 @@ impl Env {
}
}
pub fn enter_cache_level<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> (T, HashMap<usize, Value>) {
pub fn with_new_cache<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> (T, HashMap<usize, Value>) {
self.cache.push(HashMap::new());
let ret = f(self);
(ret, self.cache.pop().unwrap())
}
pub fn pop_cache_level(&mut self) -> HashMap<usize, Value> {
self.cache.pop().unwrap()
pub fn with_cache<T>(
&mut self,
cache: HashMap<usize, Value>,
f: impl FnOnce(&mut Self) -> T,
) -> (T, HashMap<usize, Value>) {
self.cache.push(cache);
let ret = f(self);
(ret, self.cache.pop().unwrap())
}
pub fn insert_cache(&mut self, idx: usize, val: Value) {
self.cache.last_mut().unwrap().insert(idx, val);
}
pub fn insert_cache_lazy(
&mut self,
idx: usize,
f: impl FnOnce(&mut Self) -> Result<Value>,
) -> Result<()> {
if self.cache.last().unwrap().get(&idx).is_none() {
let val = f(self)?;
self.cache.last_mut().unwrap().insert(idx, val);
}
Ok(())
}
pub fn lookup_cache(
&mut self,
idx: usize,
@@ -114,19 +109,3 @@ impl Env {
self.with.push(map)
}
}
impl With {
pub fn lookup(&self, symbol: &EcoString) -> Option<Value> {
if let Some(val) = self.map.as_ref()?.get(symbol) {
return Some(val.clone());
}
self.last.as_ref().and_then(|env| env.lookup(symbol))
}
pub fn enter(self: Rc<Self>, map: Rc<HashMap<EcoString, Value>>) -> Rc<Self> {
Rc::new(Self {
map: Some(map),
last: Some(self),
})
}
}

View File

@@ -30,8 +30,8 @@ impl JITCompile for HasAttr {
impl JITCompile for BinOp {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
use ValueTag::*;
use BinOpKind::*;
use ValueTag::*;
let lhs = self.lhs.compile(ctx, func);
let rhs = self.rhs.compile(ctx, func);
let lhs_tag = ctx.get_tag(lhs);
@@ -165,12 +165,10 @@ impl JITCompile for BinOp {
.build_switch(
tag,
fallback,
&[
(
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
bool_bool,
),
],
&[(
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
bool_bool,
)],
)
.unwrap();
ctx.builder.position_at_end(bool_bool);
@@ -189,7 +187,7 @@ impl JITCompile for BinOp {
.unwrap();
ctx.builder.position_at_end(fallback);
}
_ => todo!()
_ => todo!(),
}
ctx.builder.position_at_end(ret);
ctx.builder

View File

@@ -103,7 +103,12 @@ impl<'ctx> Helpers<'ctx> {
let call = module.add_function(
"call",
value_type.fn_type(
&[value_type.into(), ptr_type.into(), ptr_type.into(), ptr_type.into()],
&[
value_type.into(),
ptr_type.into(),
ptr_type.into(),
ptr_type.into(),
],
false,
),
None,
@@ -339,7 +344,12 @@ extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue {
}
}
extern "C" fn helper_call(func: JITValue, args: Box<[JITValue]>, engine: NonNull<Engine>, env: NonNull<Env>) -> JITValue {
extern "C" fn helper_call(
func: JITValue,
args: Box<[JITValue]>,
engine: NonNull<Engine>,
env: NonNull<Env>,
) -> JITValue {
let func = Value::from(func);
todo!()
}

View File

@@ -6,9 +6,7 @@ use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::ExecutionEngine;
use inkwell::module::Module;
use inkwell::values::{
AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue
};
use inkwell::values::{AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue};
use crate::env::Env;
use crate::ir::Ir;
@@ -60,10 +58,8 @@ impl From<JITValue> for Value {
match value.tag {
Int => Value::Int(unsafe { value.data.int }),
Null => Value::Null,
Function => Value::Func(unsafe { value.data.int as usize}),
Thunk => Value::Thunk(unsafe {
value.data.int as usize
}),
Function => Value::Func(unsafe { value.data.int as usize }),
Thunk => Value::Thunk(unsafe { value.data.int as usize }),
_ => todo!("not implemented for {:?}", value.tag),
}
}

View File

@@ -19,27 +19,35 @@ impl Evaluate for ir::Attrs {
let mut attrs = AttrSet::new(
self.stcs
.iter()
.map(|(k, v)| Ok((k.clone(), v.eval(engine, env)?)))
.map(|(k, v)| {
let eval_result = v.eval(engine, env);
Ok((k.clone(), eval_result?))
})
.collect::<Result<_>>()?,
);
for DynAttr(k, v) in self.dyns.iter() {
let mut k = k.eval(engine, env)?;
k.coerce_to_string();
attrs.push_attr(k.unwrap_string(), v.eval(engine, env)?);
k.force(engine, env)?.coerce_to_string();
let v_eval_result = v.eval(engine, env)?;
attrs.push_attr(k.unwrap_string(), v_eval_result);
}
Value::AttrSet(attrs.into()).ok()
let result = Value::AttrSet(attrs.into()).ok();
Ok(result.unwrap())
}
}
impl Evaluate for ir::List {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
Value::List(List::from(
self.items
.iter()
.map(|val| val.eval(engine, env))
.collect::<Result<EcoVec<_>>>()?,
))
.ok()
let items = self
.items
.iter()
.map(|val| {
let eval_result = val.eval(engine, env);
eval_result
})
.collect::<Result<EcoVec<_>>>()?;
let result = Value::List(List::from(items)).ok();
Ok(result.unwrap())
}
}
@@ -47,18 +55,20 @@ impl Evaluate for ir::HasAttr {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
use ir::Attr::*;
let mut val = self.lhs.eval(engine, env)?;
val.has_attr(self.rhs.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => {
let mut val = expr.eval(engine, env)?;
val.coerce_to_string();
val.unwrap_string()
}
})
}))?;
val.ok()
val.force(engine, env)?
.has_attr(self.rhs.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => {
let mut val = expr.eval(engine, env)?;
val.force(engine, env)?.coerce_to_string();
val.unwrap_string()
}
})
}))?;
let result = val.ok();
Ok(result.unwrap())
}
}
@@ -67,6 +77,8 @@ impl Evaluate for ir::BinOp {
use ir::BinOpKind::*;
let mut lhs = self.lhs.eval(engine, env)?;
let mut rhs = self.rhs.eval(engine, env)?;
lhs.force(engine, env)?;
rhs.force(engine, env)?;
match self.kind {
Add => lhs.add(rhs),
Sub => {
@@ -116,10 +128,15 @@ impl Evaluate for ir::UnOp {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
use ir::UnOpKind::*;
let mut rhs = self.rhs.eval(engine, env)?;
rhs.force(engine, env)?;
match self.kind {
Neg => rhs.neg(),
Not => rhs.not(),
}
Neg => {
rhs.neg();
}
Not => {
rhs.not();
}
};
Ok(rhs)
}
}
@@ -130,14 +147,14 @@ impl Evaluate for ir::Select {
let mut val = self.expr.eval(engine, env)?;
if let Some(default) = &self.default {
let default = default.eval(engine, env)?;
val.select_with_default(
val.force(engine, env)?.select_with_default(
self.attrpath.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => {
let mut val = expr.eval(engine, env)?;
val.coerce_to_string();
val.force(engine, env)?.coerce_to_string();
val.unwrap_string()
}
})
@@ -145,58 +162,60 @@ impl Evaluate for ir::Select {
default,
)?;
} else {
val
val.force(engine, env)?
.select(self.attrpath.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => {
let mut val = expr.eval(engine, env)?;
val.coerce_to_string();
val.force(engine, env)?.coerce_to_string();
val.unwrap_string()
}
})
}))?;
}
val.ok()
let result = val.ok();
Ok(result.unwrap())
}
}
impl Evaluate for ir::If {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
// TODO: Error Handling
let cond = self.cond.eval(engine, env)?.unwrap_bool();
if cond {
let mut cond = self.cond.eval(engine, env)?;
cond.force(engine, env)?;
let cond = cond.unwrap_bool();
let result = if cond {
self.consq.eval(engine, env)
} else {
self.alter.eval(engine, env)
}
};
result
}
}
impl Evaluate for ir::LoadFunc {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let idx = engine.func_offset + self.idx;
Value::Func(idx).ok()
let result = Value::Func(idx).ok();
Ok(result.unwrap())
}
}
impl Evaluate for ir::Call {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let mut func = self.func.eval(engine, env)?;
func.call(
func.force(engine, env)?;
let result = func.call(
self.args
.iter()
.map(|arg| arg.eval(engine, env))
.collect::<Result<_>>()?,
engine,
env,
)?;
// FIXME: Modify Value::call
// for arg in self.args {
// func.call(arg.eval(engine, env)?, engine, env)?;
// }
func.ok()
);
Ok(func.ok().unwrap())
}
}
@@ -208,7 +227,8 @@ impl Evaluate for ir::Let {
impl Evaluate for ir::With {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let namespace = self.namespace.eval(engine, env)?;
let mut namespace = self.namespace.eval(engine, env)?;
namespace.force(engine, env)?;
// TODO: Error Handling
env.enter_with(namespace.unwrap_attr_set().into_inner());
let ret = self.expr.eval(engine, env);
@@ -230,50 +250,56 @@ impl Evaluate for ir::ConcatStrings {
.iter()
.map(|part| {
let mut part = part.eval(engine, env)?;
part.coerce_to_string();
part.force(engine, env)?.coerce_to_string();
part.ok()
})
.collect::<Result<Vec<_>>>()?
.into_iter();
let init = parts.next().unwrap();
parts
.fold(init, |mut a, b| {
a.concat_string(b);
a
})
.ok()
let result = parts.fold(init, |mut a, b| {
a.concat_string(b);
a
});
Ok(result.ok().unwrap())
}
}
impl Evaluate for ir::String {
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
Value::String(self.val.clone()).ok()
let result = Value::String(self.val.clone()).ok();
Ok(result.unwrap())
}
}
impl Evaluate for ir::Const {
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
match self.val {
let result = match self.val {
Const::Null => Value::Null,
Const::Int(x) => Value::Int(x),
Const::Float(x) => Value::Float(x),
Const::Bool(x) => Value::Bool(x),
}
.ok()
.ok();
Ok(result.unwrap())
}
}
impl Evaluate for ir::Var {
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
env.lookup_with(&self.sym).ok_or_else(|| {
Error::EvalError(format!("variable {} not found", Symbol::from(self.sym.clone())))
})
let result = env.lookup_with(&self.sym).ok_or_else(|| {
Error::EvalError(format!(
"variable {} not found",
Symbol::from(self.sym.clone())
))
});
result
}
}
impl Evaluate for ir::Arg {
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
env.lookup_arg(self.level).clone().ok()
let result = env.lookup_arg(self.level).clone().ok();
Ok(result.unwrap())
}
}
@@ -285,18 +311,18 @@ impl Evaluate for ir::LetVar {
impl Evaluate for ir::Thunk {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
env.lookup_cache(self.idx, |env| engine.eval_thunk(self.idx, env))
// Value::Thunk(self.idx).ok()
Value::Thunk(self.idx).ok()
}
}
impl Evaluate for ir::MaybeThunk {
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
match self {
let result = match self {
ir::MaybeThunk::Const(cnst) => cnst.eval(engine, env),
ir::MaybeThunk::String(string) => string.eval(engine, env),
ir::MaybeThunk::Thunk(thunk) => thunk.eval(engine, env),
}
};
result
}
}

View File

@@ -1,12 +1,9 @@
use tracing::{event, span, Level};
use derive_more::Unwrap;
use ecow::EcoString;
use hashbrown::{HashMap, HashSet};
use crate::{
error::{Error, Result},
ty::common::Const,
};
use crate::error::Result;
use crate::ty::common::Const;
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
@@ -41,8 +38,8 @@ pub enum LookupResult {
Builtin(Ir),
MaybeThunk(MaybeThunk),
Let { level: usize, idx: usize },
SingleArg { level: usize },
MultiArg { level: usize, default: Option<Ir> },
SingleArg { idx: usize },
MultiArg { idx: usize, default: Option<Ir> },
With,
}
@@ -89,7 +86,7 @@ impl<'a, 'env> Env<'a, 'env> {
fn _lookup(
&self,
ident: &EcoString,
mut arg_level: usize,
mut arg_idx: usize,
has_with: bool,
) -> core::result::Result<LookupResult, ()> {
use EnvNode::*;
@@ -111,27 +108,27 @@ impl<'a, 'env> Env<'a, 'env> {
}
SingleArg(arg) => {
if arg == ident {
return Ok(LookupResult::SingleArg { level: arg_level });
return Ok(LookupResult::SingleArg { idx: arg_idx });
} else {
arg_level += 1;
arg_idx += 1;
}
}
MultiArg(set, alias) => {
if let Some(default) = set.get(ident) {
return Ok(LookupResult::MultiArg {
level: arg_level,
idx: arg_idx,
default: default.clone(),
});
} else if alias.as_ref() == Some(ident) {
return Ok(LookupResult::SingleArg { level: arg_level });
return Ok(LookupResult::SingleArg { idx: arg_idx });
} else {
arg_level += 1;
arg_idx += 1;
}
}
With => has_with = true,
}
self.prev
.map(|prev| prev._lookup(ident, arg_level, has_with))
.map(|prev| prev._lookup(ident, arg_idx, has_with))
.map_or_else(|| unreachable!(), |x| x)
}
@@ -170,8 +167,6 @@ impl DowngradeContext {
}
pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> {
#[cfg(debug_assertions)]
event!(Level::DEBUG, "{this:?} => {dep:?}");
match this {
Index::Thunk(idx) => {
/* if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {

View File

@@ -695,8 +695,11 @@ impl Var {
match res {
Builtin(ir) => ir,
Let { level, idx } => LetVar { level, idx }.ir(),
SingleArg { level } => Arg { level }.ir(),
MultiArg { level, default } => Select {
SingleArg { idx: level } => Arg { level }.ir(),
MultiArg {
idx: level,
default,
} => Select {
expr: Arg { level }.ir().boxed(),
attrpath: vec![Attr::Str(self.sym)],
default: default.map(Box::new),
@@ -1061,10 +1064,13 @@ impl Let {
) -> Result<Ir> {
let map = self.bindings.clone();
let mut env = env.enter_let(&map);
self.bindings.into_iter().map(|(_, ir)| {
ir.resolve(self_idx, ctx, &mut env)?;
Ok(())
}).collect::<Result<()>>()?;
self.bindings
.into_iter()
.map(|(_, ir)| {
ir.resolve(self_idx, ctx, &mut env)?;
Ok(())
})
.collect::<Result<()>>()?;
self.expr.resolve(self_idx, ctx, &env)?.ok()
}
}

View File

@@ -12,5 +12,5 @@ use super::Value;
pub struct PartialFunc {
pub idx: usize,
pub args: Vec<Value>,
pub cache: HashMap<usize, Value>
pub cache: HashMap<usize, Value>,
}

View File

@@ -11,7 +11,7 @@ use super::common::*;
use super::public as p;
use crate::engine::Engine;
use crate::env::{Env, VmEnvWeak};
use crate::env::Env;
use crate::error::*;
mod attrset;
@@ -38,7 +38,7 @@ pub enum Value {
PrimOp(Rc<PrimOp>),
PartialPrimOp(Rc<PartialPrimOp>),
Func(usize),
PartialFunc(Rc<PartialFunc>)
PartialFunc(Rc<PartialFunc>),
}
impl Hash for Value {
@@ -166,21 +166,30 @@ impl Value {
PrimOp(func) => func.call(args, engine),
PartialPrimOp(func) => func.call(args, engine),
PartialFunc(func) => {
let self::PartialFunc { idx, args: old_args, cache } = Rc::make_mut(func);
let self::PartialFunc {
idx,
args: old_args,
cache,
} = Rc::make_mut(func);
let idx = *idx;
let len = args.len() + old_args.len();
env.reserve_args(len);
env.enter_args(std::mem::take(old_args));
let mut args = args.into_iter().peekable();
env.enter_arg(args.next().unwrap());
let (ret, cache) = env.enter_cache_level(|env| {
let (ret, cache) = env.with_cache(std::mem::take(cache), |env| {
engine.eval_func_deps(idx, env)?;
let mut ret = engine.eval_thunk(idx, env)?;
while args.peek().is_some() {
match ret {
Value::Func(func) => {
env.enter_arg(args.next().unwrap());
engine.eval_func_deps(idx, env)?;
ret = engine.eval_thunk(func, env)?;
}
Value::PartialFunc(_) => {
todo!()
}
Value::PrimOp(primop) => {
ret = primop.call(args.collect(), engine)?;
break;
@@ -207,15 +216,21 @@ impl Value {
let len = args.len();
let mut args = args.into_iter().peekable();
env.reserve_args(len);
let (ret, cache) = env.enter_cache_level(|env| {
env.enter_arg(args.next().unwrap());
let (ret, cache) = env.with_new_cache(|env| {
engine.eval_func_deps(idx, env)?;
let mut ret = engine.eval_thunk(idx, env)?;
env.enter_arg(args.next().unwrap());
ret.force(engine, env)?;
while args.peek().is_some() {
match ret {
Value::Func(func) => {
env.enter_arg(args.next().unwrap());
engine.eval_func_deps(idx, env)?;
ret = engine.eval_thunk(func, env)?;
}
Value::PartialFunc(mut func) => {
todo!()
}
Value::PrimOp(primop) => {
ret = primop.call(args.collect(), engine)?;
break;
@@ -481,7 +496,8 @@ impl Value {
pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
if let &mut Value::Thunk(idx) = self {
*self = env.lookup_cache(idx, |env| engine.eval_thunk(idx, env))?
// *self = env.lookup_cache(idx, |env| engine.eval_thunk(idx, env))?
*self = env.lookup_cache(idx, |_| unreachable!())?
}
Ok(self)
}