feat: less clone, avoid evaluating not depended thunk
This commit is contained in:
@@ -39,7 +39,7 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
let expr = root.tree().expr().unwrap();
|
let expr = root.tree().expr().unwrap();
|
||||||
let downgraded = unwrap!(downgrade(expr));
|
let downgraded = unwrap!(downgrade(expr));
|
||||||
println!("{:?}", downgraded.graph);
|
println!("{:?}", downgraded);
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Interrupted) => {
|
Err(ReadlineError::Interrupted) => {
|
||||||
println!("CTRL-C");
|
println!("CTRL-C");
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ use std::rc::Rc;
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use priority_queue::PriorityQueue;
|
use priority_queue::PriorityQueue;
|
||||||
|
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::eval::Evaluate;
|
use crate::eval::Evaluate;
|
||||||
use crate::ir::{Dep, Downgraded, Ir, SccNode};
|
use crate::ir::{Dep, Downgraded, Ir, SccNode};
|
||||||
use crate::ty::internal::{self as i, ThunkRef};
|
use crate::ty::internal as i;
|
||||||
use crate::ty::public::Value;
|
use crate::ty::public::Value;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -43,38 +43,46 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(&mut self, graph: Vec<SccNode>) -> Result<Value> {
|
pub fn eval(&mut self, graph: Vec<SccNode>) -> Result<Value> {
|
||||||
let mut env = VmEnv::new();
|
let mut env = Env::new();
|
||||||
let last = graph.last().unwrap().members[0];
|
let last = graph.last().unwrap().members[0];
|
||||||
for SccNode { members, .. } in graph.into_iter() {
|
for SccNode { members, .. } in graph.into_iter() {
|
||||||
// TODO:
|
if members.len() == 1 {
|
||||||
assert!(members.len() == 1);
|
for member in members.into_iter() {
|
||||||
|
let val = self.thunks[member].clone().eval(self, &mut env)?;
|
||||||
|
env.insert_cache(member, val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
for member in members.into_iter() {
|
for member in members.into_iter() {
|
||||||
let val = self.thunks[member].clone().eval(self, &mut env)?;
|
let val = self.thunks[member].clone().eval(self, &mut env)?;
|
||||||
env.insert_cache(member, val);
|
env.insert_cache(member, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
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()))
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_thunk(&mut self, idx: usize, env: &mut VmEnv) -> Result<i::Value> {
|
pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
|
||||||
self.thunks[idx].clone().eval(self, env)
|
let self_mut = unsafe { &mut *(self as *mut Self) };
|
||||||
|
self.thunks[idx].eval(self_mut, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_func_deps(&mut self, idx: usize, env: &mut VmEnv) -> 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 self.func_deps[idx - self.func_offset].clone() {
|
||||||
match dep {
|
match dep {
|
||||||
Dep::Arg(idx) => {
|
Dep::Arg(idx) => {
|
||||||
if let i::Value::Thunk(ThunkRef { idx }) = env.lookup_arg(idx) {
|
if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
|
||||||
let val = self.thunks[idx].clone().eval(self, env)?;
|
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(idx, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Dep::Thunk(idx) => {
|
Dep::Thunk(idx) => {
|
||||||
let val = self.thunks[idx].clone().eval(self, env)?;
|
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(idx, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +94,7 @@ impl Engine {
|
|||||||
enum Thunk {
|
enum Thunk {
|
||||||
Expr(Ir),
|
Expr(Ir),
|
||||||
Compiling,
|
Compiling,
|
||||||
Compiled(fn(Rc<VmEnv>) -> Value),
|
Compiled(fn(Rc<Env>) -> Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Thunk {
|
impl Thunk {
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ 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") => thunk!()
|
symbol!("b") => int!(1)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
test_expr("{ a = 1; }.a", int!(1));
|
test_expr("{ a = 1; }.a", int!(1));
|
||||||
@@ -196,6 +196,7 @@ 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]
|
#[test]
|
||||||
|
|||||||
12
src/env.rs
12
src/env.rs
@@ -6,10 +6,10 @@ use hashbrown::HashMap;
|
|||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::stack::Stack;
|
use crate::stack::Stack;
|
||||||
use crate::ty::internal::{EnvRef, Value};
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct VmEnv {
|
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>>>,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
@@ -38,7 +38,7 @@ pub enum Type {
|
|||||||
With,
|
With,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VmEnv {
|
impl Env {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cache: Vec::from([HashMap::new()]),
|
cache: Vec::from([HashMap::new()]),
|
||||||
@@ -66,7 +66,7 @@ impl VmEnv {
|
|||||||
pub fn lookup_cache(
|
pub fn lookup_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
f: impl FnOnce(&mut VmEnv) -> Result<Value>,
|
f: impl FnOnce(&mut Env) -> Result<Value>,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
for level in self.cache.iter().rev() {
|
for level in self.cache.iter().rev() {
|
||||||
if let Some(ret) = level.get(&idx) {
|
if let Some(ret) = level.get(&idx) {
|
||||||
@@ -99,6 +99,10 @@ impl VmEnv {
|
|||||||
self.args.split_off(self.args.len() - len)
|
self.args.split_off(self.args.len() - len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reserve_args(&mut self, len: usize) {
|
||||||
|
self.args.reserve(len);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enter_args(&mut self, args: Vec<Value>) {
|
pub fn enter_args(&mut self, args: Vec<Value>) {
|
||||||
self.args.extend(args);
|
self.args.extend(args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,38 +4,204 @@ use crate::ir::*;
|
|||||||
use crate::ty::common as c;
|
use crate::ty::common as c;
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
use super::JITContext;
|
use super::{JITContext, ValueTag};
|
||||||
|
|
||||||
pub trait JITCompile {
|
pub trait JITCompile {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc>;
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Attrs {
|
impl JITCompile for Attrs {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for List {
|
impl JITCompile for List {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for HasAttr {
|
impl JITCompile for HasAttr {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
todo!()
|
use ValueTag::*;
|
||||||
|
use BinOpKind::*;
|
||||||
|
let lhs = self.lhs.compile(ctx, func);
|
||||||
|
let rhs = self.rhs.compile(ctx, func);
|
||||||
|
let lhs_tag = ctx.get_tag(lhs);
|
||||||
|
let rhs_tag = ctx.get_tag(rhs);
|
||||||
|
let tag = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_add(
|
||||||
|
lhs_tag.const_shl(ctx.helpers.const_int(8)),
|
||||||
|
rhs_tag,
|
||||||
|
"calc_tag",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let ret = ctx.context.append_basic_block(func, "fallback");
|
||||||
|
let res = ctx
|
||||||
|
.builder
|
||||||
|
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
||||||
|
.unwrap();
|
||||||
|
match self.kind {
|
||||||
|
Add => {
|
||||||
|
let int_int = ctx.context.append_basic_block(func, "int_int");
|
||||||
|
let int_float = ctx.context.append_basic_block(func, "int_float");
|
||||||
|
let float_int = ctx.context.append_basic_block(func, "float_int");
|
||||||
|
let float_float = ctx.context.append_basic_block(func, "float_float");
|
||||||
|
let fallback = ctx.context.append_basic_block(func, "fallback");
|
||||||
|
ctx.builder
|
||||||
|
.build_switch(
|
||||||
|
tag,
|
||||||
|
fallback,
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
ctx.helpers.const_int(((Int as i64) << 8) + Int as i64),
|
||||||
|
int_int,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ctx.helpers.const_int(((Int as i64) << 8) + Float as i64),
|
||||||
|
int_float,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ctx.helpers.const_int(((Float as i64) << 8) + Int as i64),
|
||||||
|
float_int,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ctx.helpers.const_int(((Float as i64) << 8) + Float as i64),
|
||||||
|
float_float,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(int_int);
|
||||||
|
let val = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add")
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_store(
|
||||||
|
res,
|
||||||
|
ctx.helpers.value_type.const_named_struct(&[
|
||||||
|
ctx.helpers.const_int(Int as i64).into(),
|
||||||
|
val.into(),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(int_float);
|
||||||
|
let val = ctx
|
||||||
|
.builder
|
||||||
|
.build_float_add(
|
||||||
|
ctx.builder
|
||||||
|
.build_signed_int_to_float(
|
||||||
|
ctx.get_int(lhs),
|
||||||
|
ctx.helpers.float_type,
|
||||||
|
"lhs_to_float",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
ctx.get_float(rhs),
|
||||||
|
"add",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_store(
|
||||||
|
res,
|
||||||
|
ctx.helpers.value_type.const_named_struct(&[
|
||||||
|
ctx.helpers.const_int(Float as i64).into(),
|
||||||
|
val.into(),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(float_int);
|
||||||
|
let val = ctx
|
||||||
|
.builder
|
||||||
|
.build_float_add(
|
||||||
|
ctx.get_float(lhs),
|
||||||
|
ctx.builder
|
||||||
|
.build_signed_int_to_float(
|
||||||
|
ctx.get_int(rhs),
|
||||||
|
ctx.helpers.float_type,
|
||||||
|
"rhs_to_float",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
"add",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_store(
|
||||||
|
res,
|
||||||
|
ctx.helpers.value_type.const_named_struct(&[
|
||||||
|
ctx.helpers.const_int(Float as i64).into(),
|
||||||
|
val.into(),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(int_int);
|
||||||
|
let val = ctx
|
||||||
|
.builder
|
||||||
|
.build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add")
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_store(
|
||||||
|
res,
|
||||||
|
ctx.helpers.value_type.const_named_struct(&[
|
||||||
|
ctx.helpers.const_int(Float as i64).into(),
|
||||||
|
val.into(),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(fallback);
|
||||||
|
}
|
||||||
|
Or => {
|
||||||
|
let bool_bool = ctx.context.append_basic_block(func, "int_int");
|
||||||
|
let fallback = ctx.context.append_basic_block(func, "fallback");
|
||||||
|
ctx.builder
|
||||||
|
.build_switch(
|
||||||
|
tag,
|
||||||
|
fallback,
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
|
||||||
|
bool_bool,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(bool_bool);
|
||||||
|
let val = ctx
|
||||||
|
.builder
|
||||||
|
.build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or")
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_store(
|
||||||
|
res,
|
||||||
|
ctx.helpers.value_type.const_named_struct(&[
|
||||||
|
ctx.helpers.const_int(Bool as i64).into(),
|
||||||
|
val.into(),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.position_at_end(fallback);
|
||||||
|
}
|
||||||
|
_ => todo!()
|
||||||
|
}
|
||||||
|
ctx.builder.position_at_end(ret);
|
||||||
|
ctx.builder
|
||||||
|
.build_load(ctx.helpers.value_type, res, "load_res")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for UnOp {
|
impl JITCompile for UnOp {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!();
|
todo!();
|
||||||
let rhs = self.rhs.compile(ctx, func);
|
let rhs = self.rhs.compile(ctx, func);
|
||||||
let tag = ctx.get_tag(rhs);
|
let tag = ctx.get_tag(rhs);
|
||||||
@@ -57,55 +223,55 @@ impl JITCompile for UnOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Select {
|
impl JITCompile for Select {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for If {
|
impl JITCompile for If {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for LoadFunc {
|
impl JITCompile for LoadFunc {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Call {
|
impl JITCompile for Call {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Let {
|
impl JITCompile for Let {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for With {
|
impl JITCompile for With {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Assert {
|
impl JITCompile for Assert {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for ConcatStrings {
|
impl JITCompile for ConcatStrings {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Const {
|
impl JITCompile for Const {
|
||||||
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 c::Const::*;
|
use c::Const::*;
|
||||||
match self.val {
|
match self.val {
|
||||||
Bool(x) => ctx.helpers.new_bool(x),
|
Bool(x) => ctx.helpers.new_bool(x),
|
||||||
@@ -117,37 +283,37 @@ impl JITCompile for Const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for String {
|
impl JITCompile for String {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Var {
|
impl JITCompile for Var {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Arg {
|
impl JITCompile for Arg {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for LetVar {
|
impl JITCompile for LetVar {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Thunk {
|
impl JITCompile for Thunk {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Path {
|
impl JITCompile for Path {
|
||||||
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ use inkwell::module::Module;
|
|||||||
use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType};
|
use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType};
|
||||||
use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue};
|
use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue};
|
||||||
|
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env;
|
||||||
use crate::eval::Engine;
|
use crate::eval::Engine;
|
||||||
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
use super::{JITContext, JITValue, JITValueData, ValueTag};
|
use super::{JITContext, JITValue, JITValueData, ValueTag};
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ impl<'ctx> Helpers<'ctx> {
|
|||||||
|
|
||||||
let new_thunk = module.add_function(
|
let new_thunk = module.add_function(
|
||||||
"new_thunk",
|
"new_thunk",
|
||||||
value_type.fn_type(&[ptr_type.into()], false),
|
value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let debug = module.add_function(
|
let debug = module.add_function(
|
||||||
@@ -102,7 +103,7 @@ 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(), value_type.into(), ptr_type.into()],
|
&[value_type.into(), ptr_type.into(), ptr_type.into(), ptr_type.into()],
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
@@ -234,11 +235,11 @@ extern "C" fn helper_debug(value: JITValue) {
|
|||||||
dbg!(value.tag);
|
dbg!(value.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_capture_env(thunk: JITValue, env: *const VmEnv) {
|
extern "C" fn helper_capture_env(thunk: JITValue, env: *const Env) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_neg(rhs: JITValue, _env: *const Env) -> JITValue {
|
||||||
use ValueTag::*;
|
use ValueTag::*;
|
||||||
match rhs.tag {
|
match rhs.tag {
|
||||||
Int => JITValue {
|
Int => JITValue {
|
||||||
@@ -257,7 +258,7 @@ extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_not(rhs: JITValue, _env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_not(rhs: JITValue, _env: *const Env) -> JITValue {
|
||||||
use ValueTag::*;
|
use ValueTag::*;
|
||||||
match rhs.tag {
|
match rhs.tag {
|
||||||
Bool => JITValue {
|
Bool => JITValue {
|
||||||
@@ -338,21 +339,22 @@ extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_call(func: JITValue, arg: JITValue, engine: *mut Engine) -> JITValue {
|
extern "C" fn helper_call(func: JITValue, args: Box<[JITValue]>, engine: NonNull<Engine>, env: NonNull<Env>) -> JITValue {
|
||||||
|
let func = Value::from(func);
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_arg(idx: usize, env: *const Env) -> JITValue {
|
||||||
let env = unsafe { env.as_ref() }.unwrap();
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
let val: JITValue = env.lookup_arg(idx).clone().into();
|
let val: JITValue = env.lookup_arg(idx).clone().into();
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const Env) -> JITValue {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_lookup(sym: usize, env: *const Env) -> JITValue {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ 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, AsValueRef, BasicMetadataValueEnum, BasicValueEnum, IntValue, StructValue,
|
AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env;
|
||||||
use crate::ir::{Ir, UnOpKind};
|
use crate::ir::Ir;
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
mod compile;
|
mod compile;
|
||||||
@@ -60,10 +60,10 @@ 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 { Rc::from_raw(value.data.ptr as *const _) }),
|
Function => Value::Func(unsafe { value.data.int as usize}),
|
||||||
Thunk => Value::Thunk(self::Thunk {
|
Thunk => Value::Thunk(unsafe {
|
||||||
thunk: unsafe { Rc::from_raw(value.data.ptr as *const _) },
|
value.data.int as usize
|
||||||
}), */
|
}),
|
||||||
_ => todo!("not implemented for {:?}", value.tag),
|
_ => todo!("not implemented for {:?}", value.tag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ impl From<Value> for JITValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>);
|
pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>);
|
||||||
type F = unsafe extern "C" fn(*const VmEnv) -> JITValue;
|
type F = unsafe extern "C" fn(*const Env) -> JITValue;
|
||||||
|
|
||||||
impl From<F> for JITFunc<'_> {
|
impl From<F> for JITFunc<'_> {
|
||||||
fn from(value: F) -> Self {
|
fn from(value: F) -> Self {
|
||||||
@@ -144,6 +144,60 @@ impl<'ctx> JITContext<'ctx> {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_float(&self, val: StructValue<'ctx>) -> FloatValue<'ctx> {
|
||||||
|
let alloca = self
|
||||||
|
.builder
|
||||||
|
.build_alloca(self.helpers.int_type, "get_value_alloca")
|
||||||
|
.unwrap();
|
||||||
|
self.builder.build_store(alloca, val).unwrap();
|
||||||
|
self.builder
|
||||||
|
.build_load(
|
||||||
|
self.helpers.float_type,
|
||||||
|
self.builder
|
||||||
|
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
|
||||||
|
.unwrap(),
|
||||||
|
"get_value",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.into_float_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_int(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
||||||
|
let alloca = self
|
||||||
|
.builder
|
||||||
|
.build_alloca(self.helpers.int_type, "get_value_alloca")
|
||||||
|
.unwrap();
|
||||||
|
self.builder.build_store(alloca, val).unwrap();
|
||||||
|
self.builder
|
||||||
|
.build_load(
|
||||||
|
self.helpers.int_type,
|
||||||
|
self.builder
|
||||||
|
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
|
||||||
|
.unwrap(),
|
||||||
|
"get_value",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.into_int_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bool(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
||||||
|
let alloca = self
|
||||||
|
.builder
|
||||||
|
.build_alloca(self.helpers.bool_type, "get_value_alloca")
|
||||||
|
.unwrap();
|
||||||
|
self.builder.build_store(alloca, val).unwrap();
|
||||||
|
self.builder
|
||||||
|
.build_load(
|
||||||
|
self.helpers.bool_type,
|
||||||
|
self.builder
|
||||||
|
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
|
||||||
|
.unwrap(),
|
||||||
|
"get_value",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.into_int_value()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
||||||
let alloca = self
|
let alloca = self
|
||||||
.builder
|
.builder
|
||||||
@@ -152,9 +206,9 @@ impl<'ctx> JITContext<'ctx> {
|
|||||||
self.builder.build_store(alloca, val).unwrap();
|
self.builder.build_store(alloca, val).unwrap();
|
||||||
self.builder
|
self.builder
|
||||||
.build_load(
|
.build_load(
|
||||||
self.context.bool_type(),
|
self.helpers.int_type,
|
||||||
self.builder
|
self.builder
|
||||||
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_tag_gep")
|
.build_struct_gep(self.helpers.value_type, alloca, 0, "get_tag_gep")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"get_tag",
|
"get_tag",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
use ecow::EcoVec;
|
use ecow::EcoVec;
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env;
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ir::{self, DynAttr};
|
use crate::ir::{self, DynAttr};
|
||||||
use crate::ty::common::Const;
|
use crate::ty::common::Const;
|
||||||
use crate::ty::internal::{AttrSet, EnvRef, List, ThunkRef, Value};
|
use crate::ty::internal::{AttrSet, List, Value};
|
||||||
use crate::ty::public::Symbol;
|
use crate::ty::public::Symbol;
|
||||||
|
|
||||||
pub mod jit;
|
pub mod jit;
|
||||||
|
|
||||||
pub trait Evaluate {
|
pub trait Evaluate {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value>;
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Attrs {
|
impl Evaluate for ir::Attrs {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let mut attrs = AttrSet::new(
|
let mut attrs = AttrSet::new(
|
||||||
self.stcs
|
self.stcs
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|(k, v)| Ok((k, v.eval(engine, env)?)))
|
.map(|(k, v)| Ok((k.clone(), v.eval(engine, env)?)))
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
);
|
);
|
||||||
for DynAttr(k, v) in self.dyns {
|
for DynAttr(k, v) in self.dyns.iter() {
|
||||||
let mut k = k.eval(engine, env)?;
|
let mut k = k.eval(engine, env)?;
|
||||||
k.force(engine, env)?.coerce_to_string();
|
k.coerce_to_string();
|
||||||
attrs.push_attr(k.unwrap_string(), v.eval(engine, env)?);
|
attrs.push_attr(k.unwrap_string(), v.eval(engine, env)?);
|
||||||
}
|
}
|
||||||
Value::AttrSet(attrs.into()).ok()
|
Value::AttrSet(attrs.into()).ok()
|
||||||
@@ -32,10 +32,10 @@ impl Evaluate for ir::Attrs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::List {
|
impl Evaluate for ir::List {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
Value::List(List::from(
|
Value::List(List::from(
|
||||||
self.items
|
self.items
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|val| val.eval(engine, env))
|
.map(|val| val.eval(engine, env))
|
||||||
.collect::<Result<EcoVec<_>>>()?,
|
.collect::<Result<EcoVec<_>>>()?,
|
||||||
))
|
))
|
||||||
@@ -44,16 +44,16 @@ impl Evaluate for ir::List {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::HasAttr {
|
impl Evaluate for ir::HasAttr {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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.into_iter().map(|attr| {
|
val.has_attr(self.rhs.iter().map(|attr| {
|
||||||
Ok(match attr {
|
Ok(match attr {
|
||||||
Str(ident) => ident,
|
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.force(engine, env)?.coerce_to_string();
|
val.coerce_to_string();
|
||||||
val.unwrap_string()
|
val.unwrap_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -63,12 +63,10 @@ impl Evaluate for ir::HasAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::BinOp {
|
impl Evaluate for ir::BinOp {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
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 => {
|
||||||
@@ -115,10 +113,9 @@ impl Evaluate for ir::BinOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::UnOp {
|
impl Evaluate for ir::UnOp {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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 => rhs.neg(),
|
||||||
Not => rhs.not(),
|
Not => rhs.not(),
|
||||||
@@ -128,19 +125,19 @@ impl Evaluate for ir::UnOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Select {
|
impl Evaluate for ir::Select {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
use ir::Attr::*;
|
use ir::Attr::*;
|
||||||
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.force(engine, env)?.select_with_default(
|
val.select_with_default(
|
||||||
self.attrpath.into_iter().map(|attr| {
|
self.attrpath.iter().map(|attr| {
|
||||||
Ok(match attr {
|
Ok(match attr {
|
||||||
Str(ident) => ident,
|
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.force(engine, env)?.coerce_to_string();
|
val.coerce_to_string();
|
||||||
val.unwrap_string()
|
val.unwrap_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -148,14 +145,14 @@ impl Evaluate for ir::Select {
|
|||||||
default,
|
default,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
val.force(engine, env)?
|
val
|
||||||
.select(self.attrpath.into_iter().map(|attr| {
|
.select(self.attrpath.iter().map(|attr| {
|
||||||
Ok(match attr {
|
Ok(match attr {
|
||||||
Str(ident) => ident,
|
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.force(engine, env)?.coerce_to_string();
|
val.coerce_to_string();
|
||||||
val.unwrap_string()
|
val.unwrap_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -166,7 +163,7 @@ impl Evaluate for ir::Select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::If {
|
impl Evaluate for ir::If {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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 cond = self.cond.eval(engine, env)?.unwrap_bool();
|
||||||
if cond {
|
if cond {
|
||||||
@@ -178,19 +175,18 @@ impl Evaluate for ir::If {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::LoadFunc {
|
impl Evaluate for ir::LoadFunc {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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()
|
Value::Func(idx).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Call {
|
impl Evaluate for ir::Call {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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.force(engine, env)?;
|
|
||||||
func.call(
|
func.call(
|
||||||
self.args
|
self.args
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|arg| arg.eval(engine, env))
|
.map(|arg| arg.eval(engine, env))
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
engine,
|
engine,
|
||||||
@@ -205,13 +201,13 @@ impl Evaluate for ir::Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Let {
|
impl Evaluate for ir::Let {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::With {
|
impl Evaluate for ir::With {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let namespace = self.namespace.eval(engine, env)?;
|
let namespace = self.namespace.eval(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());
|
||||||
@@ -222,19 +218,19 @@ impl Evaluate for ir::With {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Assert {
|
impl Evaluate for ir::Assert {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::ConcatStrings {
|
impl Evaluate for ir::ConcatStrings {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let mut parts = self
|
let mut parts = self
|
||||||
.parts
|
.parts
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|part| {
|
.map(|part| {
|
||||||
let mut part = part.eval(engine, env)?;
|
let mut part = part.eval(engine, env)?;
|
||||||
part.force(engine, env)?.coerce_to_string();
|
part.coerce_to_string();
|
||||||
part.ok()
|
part.ok()
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?
|
.collect::<Result<Vec<_>>>()?
|
||||||
@@ -250,13 +246,13 @@ impl Evaluate for ir::ConcatStrings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::String {
|
impl Evaluate for ir::String {
|
||||||
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
||||||
Value::String(self.val).ok()
|
Value::String(self.val.clone()).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Const {
|
impl Evaluate for ir::Const {
|
||||||
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
||||||
match self.val {
|
match self.val {
|
||||||
Const::Null => Value::Null,
|
Const::Null => Value::Null,
|
||||||
Const::Int(x) => Value::Int(x),
|
Const::Int(x) => Value::Int(x),
|
||||||
@@ -268,33 +264,34 @@ impl Evaluate for ir::Const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Var {
|
impl Evaluate for ir::Var {
|
||||||
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
env.lookup_with(&self.sym).ok_or_else(|| {
|
env.lookup_with(&self.sym).ok_or_else(|| {
|
||||||
Error::EvalError(format!("variable {} not found", Symbol::from(self.sym)))
|
Error::EvalError(format!("variable {} not found", Symbol::from(self.sym.clone())))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Arg {
|
impl Evaluate for ir::Arg {
|
||||||
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
env.lookup_arg(self.level).clone().ok()
|
env.lookup_arg(self.level).clone().ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::LetVar {
|
impl Evaluate for ir::LetVar {
|
||||||
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Thunk {
|
impl Evaluate for ir::Thunk {
|
||||||
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
Value::Thunk(ThunkRef::new(self.idx)).ok()
|
env.lookup_cache(self.idx, |env| engine.eval_thunk(self.idx, env))
|
||||||
|
// Value::Thunk(self.idx).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::MaybeThunk {
|
impl Evaluate for ir::MaybeThunk {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
match self {
|
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),
|
||||||
@@ -304,7 +301,7 @@ impl Evaluate for ir::MaybeThunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::Path {
|
impl Evaluate for ir::Path {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
|
|
||||||
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
|
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Unwrap)]
|
#[derive(Clone, Copy, Unwrap, Debug)]
|
||||||
pub enum Index {
|
pub enum Index {
|
||||||
Thunk(usize),
|
Thunk(usize),
|
||||||
Func(usize),
|
Func(usize),
|
||||||
@@ -169,9 +169,11 @@ 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)]
|
||||||
|
println!("{this:?} => {dep:?}");
|
||||||
match this {
|
match this {
|
||||||
Index::Thunk(idx) => {
|
Index::Thunk(idx) => {
|
||||||
if dep == Dep::Thunk(idx) {
|
if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {
|
||||||
return Err(Error::DowngradeError(
|
return Err(Error::DowngradeError(
|
||||||
"infinite recursion encountered".into(),
|
"infinite recursion encountered".into(),
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rnix::ast::{self, Expr};
|
|||||||
|
|
||||||
use crate::builtins::ir_env;
|
use crate::builtins::ir_env;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env as VmEnv;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::eval::Evaluate;
|
use crate::eval::Evaluate;
|
||||||
use crate::eval::jit::{JITCompile, JITContext};
|
use crate::eval::jit::{JITCompile, JITContext};
|
||||||
@@ -90,7 +90,7 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Ir {
|
impl JITCompile for Ir {
|
||||||
fn compile<'ctx>(self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{
|
fn compile<'ctx>(&self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{
|
||||||
match self {
|
match self {
|
||||||
$(Ir::$ty(ir) => ir.compile(ctx, func),)*
|
$(Ir::$ty(ir) => ir.compile(ctx, func),)*
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for Ir {
|
impl Evaluate for Ir {
|
||||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
$(Ir::$ty(ir) => ir.eval(engine, env),)*
|
$(Ir::$ty(ir) => ir.eval(engine, env),)*
|
||||||
}
|
}
|
||||||
@@ -1060,7 +1060,11 @@ impl Let {
|
|||||||
env: &Env<'a, 'env>,
|
env: &Env<'a, 'env>,
|
||||||
) -> Result<Ir> {
|
) -> Result<Ir> {
|
||||||
let map = self.bindings.clone();
|
let map = self.bindings.clone();
|
||||||
let env = env.enter_let(&map);
|
let mut env = env.enter_let(&map);
|
||||||
|
self.bindings.into_iter().map(|(_, ir)| {
|
||||||
|
ir.resolve(self_idx, ctx, &mut env)?;
|
||||||
|
Ok(())
|
||||||
|
}).collect::<Result<()>>()?;
|
||||||
self.expr.resolve(self_idx, ctx, &env)?.ok()
|
self.expr.resolve(self_idx, ctx, &env)?.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub enum Dep {
|
|||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct SccGraph {
|
pub struct SccGraph {
|
||||||
nodes: HashMap<usize, SccNode>,
|
nodes: HashMap<usize, SccNode>,
|
||||||
|
root: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SccGraph {
|
impl SccGraph {
|
||||||
@@ -38,6 +39,7 @@ impl SccGraph {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
graph.root = thunk_to_scc[&(ctx.thunks.len() - 1)];
|
||||||
|
|
||||||
for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() {
|
for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() {
|
||||||
let from_scc_id = thunk_to_scc[&from_node_id];
|
let from_scc_id = thunk_to_scc[&from_node_id];
|
||||||
@@ -58,28 +60,51 @@ impl SccGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sorted(self) -> Vec<SccNode> {
|
fn sorted(self) -> Vec<SccNode> {
|
||||||
let mut in_degrees: HashMap<usize, usize> = self.nodes.keys().map(|&id| (id, 0)).collect();
|
let mut reachable = HashSet::new();
|
||||||
for node in self.nodes.values() {
|
let mut stack = vec![self.root];
|
||||||
in_degrees.insert(node.id, node.deps.len());
|
reachable.insert(self.root);
|
||||||
|
|
||||||
|
while let Some(id) = stack.pop() {
|
||||||
|
if let Some(node) = self.nodes.get(&id) {
|
||||||
|
for &dep_id in &node.deps {
|
||||||
|
if reachable.insert(dep_id) {
|
||||||
|
stack.push(dep_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut in_degrees: HashMap<usize, usize> = HashMap::new();
|
||||||
let mut reverse_adj: HashMap<usize, Vec<usize>> = HashMap::new();
|
let mut reverse_adj: HashMap<usize, Vec<usize>> = HashMap::new();
|
||||||
for (node_id, node) in &self.nodes {
|
|
||||||
|
for &id in &reachable {
|
||||||
|
in_degrees.insert(id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for &id in &reachable {
|
||||||
|
if let Some(node) = self.nodes.get(&id) {
|
||||||
for &dep_id in &node.deps {
|
for &dep_id in &node.deps {
|
||||||
reverse_adj.entry(dep_id).or_default().push(*node_id);
|
if reachable.contains(&dep_id) {
|
||||||
|
reverse_adj.entry(dep_id).or_default().push(id);
|
||||||
|
*in_degrees.get_mut(&id).unwrap() += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut queue: std::collections::VecDeque<usize> = in_degrees
|
let mut queue: std::collections::VecDeque<usize> = in_degrees
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(&id, °)| if deg == 0 { Some(id) } else { None })
|
.filter(|(_, deg)| **deg == 0)
|
||||||
|
.map(|(&id, _)| id)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
queue.make_contiguous().sort();
|
queue.make_contiguous().sort();
|
||||||
|
|
||||||
let mut sorted_order = Vec::new();
|
let mut sorted_order = Vec::new();
|
||||||
while let Some(u) = queue.pop_front() {
|
while let Some(u) = queue.pop_front() {
|
||||||
sorted_order.push(self.nodes[&u].clone());
|
if let Some(node) = self.nodes.get(&u) {
|
||||||
|
sorted_order.push(node.clone());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(dependents) = reverse_adj.get(&u) {
|
if let Some(dependents) = reverse_adj.get(&u) {
|
||||||
for &v in dependents {
|
for &v in dependents {
|
||||||
@@ -93,8 +118,8 @@ impl SccGraph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sorted_order.len() != self.nodes.len() {
|
if sorted_order.len() != reachable.len() {
|
||||||
panic!("Cycle detected in SCC graph, which is impossible!");
|
panic!("Cycle detected in the reachable part of SCC graph!");
|
||||||
}
|
}
|
||||||
|
|
||||||
sorted_order
|
sorted_order
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env;
|
||||||
|
|
||||||
use crate::ir;
|
use crate::ir;
|
||||||
pub struct Func<'gc> {
|
pub struct Func<'gc> {
|
||||||
pub func: &'gc ir::Func,
|
pub func: &'gc ir::Func,
|
||||||
pub env: Rc<VmEnv>,
|
pub env: Rc<Env>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Func<'gc> {
|
impl<'gc> Func<'gc> {
|
||||||
pub fn new(func: &'gc ir::Func, env: Rc<VmEnv>) -> Self {
|
pub fn new(func: &'gc ir::Func, env: Rc<Env>) -> Self {
|
||||||
Self { func, env }
|
Self { func, env }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use ecow::EcoVec;
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::env::VmEnv;
|
use crate::env::Env;
|
||||||
use crate::ty::public as p;
|
use crate::ty::public as p;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|||||||
@@ -10,7 +10,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::{VmEnv, VmEnvWeak};
|
use crate::env::{Env, VmEnvWeak};
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
mod attrset;
|
mod attrset;
|
||||||
@@ -23,45 +23,6 @@ pub use attrset::*;
|
|||||||
pub use list::List;
|
pub use list::List;
|
||||||
pub use primop::*;
|
pub use primop::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum EnvRef {
|
|
||||||
Strong(VmEnv),
|
|
||||||
Weak(VmEnvWeak),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct ThunkRef {
|
|
||||||
pub idx: usize,
|
|
||||||
// pub env: Option<EnvRef>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ThunkRef {
|
|
||||||
pub fn new(idx: usize) -> Self {
|
|
||||||
ThunkRef {
|
|
||||||
idx, /* env: None */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
pub fn capture(&mut self, env: EnvRef) {
|
|
||||||
let _ = self.env.insert(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn upgrade(&mut self) {
|
|
||||||
replace_with_or_abort(&mut self.env, |env| {
|
|
||||||
env.map(|env| EnvRef::Strong(env.upgraded()))
|
|
||||||
});
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
impl EnvRef {
|
|
||||||
pub fn upgraded(self) -> VmEnv {
|
|
||||||
match self {
|
|
||||||
EnvRef::Weak(weak) => weak.upgrade(),
|
|
||||||
EnvRef::Strong(strong) => strong,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
#[derive(IsVariant, Unwrap, Clone, Debug)]
|
#[derive(IsVariant, Unwrap, Clone, Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
@@ -69,7 +30,7 @@ pub enum Value {
|
|||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(EcoString),
|
String(EcoString),
|
||||||
Null,
|
Null,
|
||||||
Thunk(ThunkRef),
|
Thunk(usize),
|
||||||
AttrSet(Rc<AttrSet>),
|
AttrSet(Rc<AttrSet>),
|
||||||
List(List),
|
List(List),
|
||||||
Catchable(EcoString),
|
Catchable(EcoString),
|
||||||
@@ -129,7 +90,7 @@ pub enum ValueAsRef<'v> {
|
|||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(&'v EcoString),
|
String(&'v EcoString),
|
||||||
Null,
|
Null,
|
||||||
Thunk(&'v ThunkRef),
|
Thunk(usize),
|
||||||
AttrSet(&'v AttrSet),
|
AttrSet(&'v AttrSet),
|
||||||
List(&'v List),
|
List(&'v List),
|
||||||
Catchable(&'v str),
|
Catchable(&'v str),
|
||||||
@@ -149,7 +110,7 @@ impl Value {
|
|||||||
Bool(x) => R::Bool(*x),
|
Bool(x) => R::Bool(*x),
|
||||||
String(x) => R::String(x),
|
String(x) => R::String(x),
|
||||||
Null => R::Null,
|
Null => R::Null,
|
||||||
Thunk(x) => R::Thunk(x),
|
Thunk(x) => R::Thunk(*x),
|
||||||
AttrSet(x) => R::AttrSet(x),
|
AttrSet(x) => R::AttrSet(x),
|
||||||
List(x) => R::List(x),
|
List(x) => R::List(x),
|
||||||
Catchable(x) => R::Catchable(x),
|
Catchable(x) => R::Catchable(x),
|
||||||
@@ -192,7 +153,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&mut self, args: Vec<Self>, engine: &mut Engine, env: &mut VmEnv) -> Result<()> {
|
pub fn call(&mut self, args: Vec<Self>, engine: &mut Engine, env: &mut Env) -> Result<()> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
if matches!(arg, Value::Catchable(_)) {
|
if matches!(arg, Value::Catchable(_)) {
|
||||||
@@ -206,6 +167,7 @@ impl Value {
|
|||||||
PartialFunc(idx, old) => {
|
PartialFunc(idx, old) => {
|
||||||
let idx = *idx;
|
let idx = *idx;
|
||||||
let len = args.len() + old.len();
|
let len = args.len() + old.len();
|
||||||
|
env.reserve_args(len);
|
||||||
env.enter_args(std::mem::take(old));
|
env.enter_args(std::mem::take(old));
|
||||||
env.enter_cache_level(|env| {
|
env.enter_cache_level(|env| {
|
||||||
let mut args = args.into_iter().peekable();
|
let mut args = args.into_iter().peekable();
|
||||||
@@ -240,6 +202,7 @@ impl Value {
|
|||||||
&mut Func(idx) => {
|
&mut Func(idx) => {
|
||||||
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.enter_cache_level(|env| {
|
env.enter_cache_level(|env| {
|
||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
let mut ret = engine.eval_thunk(idx, env)?;
|
let mut ret = engine.eval_thunk(idx, env)?;
|
||||||
@@ -510,18 +473,9 @@ impl Value {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn force(&mut self, engine: &mut Engine, env: &mut VmEnv) -> Result<&mut Self> {
|
pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
|
||||||
if let Value::Thunk(thunk) = self {
|
if let &mut Value::Thunk(idx) = self {
|
||||||
unsafe {
|
*self = env.lookup_cache(idx, |env| engine.eval_thunk(idx, env))?
|
||||||
let old = std::ptr::read(thunk);
|
|
||||||
match env.lookup_cache(old.idx, |env| engine.eval_thunk(old.idx, env)) {
|
|
||||||
Ok(ok) => std::ptr::write(self, ok),
|
|
||||||
Err(err) => {
|
|
||||||
std::ptr::write(self, Self::Null);
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user