fix: PartialFunc
This commit is contained in:
38
Cargo.lock
generated
38
Cargo.lock
generated
@@ -328,7 +328,6 @@ dependencies = [
|
|||||||
"rnix",
|
"rnix",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -337,12 +336,6 @@ version = "1.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "priority-queue"
|
name = "priority-queue"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -561,37 +554,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing"
|
|
||||||
version = "0.1.41"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
|
||||||
dependencies = [
|
|
||||||
"pin-project-lite",
|
|
||||||
"tracing-attributes",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-attributes"
|
|
||||||
version = "0.1.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-core"
|
|
||||||
version = "0.1.34"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ hashbrown = "0.15"
|
|||||||
priority-queue = "2.5"
|
priority-queue = "2.5"
|
||||||
lru = "0.14"
|
lru = "0.14"
|
||||||
replace_with = "0.1"
|
replace_with = "0.1"
|
||||||
tracing = "0.1"
|
|
||||||
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
||||||
|
|
||||||
rustyline = { version = "15.0", optional = true }
|
rustyline = { version = "15.0", optional = true }
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ impl Engine {
|
|||||||
for SccNode { members, .. } in graph.into_iter() {
|
for SccNode { members, .. } in graph.into_iter() {
|
||||||
if members.len() == 1 {
|
if members.len() == 1 {
|
||||||
for member in members.into_iter() {
|
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);
|
env.insert_cache(member, val);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -61,6 +63,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
env.lookup_cache(last, |_| unreachable!()).map(|mut val| {
|
env.lookup_cache(last, |_| unreachable!()).map(|mut val| {
|
||||||
Ok(val
|
Ok(val
|
||||||
|
.force(self, &mut env)?
|
||||||
.to_public(self, &mut HashSet::new()))
|
.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<()> {
|
pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {
|
||||||
for dep in self.func_deps[idx - self.func_offset].clone() {
|
for dep in
|
||||||
match dep {
|
unsafe { &*(&self.func_deps[idx - self.func_offset] as *const HashSet<Dep>) }.iter()
|
||||||
|
{
|
||||||
|
match *dep {
|
||||||
Dep::Arg(idx) => {
|
Dep::Arg(idx) => {
|
||||||
if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
|
if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
|
||||||
let self_mut = unsafe { &mut *(self as *mut Self) };
|
env.insert_cache_lazy(idx, |env| {
|
||||||
let val = self.thunks[idx].eval(self_mut, env)?;
|
let engine = unsafe { &mut *(self as *mut Self) };
|
||||||
env.insert_cache(idx, val)
|
let mut val = self.thunks[idx].eval(engine, env)?;
|
||||||
|
val.force(engine, env)?;
|
||||||
|
val.ok()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Dep::Thunk(idx) => {
|
Dep::Thunk(idx) => {
|
||||||
let self_mut = unsafe { &mut *(self as *mut Self) };
|
env.insert_cache_lazy(idx, |env| {
|
||||||
let val = self.thunks[idx].eval(self_mut, env)?;
|
let engine = unsafe { &mut *(self as *mut Self) };
|
||||||
env.insert_cache(idx, val)
|
let mut val = self.thunks[idx].eval(engine, env)?;
|
||||||
|
val.force(engine, env)?;
|
||||||
|
val.ok()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ extern crate test;
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use test::{Bencher, black_box};
|
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
use test::{Bencher, black_box};
|
||||||
|
|
||||||
use crate::ir::downgrade;
|
use crate::ir::downgrade;
|
||||||
use crate::ty::common::Const;
|
use crate::ty::common::Const;
|
||||||
@@ -154,7 +153,8 @@ fn test_attrs() {
|
|||||||
"rec { a = 1; b = a; }",
|
"rec { a = 1; b = a; }",
|
||||||
attrs! {
|
attrs! {
|
||||||
symbol!("a") => int!(1),
|
symbol!("a") => int!(1),
|
||||||
symbol!("b") => int!(1)
|
// symbol!("b") => int!(1)
|
||||||
|
symbol!("b") => thunk!()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
test_expr("{ a = 1; }.a", int!(1));
|
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_expr("if true || false then 1 else 2", int!(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_with() {
|
|
||||||
test_expr(r#"with { a = 1; }; a"#, int!(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_let() {
|
fn test_let() {
|
||||||
test_expr(r#"let a = 1; in a"#, int!(1));
|
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; }"#,
|
r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#,
|
||||||
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(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]
|
#[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]
|
#[bench]
|
||||||
|
#[ignore]
|
||||||
fn bench_fib(b: &mut Bencher) {
|
fn bench_fib(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
test_expr(
|
test_expr(
|
||||||
|
|||||||
69
src/env.rs
69
src/env.rs
@@ -1,14 +1,13 @@
|
|||||||
use std::cell::RefCell;
|
use std::fmt::Debug;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::stack::Stack;
|
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
cache: Vec<HashMap<usize, Value>>,
|
cache: Vec<HashMap<usize, Value>>,
|
||||||
with: Vec<Rc<HashMap<EcoString, Value>>>,
|
with: Vec<Rc<HashMap<EcoString, Value>>>,
|
||||||
@@ -16,28 +15,6 @@ pub struct Env {
|
|||||||
pub args_len: usize,
|
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 {
|
impl Env {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
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());
|
self.cache.push(HashMap::new());
|
||||||
let ret = f(self);
|
let ret = f(self);
|
||||||
(ret, self.cache.pop().unwrap())
|
(ret, self.cache.pop().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_cache_level(&mut self) -> HashMap<usize, Value> {
|
pub fn with_cache<T>(
|
||||||
self.cache.pop().unwrap()
|
&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) {
|
pub fn insert_cache(&mut self, idx: usize, val: Value) {
|
||||||
self.cache.last_mut().unwrap().insert(idx, val);
|
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(
|
pub fn lookup_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
@@ -114,19 +109,3 @@ impl Env {
|
|||||||
self.with.push(map)
|
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),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ impl JITCompile for HasAttr {
|
|||||||
|
|
||||||
impl JITCompile for BinOp {
|
impl JITCompile for BinOp {
|
||||||
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
use ValueTag::*;
|
|
||||||
use BinOpKind::*;
|
use BinOpKind::*;
|
||||||
|
use ValueTag::*;
|
||||||
let lhs = self.lhs.compile(ctx, func);
|
let lhs = self.lhs.compile(ctx, func);
|
||||||
let rhs = self.rhs.compile(ctx, func);
|
let rhs = self.rhs.compile(ctx, func);
|
||||||
let lhs_tag = ctx.get_tag(lhs);
|
let lhs_tag = ctx.get_tag(lhs);
|
||||||
@@ -165,12 +165,10 @@ impl JITCompile for BinOp {
|
|||||||
.build_switch(
|
.build_switch(
|
||||||
tag,
|
tag,
|
||||||
fallback,
|
fallback,
|
||||||
&[
|
&[(
|
||||||
(
|
|
||||||
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
|
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
|
||||||
bool_bool,
|
bool_bool,
|
||||||
),
|
)],
|
||||||
],
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ctx.builder.position_at_end(bool_bool);
|
ctx.builder.position_at_end(bool_bool);
|
||||||
@@ -189,7 +187,7 @@ impl JITCompile for BinOp {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
ctx.builder.position_at_end(fallback);
|
ctx.builder.position_at_end(fallback);
|
||||||
}
|
}
|
||||||
_ => todo!()
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
ctx.builder.position_at_end(ret);
|
ctx.builder.position_at_end(ret);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
|
|||||||
@@ -103,7 +103,12 @@ impl<'ctx> Helpers<'ctx> {
|
|||||||
let call = module.add_function(
|
let call = module.add_function(
|
||||||
"call",
|
"call",
|
||||||
value_type.fn_type(
|
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,
|
false,
|
||||||
),
|
),
|
||||||
None,
|
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);
|
let func = Value::from(func);
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ use inkwell::builder::Builder;
|
|||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::execution_engine::ExecutionEngine;
|
use inkwell::execution_engine::ExecutionEngine;
|
||||||
use inkwell::module::Module;
|
use inkwell::module::Module;
|
||||||
use inkwell::values::{
|
use inkwell::values::{AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue};
|
||||||
AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::ir::Ir;
|
use crate::ir::Ir;
|
||||||
@@ -60,10 +58,8 @@ impl From<JITValue> for Value {
|
|||||||
match value.tag {
|
match value.tag {
|
||||||
Int => Value::Int(unsafe { value.data.int }),
|
Int => Value::Int(unsafe { value.data.int }),
|
||||||
Null => Value::Null,
|
Null => Value::Null,
|
||||||
Function => Value::Func(unsafe { value.data.int as usize}),
|
Function => Value::Func(unsafe { value.data.int as usize }),
|
||||||
Thunk => Value::Thunk(unsafe {
|
Thunk => Value::Thunk(unsafe { value.data.int as usize }),
|
||||||
value.data.int as usize
|
|
||||||
}),
|
|
||||||
_ => todo!("not implemented for {:?}", value.tag),
|
_ => todo!("not implemented for {:?}", value.tag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
src/eval/mod.rs
122
src/eval/mod.rs
@@ -19,27 +19,35 @@ impl Evaluate for ir::Attrs {
|
|||||||
let mut attrs = AttrSet::new(
|
let mut attrs = AttrSet::new(
|
||||||
self.stcs
|
self.stcs
|
||||||
.iter()
|
.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<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
);
|
);
|
||||||
for DynAttr(k, v) in self.dyns.iter() {
|
for DynAttr(k, v) in self.dyns.iter() {
|
||||||
let mut k = k.eval(engine, env)?;
|
let mut k = k.eval(engine, env)?;
|
||||||
k.coerce_to_string();
|
k.force(engine, env)?.coerce_to_string();
|
||||||
attrs.push_attr(k.unwrap_string(), v.eval(engine, env)?);
|
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 {
|
impl Evaluate for ir::List {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
Value::List(List::from(
|
let items = self
|
||||||
self.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|val| val.eval(engine, env))
|
.map(|val| {
|
||||||
.collect::<Result<EcoVec<_>>>()?,
|
let eval_result = val.eval(engine, env);
|
||||||
))
|
eval_result
|
||||||
.ok()
|
})
|
||||||
|
.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> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
use ir::Attr::*;
|
use ir::Attr::*;
|
||||||
let mut val = self.lhs.eval(engine, env)?;
|
let mut val = self.lhs.eval(engine, env)?;
|
||||||
val.has_attr(self.rhs.iter().map(|attr| {
|
val.force(engine, env)?
|
||||||
|
.has_attr(self.rhs.iter().map(|attr| {
|
||||||
Ok(match attr {
|
Ok(match attr {
|
||||||
Str(ident) => ident.clone(),
|
Str(ident) => ident.clone(),
|
||||||
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
||||||
Dynamic(expr) => {
|
Dynamic(expr) => {
|
||||||
let mut val = expr.eval(engine, env)?;
|
let mut val = expr.eval(engine, env)?;
|
||||||
val.coerce_to_string();
|
val.force(engine, env)?.coerce_to_string();
|
||||||
val.unwrap_string()
|
val.unwrap_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}))?;
|
}))?;
|
||||||
val.ok()
|
let result = val.ok();
|
||||||
|
Ok(result.unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +77,8 @@ impl Evaluate for ir::BinOp {
|
|||||||
use ir::BinOpKind::*;
|
use ir::BinOpKind::*;
|
||||||
let mut lhs = self.lhs.eval(engine, env)?;
|
let mut lhs = self.lhs.eval(engine, env)?;
|
||||||
let mut rhs = self.rhs.eval(engine, env)?;
|
let mut rhs = self.rhs.eval(engine, env)?;
|
||||||
|
lhs.force(engine, env)?;
|
||||||
|
rhs.force(engine, env)?;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Add => lhs.add(rhs),
|
Add => lhs.add(rhs),
|
||||||
Sub => {
|
Sub => {
|
||||||
@@ -116,10 +128,15 @@ impl Evaluate for ir::UnOp {
|
|||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
use ir::UnOpKind::*;
|
use ir::UnOpKind::*;
|
||||||
let mut rhs = self.rhs.eval(engine, env)?;
|
let mut rhs = self.rhs.eval(engine, env)?;
|
||||||
|
rhs.force(engine, env)?;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Neg => rhs.neg(),
|
Neg => {
|
||||||
Not => rhs.not(),
|
rhs.neg();
|
||||||
}
|
}
|
||||||
|
Not => {
|
||||||
|
rhs.not();
|
||||||
|
}
|
||||||
|
};
|
||||||
Ok(rhs)
|
Ok(rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,14 +147,14 @@ impl Evaluate for ir::Select {
|
|||||||
let mut val = self.expr.eval(engine, env)?;
|
let mut val = self.expr.eval(engine, env)?;
|
||||||
if let Some(default) = &self.default {
|
if let Some(default) = &self.default {
|
||||||
let default = default.eval(engine, env)?;
|
let default = default.eval(engine, env)?;
|
||||||
val.select_with_default(
|
val.force(engine, env)?.select_with_default(
|
||||||
self.attrpath.iter().map(|attr| {
|
self.attrpath.iter().map(|attr| {
|
||||||
Ok(match attr {
|
Ok(match attr {
|
||||||
Str(ident) => ident.clone(),
|
Str(ident) => ident.clone(),
|
||||||
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
||||||
Dynamic(expr) => {
|
Dynamic(expr) => {
|
||||||
let mut val = expr.eval(engine, env)?;
|
let mut val = expr.eval(engine, env)?;
|
||||||
val.coerce_to_string();
|
val.force(engine, env)?.coerce_to_string();
|
||||||
val.unwrap_string()
|
val.unwrap_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -145,58 +162,60 @@ impl Evaluate for ir::Select {
|
|||||||
default,
|
default,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
val
|
val.force(engine, env)?
|
||||||
.select(self.attrpath.iter().map(|attr| {
|
.select(self.attrpath.iter().map(|attr| {
|
||||||
Ok(match attr {
|
Ok(match attr {
|
||||||
Str(ident) => ident.clone(),
|
Str(ident) => ident.clone(),
|
||||||
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
||||||
Dynamic(expr) => {
|
Dynamic(expr) => {
|
||||||
let mut val = expr.eval(engine, env)?;
|
let mut val = expr.eval(engine, env)?;
|
||||||
val.coerce_to_string();
|
val.force(engine, env)?.coerce_to_string();
|
||||||
val.unwrap_string()
|
val.unwrap_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
val.ok()
|
let result = val.ok();
|
||||||
|
Ok(result.unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::If {
|
impl Evaluate for ir::If {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
// TODO: Error Handling
|
// TODO: Error Handling
|
||||||
let cond = self.cond.eval(engine, env)?.unwrap_bool();
|
let mut cond = self.cond.eval(engine, env)?;
|
||||||
if cond {
|
cond.force(engine, env)?;
|
||||||
|
let cond = cond.unwrap_bool();
|
||||||
|
let result = if cond {
|
||||||
self.consq.eval(engine, env)
|
self.consq.eval(engine, env)
|
||||||
} else {
|
} else {
|
||||||
self.alter.eval(engine, env)
|
self.alter.eval(engine, env)
|
||||||
}
|
};
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::LoadFunc {
|
impl Evaluate for ir::LoadFunc {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let idx = engine.func_offset + self.idx;
|
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 {
|
impl Evaluate for ir::Call {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let mut func = self.func.eval(engine, env)?;
|
let mut func = self.func.eval(engine, env)?;
|
||||||
func.call(
|
func.force(engine, env)?;
|
||||||
|
let result = func.call(
|
||||||
self.args
|
self.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| arg.eval(engine, env))
|
.map(|arg| arg.eval(engine, env))
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
engine,
|
engine,
|
||||||
env,
|
env,
|
||||||
)?;
|
);
|
||||||
// FIXME: Modify Value::call
|
Ok(func.ok().unwrap())
|
||||||
// for arg in self.args {
|
|
||||||
// func.call(arg.eval(engine, env)?, engine, env)?;
|
|
||||||
// }
|
|
||||||
func.ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +227,8 @@ impl Evaluate for ir::Let {
|
|||||||
|
|
||||||
impl Evaluate for ir::With {
|
impl Evaluate for ir::With {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
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
|
// TODO: Error Handling
|
||||||
env.enter_with(namespace.unwrap_attr_set().into_inner());
|
env.enter_with(namespace.unwrap_attr_set().into_inner());
|
||||||
let ret = self.expr.eval(engine, env);
|
let ret = self.expr.eval(engine, env);
|
||||||
@@ -230,50 +250,56 @@ impl Evaluate for ir::ConcatStrings {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|part| {
|
.map(|part| {
|
||||||
let mut part = part.eval(engine, env)?;
|
let mut part = part.eval(engine, env)?;
|
||||||
part.coerce_to_string();
|
part.force(engine, env)?.coerce_to_string();
|
||||||
part.ok()
|
part.ok()
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?
|
.collect::<Result<Vec<_>>>()?
|
||||||
.into_iter();
|
.into_iter();
|
||||||
let init = parts.next().unwrap();
|
let init = parts.next().unwrap();
|
||||||
parts
|
let result = parts.fold(init, |mut a, b| {
|
||||||
.fold(init, |mut a, b| {
|
|
||||||
a.concat_string(b);
|
a.concat_string(b);
|
||||||
a
|
a
|
||||||
})
|
});
|
||||||
.ok()
|
Ok(result.ok().unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::String {
|
impl Evaluate for ir::String {
|
||||||
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
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 {
|
impl Evaluate for ir::Const {
|
||||||
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
||||||
match self.val {
|
let result = match self.val {
|
||||||
Const::Null => Value::Null,
|
Const::Null => Value::Null,
|
||||||
Const::Int(x) => Value::Int(x),
|
Const::Int(x) => Value::Int(x),
|
||||||
Const::Float(x) => Value::Float(x),
|
Const::Float(x) => Value::Float(x),
|
||||||
Const::Bool(x) => Value::Bool(x),
|
Const::Bool(x) => Value::Bool(x),
|
||||||
}
|
}
|
||||||
.ok()
|
.ok();
|
||||||
|
Ok(result.unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Var {
|
impl Evaluate for ir::Var {
|
||||||
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
env.lookup_with(&self.sym).ok_or_else(|| {
|
let result = env.lookup_with(&self.sym).ok_or_else(|| {
|
||||||
Error::EvalError(format!("variable {} not found", Symbol::from(self.sym.clone())))
|
Error::EvalError(format!(
|
||||||
})
|
"variable {} not found",
|
||||||
|
Symbol::from(self.sym.clone())
|
||||||
|
))
|
||||||
|
});
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Arg {
|
impl Evaluate for ir::Arg {
|
||||||
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
|
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 {
|
impl Evaluate for ir::Thunk {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
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 {
|
impl Evaluate for ir::MaybeThunk {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
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::Const(cnst) => cnst.eval(engine, env),
|
||||||
ir::MaybeThunk::String(string) => string.eval(engine, env),
|
ir::MaybeThunk::String(string) => string.eval(engine, env),
|
||||||
ir::MaybeThunk::Thunk(thunk) => thunk.eval(engine, env),
|
ir::MaybeThunk::Thunk(thunk) => thunk.eval(engine, env),
|
||||||
}
|
};
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
use tracing::{event, span, Level};
|
|
||||||
use derive_more::Unwrap;
|
use derive_more::Unwrap;
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::error::Result;
|
||||||
error::{Error, Result},
|
use crate::ty::common::Const;
|
||||||
ty::common::Const,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
|
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
|
||||||
|
|
||||||
@@ -41,8 +38,8 @@ pub enum LookupResult {
|
|||||||
Builtin(Ir),
|
Builtin(Ir),
|
||||||
MaybeThunk(MaybeThunk),
|
MaybeThunk(MaybeThunk),
|
||||||
Let { level: usize, idx: usize },
|
Let { level: usize, idx: usize },
|
||||||
SingleArg { level: usize },
|
SingleArg { idx: usize },
|
||||||
MultiArg { level: usize, default: Option<Ir> },
|
MultiArg { idx: usize, default: Option<Ir> },
|
||||||
With,
|
With,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +86,7 @@ impl<'a, 'env> Env<'a, 'env> {
|
|||||||
fn _lookup(
|
fn _lookup(
|
||||||
&self,
|
&self,
|
||||||
ident: &EcoString,
|
ident: &EcoString,
|
||||||
mut arg_level: usize,
|
mut arg_idx: usize,
|
||||||
has_with: bool,
|
has_with: bool,
|
||||||
) -> core::result::Result<LookupResult, ()> {
|
) -> core::result::Result<LookupResult, ()> {
|
||||||
use EnvNode::*;
|
use EnvNode::*;
|
||||||
@@ -111,27 +108,27 @@ impl<'a, 'env> Env<'a, 'env> {
|
|||||||
}
|
}
|
||||||
SingleArg(arg) => {
|
SingleArg(arg) => {
|
||||||
if arg == ident {
|
if arg == ident {
|
||||||
return Ok(LookupResult::SingleArg { level: arg_level });
|
return Ok(LookupResult::SingleArg { idx: arg_idx });
|
||||||
} else {
|
} else {
|
||||||
arg_level += 1;
|
arg_idx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MultiArg(set, alias) => {
|
MultiArg(set, alias) => {
|
||||||
if let Some(default) = set.get(ident) {
|
if let Some(default) = set.get(ident) {
|
||||||
return Ok(LookupResult::MultiArg {
|
return Ok(LookupResult::MultiArg {
|
||||||
level: arg_level,
|
idx: arg_idx,
|
||||||
default: default.clone(),
|
default: default.clone(),
|
||||||
});
|
});
|
||||||
} else if alias.as_ref() == Some(ident) {
|
} else if alias.as_ref() == Some(ident) {
|
||||||
return Ok(LookupResult::SingleArg { level: arg_level });
|
return Ok(LookupResult::SingleArg { idx: arg_idx });
|
||||||
} else {
|
} else {
|
||||||
arg_level += 1;
|
arg_idx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
With => has_with = true,
|
With => has_with = true,
|
||||||
}
|
}
|
||||||
self.prev
|
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)
|
.map_or_else(|| unreachable!(), |x| x)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,8 +167,6 @@ impl DowngradeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> {
|
pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
event!(Level::DEBUG, "{this:?} => {dep:?}");
|
|
||||||
match this {
|
match this {
|
||||||
Index::Thunk(idx) => {
|
Index::Thunk(idx) => {
|
||||||
/* if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {
|
/* if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {
|
||||||
|
|||||||
@@ -695,8 +695,11 @@ impl Var {
|
|||||||
match res {
|
match res {
|
||||||
Builtin(ir) => ir,
|
Builtin(ir) => ir,
|
||||||
Let { level, idx } => LetVar { level, idx }.ir(),
|
Let { level, idx } => LetVar { level, idx }.ir(),
|
||||||
SingleArg { level } => Arg { level }.ir(),
|
SingleArg { idx: level } => Arg { level }.ir(),
|
||||||
MultiArg { level, default } => Select {
|
MultiArg {
|
||||||
|
idx: level,
|
||||||
|
default,
|
||||||
|
} => Select {
|
||||||
expr: Arg { level }.ir().boxed(),
|
expr: Arg { level }.ir().boxed(),
|
||||||
attrpath: vec![Attr::Str(self.sym)],
|
attrpath: vec![Attr::Str(self.sym)],
|
||||||
default: default.map(Box::new),
|
default: default.map(Box::new),
|
||||||
@@ -1061,10 +1064,13 @@ impl Let {
|
|||||||
) -> Result<Ir> {
|
) -> Result<Ir> {
|
||||||
let map = self.bindings.clone();
|
let map = self.bindings.clone();
|
||||||
let mut env = env.enter_let(&map);
|
let mut env = env.enter_let(&map);
|
||||||
self.bindings.into_iter().map(|(_, ir)| {
|
self.bindings
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, ir)| {
|
||||||
ir.resolve(self_idx, ctx, &mut env)?;
|
ir.resolve(self_idx, ctx, &mut env)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}).collect::<Result<()>>()?;
|
})
|
||||||
|
.collect::<Result<()>>()?;
|
||||||
self.expr.resolve(self_idx, ctx, &env)?.ok()
|
self.expr.resolve(self_idx, ctx, &env)?.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ use super::Value;
|
|||||||
pub struct PartialFunc {
|
pub struct PartialFunc {
|
||||||
pub idx: usize,
|
pub idx: usize,
|
||||||
pub args: Vec<Value>,
|
pub args: Vec<Value>,
|
||||||
pub cache: HashMap<usize, Value>
|
pub cache: HashMap<usize, Value>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use super::common::*;
|
|||||||
use super::public as p;
|
use super::public as p;
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::env::{Env, VmEnvWeak};
|
use crate::env::Env;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
mod attrset;
|
mod attrset;
|
||||||
@@ -38,7 +38,7 @@ pub enum Value {
|
|||||||
PrimOp(Rc<PrimOp>),
|
PrimOp(Rc<PrimOp>),
|
||||||
PartialPrimOp(Rc<PartialPrimOp>),
|
PartialPrimOp(Rc<PartialPrimOp>),
|
||||||
Func(usize),
|
Func(usize),
|
||||||
PartialFunc(Rc<PartialFunc>)
|
PartialFunc(Rc<PartialFunc>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Value {
|
impl Hash for Value {
|
||||||
@@ -166,21 +166,30 @@ impl Value {
|
|||||||
PrimOp(func) => func.call(args, engine),
|
PrimOp(func) => func.call(args, engine),
|
||||||
PartialPrimOp(func) => func.call(args, engine),
|
PartialPrimOp(func) => func.call(args, engine),
|
||||||
PartialFunc(func) => {
|
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 idx = *idx;
|
||||||
let len = args.len() + old_args.len();
|
let len = args.len() + old_args.len();
|
||||||
env.reserve_args(len);
|
env.reserve_args(len);
|
||||||
env.enter_args(std::mem::take(old_args));
|
env.enter_args(std::mem::take(old_args));
|
||||||
let mut args = args.into_iter().peekable();
|
let mut args = args.into_iter().peekable();
|
||||||
env.enter_arg(args.next().unwrap());
|
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)?;
|
let mut ret = engine.eval_thunk(idx, env)?;
|
||||||
while args.peek().is_some() {
|
while args.peek().is_some() {
|
||||||
match ret {
|
match ret {
|
||||||
Value::Func(func) => {
|
Value::Func(func) => {
|
||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
|
engine.eval_func_deps(idx, env)?;
|
||||||
ret = engine.eval_thunk(func, env)?;
|
ret = engine.eval_thunk(func, env)?;
|
||||||
}
|
}
|
||||||
|
Value::PartialFunc(_) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
Value::PrimOp(primop) => {
|
Value::PrimOp(primop) => {
|
||||||
ret = primop.call(args.collect(), engine)?;
|
ret = primop.call(args.collect(), engine)?;
|
||||||
break;
|
break;
|
||||||
@@ -207,15 +216,21 @@ impl Value {
|
|||||||
let len = args.len();
|
let len = args.len();
|
||||||
let mut args = args.into_iter().peekable();
|
let mut args = args.into_iter().peekable();
|
||||||
env.reserve_args(len);
|
env.reserve_args(len);
|
||||||
let (ret, cache) = env.enter_cache_level(|env| {
|
|
||||||
let mut ret = engine.eval_thunk(idx, env)?;
|
|
||||||
env.enter_arg(args.next().unwrap());
|
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)?;
|
||||||
|
ret.force(engine, env)?;
|
||||||
while args.peek().is_some() {
|
while args.peek().is_some() {
|
||||||
match ret {
|
match ret {
|
||||||
Value::Func(func) => {
|
Value::Func(func) => {
|
||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
|
engine.eval_func_deps(idx, env)?;
|
||||||
ret = engine.eval_thunk(func, env)?;
|
ret = engine.eval_thunk(func, env)?;
|
||||||
}
|
}
|
||||||
|
Value::PartialFunc(mut func) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
Value::PrimOp(primop) => {
|
Value::PrimOp(primop) => {
|
||||||
ret = primop.call(args.collect(), engine)?;
|
ret = primop.call(args.collect(), engine)?;
|
||||||
break;
|
break;
|
||||||
@@ -481,7 +496,8 @@ impl Value {
|
|||||||
|
|
||||||
pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
|
pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
|
||||||
if let &mut Value::Thunk(idx) = 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)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user