feat: at least it compiles, right?

This commit is contained in:
2025-06-12 20:12:31 +08:00
parent 7293cb9f75
commit 49255948ff
22 changed files with 383 additions and 251 deletions

10
Cargo.lock generated
View File

@@ -267,6 +267,15 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "lru"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198"
dependencies = [
"hashbrown 0.15.3",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@@ -312,6 +321,7 @@ dependencies = [
"hashbrown 0.15.3", "hashbrown 0.15.3",
"inkwell", "inkwell",
"itertools", "itertools",
"lru",
"priority-queue", "priority-queue",
"regex", "regex",
"replace_with", "replace_with",

View File

@@ -28,6 +28,7 @@ ecow = "0.2"
regex = "1.11" regex = "1.11"
hashbrown = "0.15" hashbrown = "0.15"
priority-queue = "2.5" priority-queue = "2.5"
lru = "0.14"
replace_with = "0.1" replace_with = "0.1"
inkwell = { version = "0.6.0", features = ["llvm18-1"] } inkwell = { version = "0.6.0", features = ["llvm18-1"] }

View File

@@ -2,10 +2,10 @@ use std::process::exit;
use itertools::Itertools; use itertools::Itertools;
use nixjit::engine::eval;
use nixjit::error::Error; use nixjit::error::Error;
use nixjit::error::Result; use nixjit::error::Result;
use nixjit::ir::downgrade; use nixjit::ir::downgrade;
use nixjit::engine::eval;
fn main() -> Result<()> { fn main() -> Result<()> {
let mut args = std::env::args(); let mut args = std::env::args();

View File

@@ -1,7 +1,7 @@
use ecow::EcoString; use ecow::EcoString;
use hashbrown::HashMap; use hashbrown::HashMap;
use crate::ir::{DowngradeContext, Ir, Const}; use crate::ir::{Const, DowngradeContext, Ir};
pub fn ir_env(ctx: &mut DowngradeContext) -> HashMap<EcoString, Ir> { pub fn ir_env(ctx: &mut DowngradeContext) -> HashMap<EcoString, Ir> {
let mut map = HashMap::new(); let mut map = HashMap::new();

View File

@@ -1,52 +1,63 @@
use std::sync::RwLock;
use std::rc::Rc; use std::rc::Rc;
use hashbrown::HashSet; use hashbrown::HashSet;
use lru::LruCache;
use priority_queue::PriorityQueue; use priority_queue::PriorityQueue;
use crate::env::VmEnv; use crate::env::VmEnv;
use crate::error::Result;
use crate::eval::Evaluate; use crate::eval::Evaluate;
use crate::ir::{Downgraded, Ir}; use crate::ir::{Downgraded, Ir};
use crate::ty::public::Value;
use crate::ty::internal as i; use crate::ty::internal as i;
use crate::error::Result; use crate::ty::public::Value;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
type ThunkIdx = usize;
type EnvIdx = usize;
pub struct Engine { pub struct Engine {
thunks: Box<[RwLock<Thunk>]>, thunks: Box<[Ir]>,
func_offset: usize, pub func_offset: usize,
tasks: PriorityQueue<CompileTask, usize> tasks: PriorityQueue<CompileTask, usize>,
lru: LruCache<(ThunkIdx, EnvIdx), i::Value>,
} }
pub fn eval(downgraded: Downgraded) -> Result<Value> { pub fn eval(downgraded: Downgraded) -> Result<Value> {
let mut engine = Engine::new(downgraded.thunks, downgraded.func_offset); let mut engine = Engine::new(downgraded.thunks, downgraded.func_offset);
engine.eval(downgraded.top_level, &VmEnv::new(vec![])).map(|mut val| Ok(val.force(&engine)?.to_public(&engine, &mut HashSet::new())))? engine
.eval(downgraded.top_level, &mut VmEnv::new())
.map(|mut val| {
Ok(val
.force(&mut engine)?
.to_public(&engine, &mut HashSet::new()))
})?
} }
impl Engine { impl Engine {
pub fn new(thunks: Box<[Ir]>, func_offset: usize) -> Self { pub fn new(thunks: Box<[Ir]>, func_offset: usize) -> Self {
Self { Self {
thunks: thunks.into_iter().map(Thunk::new).map(RwLock::new).collect(), lru: LruCache::new(thunks.len().clamp(1, usize::MAX).try_into().unwrap()),
thunks,
func_offset, func_offset,
tasks: PriorityQueue::new() tasks: PriorityQueue::new(),
} }
} }
pub fn eval(&mut self, expr: Ir, env: &VmEnv) -> Result<i::Value> { pub fn eval(&mut self, expr: Ir, env: &mut VmEnv) -> Result<i::Value> {
expr.eval(self, env) expr.eval(self, env)
} }
pub fn eval_thunk(&self, idx: usize, env: &VmEnv) -> Result<i::Value> { pub fn eval_thunk(&mut self, idx: usize, env: &mut VmEnv) -> Result<i::Value> {
todo!() self.thunks[idx].clone().eval(self, env)
} }
} }
enum Thunk { enum Thunk {
Expr(Ir), Expr(Ir),
Compiling, Compiling,
Compiled(fn(Rc<VmEnv>) -> Value) Compiled(fn(Rc<VmEnv>) -> Value),
} }
impl Thunk { impl Thunk {
@@ -57,5 +68,5 @@ impl Thunk {
#[derive(Hash, PartialEq, Eq)] #[derive(Hash, PartialEq, Eq)]
struct CompileTask { struct CompileTask {
idx: usize idx: usize,
} }

View File

@@ -221,4 +221,3 @@ fn bench_fib(b: &mut Bencher) {
black_box(()) black_box(())
}) })
} }

View File

@@ -1,33 +1,34 @@
use std::hash::Hash; use std::cell::RefCell;
use std::rc::Rc; use std::rc::{Rc, Weak};
use ecow::EcoString; use ecow::EcoString;
use hashbrown::HashMap; use hashbrown::HashMap;
use crate::ty::internal::Value; use crate::stack::Stack;
use crate::ty::internal::{EnvRef, Value};
pub struct Env<K: Hash + Eq, V> { #[derive(Clone)]
let_: Rc<LetEnv<V>>, pub struct VmEnv {
with: Rc<With<K, V>>, let_: Rc<RefCell<Stack<Vec<Value>, 1000>>>,
args: Rc<Vec<V>>, with: Rc<With>,
args: Rc<RefCell<Stack<Value, 1000>>>,
new: bool,
pub id: usize,
} }
pub struct LetEnv<V> { #[derive(Clone)]
map: Vec<V>, pub struct VmEnvWeak {
last: Option<Rc<LetEnv<V>>>, let_: Weak<RefCell<Stack<Vec<Value>, 1000>>>,
with: Weak<With>,
args: Weak<RefCell<Stack<Value, 1000>>>,
new: bool,
pub id: usize,
} }
pub type VmEnv = Env<EcoString, Value>;
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct With<K: Hash + Eq, V> { pub struct With {
map: Option<Rc<HashMap<K, V>>>, map: Option<Rc<HashMap<EcoString, Value>>>,
last: Option<Rc<With<K, V>>>, last: Option<Rc<With>>,
}
enum LetNode<K: Hash + Eq, V> {
Let(Rc<HashMap<K, V>>),
MultiArg(Rc<HashMap<K, V>>),
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@@ -37,27 +38,30 @@ pub enum Type {
With, With,
} }
impl<K: Hash + Eq + Clone, V: Clone> Env<K, V> { impl VmEnv {
pub fn new(map: Vec<V>) -> Self { pub fn new() -> Self {
Self { Self {
let_: LetEnv::new(map), let_: Rc::default(),
with: With { with: With {
map: None, map: None,
last: None, last: None,
}.into(), }
args: Vec::new().into(), .into(),
args: Rc::default(),
new: false,
id: 0,
} }
} }
pub fn lookup_arg(&self, level: usize) -> &V { pub fn lookup_let(&self, level: usize, idx: usize) -> Value {
&self.args[self.args.len() - level - 1] self.let_.borrow()[level][idx].clone()
} }
pub fn lookup_let(&self, level: usize, idx: usize) -> &V { pub fn lookup_arg(&self, level: usize) -> Value {
self.let_.lookup(level, idx) self.args.borrow()[level].clone()
} }
pub fn lookup_with(&self, symbol: &K) -> Option<&V> { pub fn lookup_with(&self, symbol: &EcoString) -> Option<Value> {
self.with.lookup(symbol) self.with.lookup(symbol)
} }
@@ -65,69 +69,103 @@ impl<K: Hash + Eq + Clone, V: Clone> Env<K, V> {
self.with.map.is_some() self.with.map.is_some()
} }
#[must_use] pub fn enter_let(&mut self, mut map: Vec<Value>) {
pub fn enter_arg(&self, val: V) -> Self { if Rc::strong_count(&self.let_) > 1 {
let mut args = self.args.clone(); self.let_ = Rc::new_cyclic(|weak| {
Rc::make_mut(&mut args).push(val); let weak = VmEnvWeak {
Self { let_: weak.clone(),
let_: self.let_.clone(), with: Rc::downgrade(&self.with),
with: self.with.clone(), args: Rc::downgrade(&self.args),
args, new: self.new,
id: self.id,
};
map.iter_mut().for_each(|val| {
if let Value::Thunk(thunk) = val {
thunk.capture(EnvRef::Weak(weak.clone()));
}
});
let new = self.let_.as_ref().clone();
new.borrow_mut().push(map).unwrap();
new
})
} else {
let weak = self.downgrade();
map.iter_mut().for_each(|val| {
if let Value::Thunk(thunk) = val {
thunk.capture(EnvRef::Weak(weak.clone()));
}
});
let _ = self.let_.borrow_mut().push(map);
} }
} }
#[must_use] pub fn enter_arg(&mut self, val: Value) {
pub fn enter_let(&self, map: Vec<V>) -> Self { if Rc::strong_count(&self.args) > 1 {
Self { self.args = Rc::new(self.args.as_ref().clone());
let_: self.let_.clone().enter_let(map),
with: self.with.clone(),
args: self.args.clone(),
} }
self.args.borrow_mut().push(val).unwrap()
}
pub fn pop_let(&mut self) {
if Rc::strong_count(&self.let_) > 1 {
self.let_ = Rc::new(self.let_.as_ref().clone());
}
self.let_.borrow_mut().pop();
}
pub fn pop_arg(&mut self) {
if Rc::strong_count(&self.args) > 1 {
self.args = Rc::new(self.args.as_ref().clone());
}
self.args.borrow_mut().pop();
} }
#[must_use] #[must_use]
pub fn enter_with(&self, map: Rc<HashMap<K, V>>) -> Self { pub fn enter_with(&self, map: Rc<HashMap<EcoString, Value>>) -> Self {
Self { Self {
let_: self.let_.clone(), let_: self.let_.clone(),
with: self.with.clone().enter(map), with: self.with.clone().enter(map),
args: self.args.clone(), args: self.args.clone(),
new: self.new,
id: self.id + 1,
}
}
pub fn downgrade(&self) -> VmEnvWeak {
VmEnvWeak {
let_: Rc::downgrade(&self.let_),
with: Rc::downgrade(&self.with),
args: Rc::downgrade(&self.args),
id: self.id,
new: self.new,
} }
} }
} }
impl<V: Clone> LetEnv<V> { impl With {
pub fn new(map: Vec<V>) -> Rc<Self> { pub fn lookup(&self, symbol: &EcoString) -> Option<Value> {
Rc::new(Self { map, last: None })
}
pub fn lookup(&self, level: usize, idx: usize) -> &V {
let mut cur = self;
for _ in 0..level {
cur = cur.last.as_ref().unwrap();
}
&cur.map[idx]
}
pub fn enter_let(self: Rc<Self>, map: Vec<V>) -> Rc<Self> {
Rc::new(Self {
map,
last: Some(self),
})
}
}
impl<K: Hash + Eq + Clone, V: Clone> With<K, V> {
pub fn lookup(&self, symbol: &K) -> Option<&V> {
if let Some(val) = self.map.as_ref()?.get(symbol) { if let Some(val) = self.map.as_ref()?.get(symbol) {
return Some(val); return Some(val.clone());
} }
self.last.as_ref().and_then(|env| env.lookup(symbol)) self.last.as_ref().and_then(|env| env.lookup(symbol))
} }
pub fn enter(self: Rc<Self>, map: Rc<HashMap<K, V>>) -> Rc<Self> { pub fn enter(self: Rc<Self>, map: Rc<HashMap<EcoString, Value>>) -> Rc<Self> {
Rc::new(Self { Rc::new(Self {
map: Some(map), map: Some(map),
last: Some(self), last: Some(self),
}) })
} }
} }
impl VmEnvWeak {
pub fn upgrade(&self) -> VmEnv {
VmEnv {
let_: self.let_.upgrade().unwrap(),
with: self.with.upgrade().unwrap(),
args: self.args.upgrade().unwrap(),
id: self.id,
new: self.new,
}
}
}

View File

@@ -14,7 +14,7 @@ impl JITCompile for Attrs {
} }
} }
impl JITCompile for List { impl JITCompile for List {
fn compile<'gc>(self, ctx: &JITContext<'gc>) { fn compile<'gc>(self, ctx: &JITContext<'gc>) {
todo!() todo!()
} }
@@ -32,7 +32,7 @@ impl JITCompile for BinOp {
} }
} }
impl JITCompile for UnOp { impl JITCompile for UnOp {
fn compile<'gc>(self, ctx: &JITContext<'gc>) { fn compile<'gc>(self, ctx: &JITContext<'gc>) {
todo!() todo!()
} }
@@ -91,13 +91,13 @@ impl JITCompile for Const {
todo!() todo!()
} }
} }
impl JITCompile for String { impl JITCompile for String {
fn compile<'gc>(self, ctx: &JITContext<'gc>) { fn compile<'gc>(self, ctx: &JITContext<'gc>) {
todo!() todo!()
} }
} }
impl JITCompile for Var { impl JITCompile for Var {
fn compile<'gc>(self, ctx: &JITContext<'gc>) { fn compile<'gc>(self, ctx: &JITContext<'gc>) {
todo!() todo!()
@@ -124,6 +124,6 @@ impl JITCompile for Thunk {
impl JITCompile for Path { impl JITCompile for Path {
fn compile<'gc>(self, ctx: &JITContext<'gc>) { fn compile<'gc>(self, ctx: &JITContext<'gc>) {
todo!() todo!()
} }
} }

View File

@@ -10,7 +10,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue};
use crate::env::VmEnv; use crate::env::VmEnv;
use crate::eval::Engine; use crate::eval::Engine;
use super::{JITContext, JITValue, ValueTag, JITValueData}; use super::{JITContext, JITValue, JITValueData, ValueTag};
pub struct Helpers<'ctx> { pub struct Helpers<'ctx> {
pub int_type: IntType<'ctx>, pub int_type: IntType<'ctx>,
@@ -341,9 +341,7 @@ extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
} }
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 VmEnv) -> JITValue {
let env = unsafe { env.as_ref() }.unwrap(); todo!()
let val: JITValue = env.lookup_let(level, idx).clone().into();
val
} }
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue { extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {

View File

@@ -1,5 +1,5 @@
use std::ops::Deref;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Deref;
use inkwell::OptimizationLevel; use inkwell::OptimizationLevel;
use inkwell::builder::Builder; use inkwell::builder::Builder;
@@ -10,8 +10,8 @@ use inkwell::module::Module;
use crate::env::VmEnv; use crate::env::VmEnv;
use crate::ty::internal::Value; use crate::ty::internal::Value;
mod helpers;
mod compile; mod compile;
mod helpers;
pub use compile::JITCompile; pub use compile::JITCompile;
use helpers::Helpers; use helpers::Helpers;
@@ -105,7 +105,6 @@ impl Deref for JITFunc<'_> {
} }
} }
pub struct JITContext<'ctx> { pub struct JITContext<'ctx> {
context: &'ctx Context, context: &'ctx Context,
module: Module<'ctx>, module: Module<'ctx>,

View File

@@ -8,8 +8,8 @@ use inkwell::context::Context;
use ecow::EcoString; use ecow::EcoString;
use crate::ir::downgrade;
use super::JITContext; use super::JITContext;
use crate::ir::downgrade;
use crate::ty::common::Const; use crate::ty::common::Const;
use crate::ty::public::*; use crate::ty::public::*;

View File

@@ -7,26 +7,34 @@ use crate::env::VmEnv;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::ir::{self, DynamicAttrPair}; use crate::ir::{self, DynamicAttrPair};
use crate::ty::common::Const; use crate::ty::common::Const;
use crate::ty::internal::{AttrSet, List, Thunk, ThunkRef, Value}; use crate::ty::internal::{AttrSet, EnvRef, List, ThunkRef, 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: &Engine, env: &VmEnv) -> Result<Value>; fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value>;
} }
impl Evaluate for ir::Attrs { impl Evaluate for ir::Attrs {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
let mut attrs = AttrSet::new( let mut attrs = AttrSet::new(
self.stcs self.stcs
.into_iter() .into_iter()
.map(|(k, v)| Ok((k, v.eval(engine, env)?))) .map(|(k, v)| {
Ok((k, {
let mut val = v.eval(engine, env)?;
if let Value::Thunk(thunk) = &mut val {
thunk.capture(EnvRef::Strong(env.clone()));
}
val
}))
})
.collect::<Result<_>>()?, .collect::<Result<_>>()?,
); );
for DynamicAttrPair(k, v) in self.dyns { for DynamicAttrPair(k, v) in self.dyns {
let mut k = k.eval(engine, env)?; let mut k = k.eval(engine, env)?;
k.coerce_to_string(); k.force(engine)?.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()
@@ -34,11 +42,17 @@ impl Evaluate for ir::Attrs {
} }
impl Evaluate for ir::List { impl Evaluate for ir::List {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
Value::List(List::from( Value::List(List::from(
self.items self.items
.into_iter() .into_iter()
.map(|val| val.eval(engine, env)) .map(|val| {
let mut val = val.eval(engine, env)?;
if let Value::Thunk(thunk) = &mut val {
thunk.capture(EnvRef::Strong(env.clone()));
}
val.ok()
})
.collect::<Result<EcoVec<_>>>()?, .collect::<Result<EcoVec<_>>>()?,
)) ))
.ok() .ok()
@@ -46,7 +60,7 @@ impl Evaluate for ir::List {
} }
impl Evaluate for ir::HasAttr { impl Evaluate for ir::HasAttr {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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.into_iter().map(|attr| {
@@ -55,7 +69,7 @@ impl Evaluate for ir::HasAttr {
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)?.coerce_to_string();
val.unwrap_string() val.unwrap_string()
} }
}) })
@@ -65,10 +79,12 @@ impl Evaluate for ir::HasAttr {
} }
impl Evaluate for ir::BinOp { impl Evaluate for ir::BinOp {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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)?;
rhs.force(engine)?;
match self.kind { match self.kind {
Add => lhs.add(rhs), Add => lhs.add(rhs),
Sub => { Sub => {
@@ -115,9 +131,10 @@ impl Evaluate for ir::BinOp {
} }
impl Evaluate for ir::UnOp { impl Evaluate for ir::UnOp {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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)?;
match self.kind { match self.kind {
Neg => rhs.neg(), Neg => rhs.neg(),
Not => rhs.not(), Not => rhs.not(),
@@ -127,43 +144,45 @@ impl Evaluate for ir::UnOp {
} }
impl Evaluate for ir::Select { impl Evaluate for ir::Select {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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 {
val.select_with_default( let default = default.eval(engine, env)?;
val.force(engine)?.select_with_default(
self.attrpath.into_iter().map(|attr| { self.attrpath.into_iter().map(|attr| {
Ok(match attr { Ok(match attr {
Str(ident) => ident, Str(ident) => ident,
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)?.coerce_to_string();
val.unwrap_string() val.unwrap_string()
} }
}) })
}), }),
default.eval(engine, env)?, default,
)?; )?;
} else { } else {
val.select(self.attrpath.into_iter().map(|attr| { val.force(engine)?
Ok(match attr { .select(self.attrpath.into_iter().map(|attr| {
Str(ident) => ident, Ok(match attr {
Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Str(ident) => ident,
Dynamic(expr) => { Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
let mut val = expr.eval(engine, env)?; Dynamic(expr) => {
val.coerce_to_string(); let mut val = expr.eval(engine, env)?;
val.unwrap_string() val.force(engine)?.coerce_to_string();
} val.unwrap_string()
}) }
}))?; })
}))?;
} }
val.ok() val.ok()
} }
} }
impl Evaluate for ir::If { impl Evaluate for ir::If {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> 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 {
@@ -175,14 +194,19 @@ impl Evaluate for ir::If {
} }
impl Evaluate for ir::LoadFunc { impl Evaluate for ir::LoadFunc {
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
Value::Func(Rc::new(ThunkRef::new(self.idx).into())).ok() Value::Func(ThunkRef {
idx: engine.func_offset + self.idx,
env: Some(EnvRef::Strong(env.clone())).into(),
})
.ok()
} }
} }
impl Evaluate for ir::Call { impl Evaluate for ir::Call {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
let mut func = self.func.eval(engine, env)?; let mut func = self.func.eval(engine, env)?;
func.force(engine)?;
// FIXME: Modify Value::call // FIXME: Modify Value::call
for arg in self.args { for arg in self.args {
func.call(arg.eval(engine, env)?, engine)?; func.call(arg.eval(engine, env)?, engine)?;
@@ -192,34 +216,44 @@ impl Evaluate for ir::Call {
} }
impl Evaluate for ir::Let { impl Evaluate for ir::Let {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
let bindings = self.bindings.into_iter().map(|(_, v)| Ok(v.eval(engine, env)?)).collect::<Result<Vec<_>>>()?; let bindings = self
self.expr.eval(engine, &env.enter_let(bindings)) .bindings
.into_iter()
.map(|(_, v)| v.eval(engine, env))
.collect::<Result<Vec<_>>>()?;
env.enter_let(bindings);
let val = self.expr.eval(engine, env)?;
env.pop_let();
Ok(val)
} }
} }
impl Evaluate for ir::With { impl Evaluate for ir::With {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
let namespace = self.namespace.eval(engine, env)?; let namespace = self.namespace.eval(engine, env)?;
// TODO: Error Handling // TODO: Error Handling
self.expr.eval(engine, &env.enter_with(namespace.unwrap_attr_set().into_inner())) self.expr.eval(
engine,
&mut env.enter_with(namespace.unwrap_attr_set().into_inner()),
)
} }
} }
impl Evaluate for ir::Assert { impl Evaluate for ir::Assert {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
todo!() todo!()
} }
} }
impl Evaluate for ir::ConcatStrings { impl Evaluate for ir::ConcatStrings {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
let mut parts = self let mut parts = self
.parts .parts
.into_iter() .into_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)?.coerce_to_string();
part.ok() part.ok()
}) })
.collect::<Result<Vec<_>>>()? .collect::<Result<Vec<_>>>()?
@@ -235,13 +269,13 @@ impl Evaluate for ir::ConcatStrings {
} }
impl Evaluate for ir::String { impl Evaluate for ir::String {
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> { fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
Value::String(self.val).ok() Value::String(self.val).ok()
} }
} }
impl Evaluate for ir::Const { impl Evaluate for ir::Const {
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> { fn eval(self, _: &mut Engine, _: &mut VmEnv) -> 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),
@@ -253,33 +287,36 @@ impl Evaluate for ir::Const {
} }
impl Evaluate for ir::Var { impl Evaluate for ir::Var {
fn eval(self, _: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> {
env.lookup_with(&self.sym) env.lookup_with(&self.sym)
.cloned()
.ok_or_else(|| Error::EvalError(format!("{} not found", Symbol::from(self.sym)))) .ok_or_else(|| Error::EvalError(format!("{} not found", Symbol::from(self.sym))))
} }
} }
impl Evaluate for ir::Arg { impl Evaluate for ir::Arg {
fn eval(self, _: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, _: &mut Engine, env: &mut VmEnv) -> 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, _: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> {
env.lookup_let(self.level, self.idx).clone().ok() let mut ret = env.lookup_let(self.level, self.idx);
if let Value::Thunk(thunk) = &mut ret {
thunk.upgrade();
}
ret.ok()
} }
} }
impl Evaluate for ir::Thunk { impl Evaluate for ir::Thunk {
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> { fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
Value::Thunk(Rc::new(Thunk::new(self.idx).into())).ok() Value::Thunk(ThunkRef::new(self.idx)).ok()
} }
} }
impl Evaluate for ir::Path { impl Evaluate for ir::Path {
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> { fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
todo!() todo!()
} }
} }

View File

@@ -99,7 +99,7 @@ macro_rules! ir {
} }
impl Evaluate for Ir { impl Evaluate for Ir {
fn eval(self, engine: &Engine, env: &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),)*
} }
@@ -182,6 +182,8 @@ pub struct DowngradeContext {
struct Env<'a, 'env> { struct Env<'a, 'env> {
env: EnvNode<'a>, env: EnvNode<'a>,
prev: Option<&'env Env<'a, 'env>>, prev: Option<&'env Env<'a, 'env>>,
arg_level: usize,
let_level: usize
} }
enum EnvNode<'a> { enum EnvNode<'a> {
@@ -205,6 +207,8 @@ impl<'a, 'env> Env<'a, 'env> {
Self { Self {
env: EnvNode::Builtins(base), env: EnvNode::Builtins(base),
prev: None, prev: None,
arg_level: 0,
let_level: 0
} }
} }
@@ -212,6 +216,8 @@ impl<'a, 'env> Env<'a, 'env> {
Self { Self {
env: EnvNode::Let(map), env: EnvNode::Let(map),
prev: Some(self), prev: Some(self),
arg_level: self.arg_level,
let_level: self.let_level + 1
} }
} }
@@ -219,6 +225,8 @@ impl<'a, 'env> Env<'a, 'env> {
Self { Self {
env: EnvNode::SingleArg(ident), env: EnvNode::SingleArg(ident),
prev: Some(self), prev: Some(self),
arg_level: self.arg_level + 1,
let_level: self.let_level
} }
} }
@@ -230,6 +238,8 @@ impl<'a, 'env> Env<'a, 'env> {
Self { Self {
env: EnvNode::MultiArg(map, alias), env: EnvNode::MultiArg(map, alias),
prev: Some(self), prev: Some(self),
arg_level: self.arg_level + 1,
let_level: 0
} }
} }
@@ -237,6 +247,8 @@ impl<'a, 'env> Env<'a, 'env> {
Self { Self {
env: EnvNode::With, env: EnvNode::With,
prev: Some(self), prev: Some(self),
arg_level: self.arg_level,
let_level: self.let_level
} }
} }
@@ -262,30 +274,30 @@ impl<'a, 'env> Env<'a, 'env> {
Let(map) => { Let(map) => {
if let Ok(idx) = map.binary_search(ident) { if let Ok(idx) = map.binary_search(ident) {
return Ok(LookupResult::Let { return Ok(LookupResult::Let {
level: let_level, level: let_level - 1,
idx, idx,
}); });
} else { } else {
let_level += 1; let_level -= 1;
} }
} }
SingleArg(arg) => { SingleArg(arg) => {
if arg == ident { if arg == ident {
return Ok(LookupResult::SingleArg { level: arg_level }); return Ok(LookupResult::SingleArg { level: arg_level - 1 });
} else { } else {
arg_level += 1; arg_level -= 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, level: arg_level - 1,
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 { level: arg_level - 1 });
} else { } else {
arg_level += 1; arg_level -= 1;
} }
} }
With => has_with = true, With => has_with = true,
@@ -296,7 +308,7 @@ impl<'a, 'env> Env<'a, 'env> {
} }
fn lookup(&self, ident: &EcoString) -> core::result::Result<LookupResult, ()> { fn lookup(&self, ident: &EcoString) -> core::result::Result<LookupResult, ()> {
self._lookup(ident, 0, 0, false) self._lookup(ident, self.arg_level, self.let_level, false)
} }
} }
@@ -367,30 +379,25 @@ impl Attrs {
) -> Result<()> { ) -> Result<()> {
if let Some(attr) = path.next() { if let Some(attr) = path.next() {
match attr { match attr {
Attr::Str(ident) => { Attr::Str(ident) => self
if self.stcs.get(&ident).is_some() { .stcs
self.stcs .entry(ident.clone())
.get_mut(&ident) .or_insert_with(|| {
.unwrap() Attrs {
.as_mut()
.try_unwrap_attrs()
.map_err(|_| {
Error::DowngradeError(format!(
r#"attribute '{}' already defined"#,
Symbol::from(ident)
))
})
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value, ctx))
} else {
let mut attrs = Attrs {
stcs: HashMap::new(), stcs: HashMap::new(),
dyns: Vec::new(), dyns: Vec::new(),
}; }
attrs._insert(path, name, value, ctx)?; .ir()
assert!(self.stcs.insert(ident, attrs.ir()).is_none()); })
Ok(()) .as_mut()
} .try_unwrap_attrs()
} .map_err(|_| {
Error::DowngradeError(format!(
r#"attribute '{}' already defined"#,
Symbol::from(ident)
))
})
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value, ctx)),
Attr::Strs(string) => { Attr::Strs(string) => {
let mut attrs = Attrs { let mut attrs = Attrs {
stcs: HashMap::new(), stcs: HashMap::new(),
@@ -413,13 +420,12 @@ impl Attrs {
} else { } else {
match name { match name {
Attr::Str(ident) => { Attr::Str(ident) => {
if self.stcs.get(&ident).is_some() { if self.stcs.insert(ident.clone(), value).is_some() {
return Err(Error::DowngradeError(format!( return Err(Error::DowngradeError(format!(
r#"attribute '{}' already defined"#, r#"attribute '{}' already defined"#,
Symbol::from(ident) Symbol::from(ident)
))); )));
} }
self.stcs.insert(ident, value);
} }
Attr::Strs(string) => { Attr::Strs(string) => {
self.dyns.push(DynamicAttrPair(string.ir(), value)); self.dyns.push(DynamicAttrPair(string.ir(), value));

View File

@@ -2,7 +2,6 @@ use rnix::ast;
use super::*; use super::*;
pub fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result<Param> { pub fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result<Param> {
match param { match param {
ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())), ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())),
@@ -122,7 +121,10 @@ pub fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result<Att
} }
} }
pub fn downgrade_attrpath(attrpath: ast::Attrpath, ctx: &mut DowngradeContext) -> Result<Vec<Attr>> { pub fn downgrade_attrpath(
attrpath: ast::Attrpath,
ctx: &mut DowngradeContext,
) -> Result<Vec<Attr>> {
attrpath attrpath
.attrs() .attrs()
.map(|attr| downgrade_attr(attr, ctx)) .map(|attr| downgrade_attr(attr, ctx))

View File

@@ -6,8 +6,8 @@ mod env;
mod stack; mod stack;
mod ty; mod ty;
pub mod error;
pub mod ir;
pub mod eval;
pub mod engine; pub mod engine;
pub mod error;
pub mod eval;
pub mod ir;
pub use ty::public::Value; pub use ty::public::Value;

View File

@@ -1,5 +1,5 @@
use std::mem::{MaybeUninit, replace, transmute}; use std::mem::{MaybeUninit, replace, transmute};
use std::ops::Deref; use std::ops::{Deref, DerefMut};
use crate::error::*; use crate::error::*;
@@ -18,13 +18,25 @@ pub struct Stack<T, const CAP: usize> {
top: usize, top: usize,
} }
impl<T, const CAP: usize> Default for Stack<T, CAP> { impl<T, const CAP: usize> Default for Stack<T, CAP> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl<T: Clone, const CAP: usize> Clone for Stack<T, CAP> {
fn clone(&self) -> Self {
let mut items = [const { MaybeUninit::uninit() }; CAP];
for (i, item) in self.items.iter().take(self.top).enumerate() {
items[i].write(unsafe { item.assume_init_ref() }.clone());
}
Self {
items,
top: self.top,
}
}
}
impl<T, const CAP: usize> Stack<T, CAP> { impl<T, const CAP: usize> Stack<T, CAP> {
pub fn new() -> Self { pub fn new() -> Self {
Stack { Stack {
@@ -68,6 +80,12 @@ impl<T, const CAP: usize> Deref for Stack<T, CAP> {
} }
} }
impl<T, const CAP: usize> DerefMut for Stack<T, CAP> {
fn deref_mut(&mut self) -> &mut Self::Target {
into!(&mut self.items[0..self.top])
}
}
impl<T, const CAP: usize> Drop for Stack<T, CAP> { impl<T, const CAP: usize> Drop for Stack<T, CAP> {
fn drop(&mut self) { fn drop(&mut self) {
self.items.as_mut_slice()[0..self.top] self.items.as_mut_slice()[0..self.top]

View File

@@ -1,8 +1,8 @@
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use ecow::EcoString;
use derive_more::Constructor; use derive_more::Constructor;
use ecow::EcoString;
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use itertools::Itertools; use itertools::Itertools;
@@ -50,30 +50,39 @@ impl AttrSet {
self.data.insert(sym, val); self.data.insert(sym, val);
} }
pub fn select(&self, mut path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<Value> { pub fn select(
// .ok_or_else(|| Error::EvalError())), &self,
mut path: impl DoubleEndedIterator<Item = Result<EcoString>>,
) -> Result<Value> {
// .ok_or_else(|| Error::EvalError())),
let mut data = &self.data; let mut data = &self.data;
let last = path.nth_back(0).unwrap(); let last = path.nth_back(0).unwrap();
for item in path { for item in path {
let item = item?; let item = item?;
let Some(Value::AttrSet(attrs)) = data.get(&item) else { let Some(Value::AttrSet(attrs)) = data.get(&item) else {
return Err(Error::EvalError(format!("{} not found", Symbol::from(item)))) return Err(Error::EvalError(format!(
"{} not found",
Symbol::from(item)
)));
}; };
data = attrs.as_inner(); data = attrs.as_inner();
} }
let last = last?; let last = last?;
data.get(&last).cloned().ok_or_else(|| Error::EvalError(format!("{} not found", Symbol::from(last)))) data.get(&last)
.cloned()
.ok_or_else(|| Error::EvalError(format!("{} not found", Symbol::from(last))))
} }
pub fn has_attr(&self, path: impl IntoIterator<Item = Result<EcoString>>) -> Result<bool> { pub fn has_attr(&self, mut path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<bool> {
let mut data = &self.data; let mut data = &self.data;
let last = path.nth_back(0).unwrap();
for item in path { for item in path {
let Some(Value::AttrSet(attrs)) = data.get(&item?) else { let Some(Value::AttrSet(attrs)) = data.get(&item?) else {
return Ok(false) return Ok(false);
}; };
data = attrs.as_inner(); data = attrs.as_inner();
} }
Ok(true) Ok(data.get(&last?).is_some())
} }
pub fn update(&mut self, other: &AttrSet) { pub fn update(&mut self, other: &AttrSet) {

View File

@@ -10,10 +10,7 @@ pub struct Func<'gc> {
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<VmEnv>) -> Self {
Self { Self { func, env }
func,
env,
}
} }
} }

View File

@@ -4,9 +4,9 @@ use std::rc::Weak;
use ecow::EcoVec; use ecow::EcoVec;
use hashbrown::HashSet; use hashbrown::HashSet;
use crate::engine::Engine;
use crate::env::VmEnv; use crate::env::VmEnv;
use crate::ty::public as p; use crate::ty::public as p;
use crate::engine::Engine;
use super::Value; use super::Value;
@@ -36,7 +36,9 @@ impl Deref for List {
impl List { impl List {
pub fn new() -> Self { pub fn new() -> Self {
List { data: EcoVec::new() } List {
data: EcoVec::new(),
}
} }
pub fn with_capacity(cap: usize) -> Self { pub fn with_capacity(cap: usize) -> Self {

View File

@@ -1,7 +1,6 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::hash::Hash; use std::hash::Hash;
use std::rc::{Rc, Weak}; use std::rc::Rc;
use std::sync::RwLock;
use derive_more::{IsVariant, Unwrap}; use derive_more::{IsVariant, Unwrap};
use ecow::EcoString; use ecow::EcoString;
@@ -9,11 +8,11 @@ use hashbrown::HashSet;
use replace_with::replace_with_or_abort; use replace_with::replace_with_or_abort;
use super::common::*; use super::common::*;
use super::public::{self as p, Symbol}; use super::public as p;
use crate::env::VmEnv;
use crate::error::*;
use crate::engine::Engine; use crate::engine::Engine;
use crate::env::{VmEnv, VmEnvWeak};
use crate::error::*;
mod attrset; mod attrset;
mod func; mod func;
@@ -27,30 +26,14 @@ pub use primop::*;
#[derive(Clone)] #[derive(Clone)]
pub enum EnvRef { pub enum EnvRef {
Strong(Rc<VmEnv>), Strong(VmEnv),
Weak(Weak<VmEnv>) Weak(VmEnvWeak),
} }
#[derive(Clone)] #[derive(Clone)]
pub struct ThunkRef { pub struct ThunkRef {
pub idx: usize, pub idx: usize,
pub env: Option<EnvRef> pub env: Option<EnvRef>,
}
pub enum Thunk {
Expr(ThunkRef),
Suspended,
Value(Value)
}
impl Thunk {
pub fn new(idx: usize) -> Self {
Thunk::Expr(ThunkRef::new(idx))
}
pub fn force(&mut self, engine: &Engine) -> Result<Value> {
todo!()
}
} }
impl ThunkRef { impl ThunkRef {
@@ -61,12 +44,19 @@ impl ThunkRef {
pub fn capture(&mut self, env: EnvRef) { pub fn capture(&mut self, env: EnvRef) {
let _ = self.env.insert(env); 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 { impl EnvRef {
pub fn upgrade(&mut self) { pub fn upgraded(self) -> VmEnv {
if let EnvRef::Weak(weak) = &*self { match self {
*self = EnvRef::Strong(weak.upgrade().unwrap()) EnvRef::Weak(weak) => weak.upgrade(),
EnvRef::Strong(strong) => strong,
} }
} }
} }
@@ -78,13 +68,13 @@ pub enum Value {
Bool(bool), Bool(bool),
String(EcoString), String(EcoString),
Null, Null,
Thunk(Rc<RwLock<Thunk>>), Thunk(ThunkRef),
AttrSet(Rc<AttrSet>), AttrSet(Rc<AttrSet>),
List(List), List(List),
Catchable(EcoString), Catchable(EcoString),
PrimOp(Rc<PrimOp>), PrimOp(Rc<PrimOp>),
PartialPrimOp(Rc<PartialPrimOp>), PartialPrimOp(Rc<PartialPrimOp>),
Func(Rc<RwLock<ThunkRef>>), Func(ThunkRef),
} }
impl Hash for Value { impl Hash for Value {
@@ -137,13 +127,13 @@ pub enum ValueAsRef<'v> {
Bool(bool), Bool(bool),
String(&'v EcoString), String(&'v EcoString),
Null, Null,
Thunk(&'v RwLock<Thunk>), Thunk(&'v ThunkRef),
AttrSet(&'v AttrSet), AttrSet(&'v AttrSet),
List(&'v List), List(&'v List),
Catchable(&'v str), Catchable(&'v str),
PrimOp(&'v PrimOp), PrimOp(&'v PrimOp),
PartialPrimOp(&'v PartialPrimOp), PartialPrimOp(&'v PartialPrimOp),
Func(&'v RwLock<ThunkRef>), Func(&'v ThunkRef),
} }
impl Value { impl Value {
@@ -197,7 +187,7 @@ impl Value {
} }
} }
pub fn call(&mut self, arg: Self, engine: &Engine) -> Result<()> { pub fn call(&mut self, arg: Self, engine: &mut Engine) -> Result<()> {
use Value::*; use Value::*;
if matches!(arg, Value::Catchable(_)) { if matches!(arg, Value::Catchable(_)) {
*self = arg; *self = arg;
@@ -206,6 +196,13 @@ impl Value {
*self = match self { *self = match self {
PrimOp(func) => func.call(arg, engine), PrimOp(func) => func.call(arg, engine),
PartialPrimOp(func) => func.call(arg, engine), PartialPrimOp(func) => func.call(arg, engine),
Func(func) => {
let mut env = func.env.take().unwrap().upgraded().clone();
env.enter_arg(arg);
let val = engine.eval_thunk(func.idx, &mut env);
env.pop_arg();
val
}
Catchable(_) => return Ok(()), Catchable(_) => return Ok(()),
_ => todo!(), _ => todo!(),
}?; }?;
@@ -389,10 +386,12 @@ impl Value {
} }
} }
pub fn select(&mut self, path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<&mut Self> { pub fn select(
&mut self,
path: impl DoubleEndedIterator<Item = Result<EcoString>>,
) -> Result<&mut Self> {
let val = match self { let val = match self {
Value::AttrSet(attrs) => attrs Value::AttrSet(attrs) => attrs.select(path),
.select(path),
Value::Catchable(_) => return Ok(self), Value::Catchable(_) => return Ok(self),
_ => Err(Error::EvalError(format!( _ => Err(Error::EvalError(format!(
"cannot select from {:?}", "cannot select from {:?}",
@@ -403,7 +402,11 @@ impl Value {
Ok(self) Ok(self)
} }
pub fn select_with_default(&mut self, path: impl DoubleEndedIterator<Item = Result<EcoString>>, default: Self) -> Result<&mut Self> { pub fn select_with_default(
&mut self,
path: impl DoubleEndedIterator<Item = Result<EcoString>>,
default: Self,
) -> Result<&mut Self> {
let val = match self { let val = match self {
Value::AttrSet(attrs) => attrs.select(path).unwrap_or(default), Value::AttrSet(attrs) => attrs.select(path).unwrap_or(default),
Value::Catchable(_) => return Ok(self), Value::Catchable(_) => return Ok(self),
@@ -418,7 +421,7 @@ impl Value {
Ok(self) Ok(self)
} }
pub fn has_attr(&mut self, path: impl IntoIterator<Item = Result<EcoString>>) -> Result<()> { pub fn has_attr(&mut self, path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<()> {
if let Value::AttrSet(attrs) = self { if let Value::AttrSet(attrs) = self {
let val = Value::Bool(attrs.has_attr(path)?); let val = Value::Bool(attrs.has_attr(path)?);
*self = val; *self = val;
@@ -438,13 +441,16 @@ impl Value {
self self
} }
pub fn force(&mut self, engine: &Engine) -> Result<&mut Self> { pub fn force(&mut self, engine: &mut Engine) -> Result<&mut Self> {
if let Value::Thunk(thunk) = &*self { if let Value::Thunk(thunk) = self {
let val = { unsafe {
let mut thunk = thunk.write().unwrap(); let old = std::ptr::read(thunk);
thunk.force(engine) let mut env = old.env.unwrap().upgraded();
}?; std::ptr::write(
*self = val; self,
engine.eval_thunk(old.idx, &mut env)?,
);
}
} }
Ok(self) Ok(self)
} }
@@ -477,4 +483,3 @@ impl Value {
} }
} }
} }

View File

@@ -2,8 +2,8 @@ use std::rc::Rc;
use derive_more::Constructor; use derive_more::Constructor;
use crate::error::Result;
use crate::engine::Engine; use crate::engine::Engine;
use crate::error::Result;
use super::Value; use super::Value;

View File

@@ -1,7 +1,7 @@
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ops::Deref; use std::ops::Deref;
use std::sync::LazyLock; use std::sync::LazyLock;
use std::collections::BTreeMap;
use derive_more::{Constructor, IsVariant, Unwrap}; use derive_more::{Constructor, IsVariant, Unwrap};
use ecow::EcoString; use ecow::EcoString;