feat: at least it compiles, right?
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -267,6 +267,15 @@ version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@@ -312,6 +321,7 @@ dependencies = [
|
||||
"hashbrown 0.15.3",
|
||||
"inkwell",
|
||||
"itertools",
|
||||
"lru",
|
||||
"priority-queue",
|
||||
"regex",
|
||||
"replace_with",
|
||||
|
||||
@@ -28,6 +28,7 @@ ecow = "0.2"
|
||||
regex = "1.11"
|
||||
hashbrown = "0.15"
|
||||
priority-queue = "2.5"
|
||||
lru = "0.14"
|
||||
replace_with = "0.1"
|
||||
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ use std::process::exit;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use nixjit::engine::eval;
|
||||
use nixjit::error::Error;
|
||||
use nixjit::error::Result;
|
||||
use nixjit::ir::downgrade;
|
||||
use nixjit::engine::eval;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut args = std::env::args();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ecow::EcoString;
|
||||
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> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
@@ -1,52 +1,63 @@
|
||||
use std::sync::RwLock;
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use lru::LruCache;
|
||||
use priority_queue::PriorityQueue;
|
||||
|
||||
use crate::env::VmEnv;
|
||||
use crate::error::Result;
|
||||
use crate::eval::Evaluate;
|
||||
use crate::ir::{Downgraded, Ir};
|
||||
use crate::ty::public::Value;
|
||||
use crate::ty::internal as i;
|
||||
use crate::error::Result;
|
||||
use crate::ty::public::Value;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
type ThunkIdx = usize;
|
||||
type EnvIdx = usize;
|
||||
|
||||
pub struct Engine {
|
||||
thunks: Box<[RwLock<Thunk>]>,
|
||||
func_offset: usize,
|
||||
tasks: PriorityQueue<CompileTask, usize>
|
||||
thunks: Box<[Ir]>,
|
||||
pub func_offset: usize,
|
||||
tasks: PriorityQueue<CompileTask, usize>,
|
||||
lru: LruCache<(ThunkIdx, EnvIdx), i::Value>,
|
||||
}
|
||||
|
||||
pub fn eval(downgraded: Downgraded) -> Result<Value> {
|
||||
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 {
|
||||
pub fn new(thunks: Box<[Ir]>, func_offset: usize) -> 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,
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn eval_thunk(&self, idx: usize, env: &VmEnv) -> Result<i::Value> {
|
||||
todo!()
|
||||
pub fn eval_thunk(&mut self, idx: usize, env: &mut VmEnv) -> Result<i::Value> {
|
||||
self.thunks[idx].clone().eval(self, env)
|
||||
}
|
||||
}
|
||||
|
||||
enum Thunk {
|
||||
Expr(Ir),
|
||||
Compiling,
|
||||
Compiled(fn(Rc<VmEnv>) -> Value)
|
||||
Compiled(fn(Rc<VmEnv>) -> Value),
|
||||
}
|
||||
|
||||
impl Thunk {
|
||||
@@ -57,5 +68,5 @@ impl Thunk {
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
struct CompileTask {
|
||||
idx: usize
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
@@ -221,4 +221,3 @@ fn bench_fib(b: &mut Bencher) {
|
||||
black_box(())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
178
src/env.rs
178
src/env.rs
@@ -1,33 +1,34 @@
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use ecow::EcoString;
|
||||
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> {
|
||||
let_: Rc<LetEnv<V>>,
|
||||
with: Rc<With<K, V>>,
|
||||
args: Rc<Vec<V>>,
|
||||
#[derive(Clone)]
|
||||
pub struct VmEnv {
|
||||
let_: Rc<RefCell<Stack<Vec<Value>, 1000>>>,
|
||||
with: Rc<With>,
|
||||
args: Rc<RefCell<Stack<Value, 1000>>>,
|
||||
new: bool,
|
||||
pub id: usize,
|
||||
}
|
||||
|
||||
pub struct LetEnv<V> {
|
||||
map: Vec<V>,
|
||||
last: Option<Rc<LetEnv<V>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct VmEnvWeak {
|
||||
let_: Weak<RefCell<Stack<Vec<Value>, 1000>>>,
|
||||
with: Weak<With>,
|
||||
args: Weak<RefCell<Stack<Value, 1000>>>,
|
||||
new: bool,
|
||||
pub id: usize,
|
||||
}
|
||||
|
||||
pub type VmEnv = Env<EcoString, Value>;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct With<K: Hash + Eq, V> {
|
||||
map: Option<Rc<HashMap<K, V>>>,
|
||||
last: Option<Rc<With<K, V>>>,
|
||||
}
|
||||
|
||||
enum LetNode<K: Hash + Eq, V> {
|
||||
Let(Rc<HashMap<K, V>>),
|
||||
MultiArg(Rc<HashMap<K, V>>),
|
||||
pub struct With {
|
||||
map: Option<Rc<HashMap<EcoString, Value>>>,
|
||||
last: Option<Rc<With>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -37,27 +38,30 @@ pub enum Type {
|
||||
With,
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Clone, V: Clone> Env<K, V> {
|
||||
pub fn new(map: Vec<V>) -> Self {
|
||||
impl VmEnv {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
let_: LetEnv::new(map),
|
||||
let_: Rc::default(),
|
||||
with: With {
|
||||
map: None,
|
||||
last: None,
|
||||
}.into(),
|
||||
args: Vec::new().into(),
|
||||
}
|
||||
.into(),
|
||||
args: Rc::default(),
|
||||
new: false,
|
||||
id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_arg(&self, level: usize) -> &V {
|
||||
&self.args[self.args.len() - level - 1]
|
||||
pub fn lookup_let(&self, level: usize, idx: usize) -> Value {
|
||||
self.let_.borrow()[level][idx].clone()
|
||||
}
|
||||
|
||||
pub fn lookup_let(&self, level: usize, idx: usize) -> &V {
|
||||
self.let_.lookup(level, idx)
|
||||
pub fn lookup_arg(&self, level: usize) -> Value {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -65,69 +69,103 @@ impl<K: Hash + Eq + Clone, V: Clone> Env<K, V> {
|
||||
self.with.map.is_some()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn enter_arg(&self, val: V) -> Self {
|
||||
let mut args = self.args.clone();
|
||||
Rc::make_mut(&mut args).push(val);
|
||||
Self {
|
||||
let_: self.let_.clone(),
|
||||
with: self.with.clone(),
|
||||
args,
|
||||
pub fn enter_let(&mut self, mut map: Vec<Value>) {
|
||||
if Rc::strong_count(&self.let_) > 1 {
|
||||
self.let_ = Rc::new_cyclic(|weak| {
|
||||
let weak = VmEnvWeak {
|
||||
let_: weak.clone(),
|
||||
with: Rc::downgrade(&self.with),
|
||||
args: Rc::downgrade(&self.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_let(&self, map: Vec<V>) -> Self {
|
||||
Self {
|
||||
let_: self.let_.clone().enter_let(map),
|
||||
with: self.with.clone(),
|
||||
args: self.args.clone(),
|
||||
pub fn enter_arg(&mut self, val: Value) {
|
||||
if Rc::strong_count(&self.args) > 1 {
|
||||
self.args = Rc::new(self.args.as_ref().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]
|
||||
pub fn enter_with(&self, map: Rc<HashMap<K, V>>) -> Self {
|
||||
pub fn enter_with(&self, map: Rc<HashMap<EcoString, Value>>) -> Self {
|
||||
Self {
|
||||
let_: self.let_.clone(),
|
||||
with: self.with.clone().enter(map),
|
||||
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> {
|
||||
pub fn new(map: Vec<V>) -> Rc<Self> {
|
||||
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> {
|
||||
impl With {
|
||||
pub fn lookup(&self, symbol: &EcoString) -> Option<Value> {
|
||||
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))
|
||||
}
|
||||
|
||||
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 {
|
||||
map: Some(map),
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl JITCompile for Attrs {
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for List {
|
||||
impl JITCompile for List {
|
||||
fn compile<'gc>(self, ctx: &JITContext<'gc>) {
|
||||
todo!()
|
||||
}
|
||||
@@ -32,7 +32,7 @@ impl JITCompile for BinOp {
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for UnOp {
|
||||
impl JITCompile for UnOp {
|
||||
fn compile<'gc>(self, ctx: &JITContext<'gc>) {
|
||||
todo!()
|
||||
}
|
||||
@@ -91,13 +91,13 @@ impl JITCompile for Const {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl JITCompile for String {
|
||||
fn compile<'gc>(self, ctx: &JITContext<'gc>) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl JITCompile for Var {
|
||||
fn compile<'gc>(self, ctx: &JITContext<'gc>) {
|
||||
todo!()
|
||||
@@ -124,6 +124,6 @@ impl JITCompile for Thunk {
|
||||
|
||||
impl JITCompile for Path {
|
||||
fn compile<'gc>(self, ctx: &JITContext<'gc>) {
|
||||
todo!()
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue};
|
||||
use crate::env::VmEnv;
|
||||
use crate::eval::Engine;
|
||||
|
||||
use super::{JITContext, JITValue, ValueTag, JITValueData};
|
||||
use super::{JITContext, JITValue, JITValueData, ValueTag};
|
||||
|
||||
pub struct Helpers<'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 {
|
||||
let env = unsafe { env.as_ref() }.unwrap();
|
||||
let val: JITValue = env.lookup_let(level, idx).clone().into();
|
||||
val
|
||||
todo!()
|
||||
}
|
||||
|
||||
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::ops::Deref;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
|
||||
use inkwell::OptimizationLevel;
|
||||
use inkwell::builder::Builder;
|
||||
@@ -10,8 +10,8 @@ use inkwell::module::Module;
|
||||
use crate::env::VmEnv;
|
||||
use crate::ty::internal::Value;
|
||||
|
||||
mod helpers;
|
||||
mod compile;
|
||||
mod helpers;
|
||||
|
||||
pub use compile::JITCompile;
|
||||
use helpers::Helpers;
|
||||
@@ -105,7 +105,6 @@ impl Deref for JITFunc<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct JITContext<'ctx> {
|
||||
context: &'ctx Context,
|
||||
module: Module<'ctx>,
|
||||
|
||||
@@ -8,8 +8,8 @@ use inkwell::context::Context;
|
||||
|
||||
use ecow::EcoString;
|
||||
|
||||
use crate::ir::downgrade;
|
||||
use super::JITContext;
|
||||
use crate::ir::downgrade;
|
||||
use crate::ty::common::Const;
|
||||
use crate::ty::public::*;
|
||||
|
||||
|
||||
133
src/eval/mod.rs
133
src/eval/mod.rs
@@ -7,26 +7,34 @@ use crate::env::VmEnv;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ir::{self, DynamicAttrPair};
|
||||
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;
|
||||
|
||||
pub mod jit;
|
||||
|
||||
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 {
|
||||
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(
|
||||
self.stcs
|
||||
.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<_>>()?,
|
||||
);
|
||||
for DynamicAttrPair(k, v) in self.dyns {
|
||||
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)?);
|
||||
}
|
||||
Value::AttrSet(attrs.into()).ok()
|
||||
@@ -34,11 +42,17 @@ impl Evaluate for ir::Attrs {
|
||||
}
|
||||
|
||||
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(
|
||||
self.items
|
||||
.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<_>>>()?,
|
||||
))
|
||||
.ok()
|
||||
@@ -46,7 +60,7 @@ impl Evaluate for ir::List {
|
||||
}
|
||||
|
||||
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::*;
|
||||
let mut val = self.lhs.eval(engine, env)?;
|
||||
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(),
|
||||
Dynamic(expr) => {
|
||||
let mut val = expr.eval(engine, env)?;
|
||||
val.coerce_to_string();
|
||||
val.force(engine)?.coerce_to_string();
|
||||
val.unwrap_string()
|
||||
}
|
||||
})
|
||||
@@ -65,10 +79,12 @@ impl Evaluate for ir::HasAttr {
|
||||
}
|
||||
|
||||
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::*;
|
||||
let mut lhs = self.lhs.eval(engine, env)?;
|
||||
let mut rhs = self.rhs.eval(engine, env)?;
|
||||
lhs.force(engine)?;
|
||||
rhs.force(engine)?;
|
||||
match self.kind {
|
||||
Add => lhs.add(rhs),
|
||||
Sub => {
|
||||
@@ -115,9 +131,10 @@ impl Evaluate for ir::BinOp {
|
||||
}
|
||||
|
||||
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::*;
|
||||
let mut rhs = self.rhs.eval(engine, env)?;
|
||||
rhs.force(engine)?;
|
||||
match self.kind {
|
||||
Neg => rhs.neg(),
|
||||
Not => rhs.not(),
|
||||
@@ -127,43 +144,45 @@ impl Evaluate for ir::UnOp {
|
||||
}
|
||||
|
||||
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::*;
|
||||
let mut val = self.expr.eval(engine, env)?;
|
||||
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| {
|
||||
Ok(match attr {
|
||||
Str(ident) => ident,
|
||||
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
||||
Dynamic(expr) => {
|
||||
let mut val = expr.eval(engine, env)?;
|
||||
val.coerce_to_string();
|
||||
val.force(engine)?.coerce_to_string();
|
||||
val.unwrap_string()
|
||||
}
|
||||
})
|
||||
}),
|
||||
default.eval(engine, env)?,
|
||||
default,
|
||||
)?;
|
||||
} else {
|
||||
val.select(self.attrpath.into_iter().map(|attr| {
|
||||
Ok(match attr {
|
||||
Str(ident) => ident,
|
||||
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
||||
Dynamic(expr) => {
|
||||
let mut val = expr.eval(engine, env)?;
|
||||
val.coerce_to_string();
|
||||
val.unwrap_string()
|
||||
}
|
||||
})
|
||||
}))?;
|
||||
val.force(engine)?
|
||||
.select(self.attrpath.into_iter().map(|attr| {
|
||||
Ok(match attr {
|
||||
Str(ident) => ident,
|
||||
Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
|
||||
Dynamic(expr) => {
|
||||
let mut val = expr.eval(engine, env)?;
|
||||
val.force(engine)?.coerce_to_string();
|
||||
val.unwrap_string()
|
||||
}
|
||||
})
|
||||
}))?;
|
||||
}
|
||||
val.ok()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
let cond = self.cond.eval(engine, env)?.unwrap_bool();
|
||||
if cond {
|
||||
@@ -175,14 +194,19 @@ impl Evaluate for ir::If {
|
||||
}
|
||||
|
||||
impl Evaluate for ir::LoadFunc {
|
||||
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> {
|
||||
Value::Func(Rc::new(ThunkRef::new(self.idx).into())).ok()
|
||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
||||
Value::Func(ThunkRef {
|
||||
idx: engine.func_offset + self.idx,
|
||||
env: Some(EnvRef::Strong(env.clone())).into(),
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
func.force(engine)?;
|
||||
// FIXME: Modify Value::call
|
||||
for arg in self.args {
|
||||
func.call(arg.eval(engine, env)?, engine)?;
|
||||
@@ -192,34 +216,44 @@ impl Evaluate for ir::Call {
|
||||
}
|
||||
|
||||
impl Evaluate for ir::Let {
|
||||
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> {
|
||||
let bindings = self.bindings.into_iter().map(|(_, v)| Ok(v.eval(engine, env)?)).collect::<Result<Vec<_>>>()?;
|
||||
self.expr.eval(engine, &env.enter_let(bindings))
|
||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
||||
let bindings = self
|
||||
.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 {
|
||||
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)?;
|
||||
// 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 {
|
||||
fn eval(self, engine: &Engine, env: &VmEnv) -> Result<Value> {
|
||||
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
.parts
|
||||
.into_iter()
|
||||
.map(|part| {
|
||||
let mut part = part.eval(engine, env)?;
|
||||
part.coerce_to_string();
|
||||
part.force(engine)?.coerce_to_string();
|
||||
part.ok()
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
@@ -235,13 +269,13 @@ impl Evaluate for ir::ConcatStrings {
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
impl Evaluate for ir::Const {
|
||||
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> {
|
||||
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
|
||||
match self.val {
|
||||
Const::Null => Value::Null,
|
||||
Const::Int(x) => Value::Int(x),
|
||||
@@ -253,33 +287,36 @@ impl Evaluate for ir::Const {
|
||||
}
|
||||
|
||||
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)
|
||||
.cloned()
|
||||
.ok_or_else(|| Error::EvalError(format!("{} not found", Symbol::from(self.sym))))
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
impl Evaluate for ir::LetVar {
|
||||
fn eval(self, _: &Engine, env: &VmEnv) -> Result<Value> {
|
||||
env.lookup_let(self.level, self.idx).clone().ok()
|
||||
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> {
|
||||
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 {
|
||||
fn eval(self, _: &Engine, _: &VmEnv) -> Result<Value> {
|
||||
Value::Thunk(Rc::new(Thunk::new(self.idx).into())).ok()
|
||||
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> {
|
||||
Value::Thunk(ThunkRef::new(self.idx)).ok()
|
||||
}
|
||||
}
|
||||
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ macro_rules! 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 {
|
||||
$(Ir::$ty(ir) => ir.eval(engine, env),)*
|
||||
}
|
||||
@@ -182,6 +182,8 @@ pub struct DowngradeContext {
|
||||
struct Env<'a, 'env> {
|
||||
env: EnvNode<'a>,
|
||||
prev: Option<&'env Env<'a, 'env>>,
|
||||
arg_level: usize,
|
||||
let_level: usize
|
||||
}
|
||||
|
||||
enum EnvNode<'a> {
|
||||
@@ -205,6 +207,8 @@ impl<'a, 'env> Env<'a, 'env> {
|
||||
Self {
|
||||
env: EnvNode::Builtins(base),
|
||||
prev: None,
|
||||
arg_level: 0,
|
||||
let_level: 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +216,8 @@ impl<'a, 'env> Env<'a, 'env> {
|
||||
Self {
|
||||
env: EnvNode::Let(map),
|
||||
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 {
|
||||
env: EnvNode::SingleArg(ident),
|
||||
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 {
|
||||
env: EnvNode::MultiArg(map, alias),
|
||||
prev: Some(self),
|
||||
arg_level: self.arg_level + 1,
|
||||
let_level: 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +247,8 @@ impl<'a, 'env> Env<'a, 'env> {
|
||||
Self {
|
||||
env: EnvNode::With,
|
||||
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) => {
|
||||
if let Ok(idx) = map.binary_search(ident) {
|
||||
return Ok(LookupResult::Let {
|
||||
level: let_level,
|
||||
level: let_level - 1,
|
||||
idx,
|
||||
});
|
||||
} else {
|
||||
let_level += 1;
|
||||
let_level -= 1;
|
||||
}
|
||||
}
|
||||
SingleArg(arg) => {
|
||||
if arg == ident {
|
||||
return Ok(LookupResult::SingleArg { level: arg_level });
|
||||
return Ok(LookupResult::SingleArg { level: arg_level - 1 });
|
||||
} else {
|
||||
arg_level += 1;
|
||||
arg_level -= 1;
|
||||
}
|
||||
}
|
||||
MultiArg(set, alias) => {
|
||||
if let Some(default) = set.get(ident) {
|
||||
return Ok(LookupResult::MultiArg {
|
||||
level: arg_level,
|
||||
level: arg_level - 1,
|
||||
default: default.clone(),
|
||||
});
|
||||
} else if alias.as_ref() == Some(ident) {
|
||||
return Ok(LookupResult::SingleArg { level: arg_level });
|
||||
return Ok(LookupResult::SingleArg { level: arg_level - 1 });
|
||||
} else {
|
||||
arg_level += 1;
|
||||
arg_level -= 1;
|
||||
}
|
||||
}
|
||||
With => has_with = true,
|
||||
@@ -296,7 +308,7 @@ impl<'a, 'env> Env<'a, 'env> {
|
||||
}
|
||||
|
||||
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<()> {
|
||||
if let Some(attr) = path.next() {
|
||||
match attr {
|
||||
Attr::Str(ident) => {
|
||||
if self.stcs.get(&ident).is_some() {
|
||||
self.stcs
|
||||
.get_mut(&ident)
|
||||
.unwrap()
|
||||
.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 {
|
||||
Attr::Str(ident) => self
|
||||
.stcs
|
||||
.entry(ident.clone())
|
||||
.or_insert_with(|| {
|
||||
Attrs {
|
||||
stcs: HashMap::new(),
|
||||
dyns: Vec::new(),
|
||||
};
|
||||
attrs._insert(path, name, value, ctx)?;
|
||||
assert!(self.stcs.insert(ident, attrs.ir()).is_none());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
.ir()
|
||||
})
|
||||
.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) => {
|
||||
let mut attrs = Attrs {
|
||||
stcs: HashMap::new(),
|
||||
@@ -413,13 +420,12 @@ impl Attrs {
|
||||
} else {
|
||||
match name {
|
||||
Attr::Str(ident) => {
|
||||
if self.stcs.get(&ident).is_some() {
|
||||
if self.stcs.insert(ident.clone(), value).is_some() {
|
||||
return Err(Error::DowngradeError(format!(
|
||||
r#"attribute '{}' already defined"#,
|
||||
Symbol::from(ident)
|
||||
)));
|
||||
}
|
||||
self.stcs.insert(ident, value);
|
||||
}
|
||||
Attr::Strs(string) => {
|
||||
self.dyns.push(DynamicAttrPair(string.ir(), value));
|
||||
|
||||
@@ -2,7 +2,6 @@ use rnix::ast;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
pub fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result<Param> {
|
||||
match param {
|
||||
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
|
||||
.attrs()
|
||||
.map(|attr| downgrade_attr(attr, ctx))
|
||||
|
||||
@@ -6,8 +6,8 @@ mod env;
|
||||
mod stack;
|
||||
mod ty;
|
||||
|
||||
pub mod error;
|
||||
pub mod ir;
|
||||
pub mod eval;
|
||||
pub mod engine;
|
||||
pub mod error;
|
||||
pub mod eval;
|
||||
pub mod ir;
|
||||
pub use ty::public::Value;
|
||||
|
||||
22
src/stack.rs
22
src/stack.rs
@@ -1,5 +1,5 @@
|
||||
use std::mem::{MaybeUninit, replace, transmute};
|
||||
use std::ops::Deref;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
@@ -18,13 +18,25 @@ pub struct Stack<T, const CAP: usize> {
|
||||
top: usize,
|
||||
}
|
||||
|
||||
|
||||
impl<T, const CAP: usize> Default for Stack<T, CAP> {
|
||||
fn default() -> Self {
|
||||
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> {
|
||||
pub fn new() -> Self {
|
||||
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> {
|
||||
fn drop(&mut self) {
|
||||
self.items.as_mut_slice()[0..self.top]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use ecow::EcoString;
|
||||
use derive_more::Constructor;
|
||||
use ecow::EcoString;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use itertools::Itertools;
|
||||
|
||||
@@ -50,30 +50,39 @@ impl AttrSet {
|
||||
self.data.insert(sym, val);
|
||||
}
|
||||
|
||||
pub fn select(&self, mut path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<Value> {
|
||||
// .ok_or_else(|| Error::EvalError())),
|
||||
pub fn select(
|
||||
&self,
|
||||
mut path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
||||
) -> Result<Value> {
|
||||
// .ok_or_else(|| Error::EvalError())),
|
||||
let mut data = &self.data;
|
||||
let last = path.nth_back(0).unwrap();
|
||||
for item in path {
|
||||
let item = item?;
|
||||
let Some(Value::AttrSet(attrs)) = data.get(&item) else {
|
||||
return Err(Error::EvalError(format!("{} not found", Symbol::from(item))))
|
||||
let Some(Value::AttrSet(attrs)) = data.get(&item) else {
|
||||
return Err(Error::EvalError(format!(
|
||||
"{} not found",
|
||||
Symbol::from(item)
|
||||
)));
|
||||
};
|
||||
data = attrs.as_inner();
|
||||
}
|
||||
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 last = path.nth_back(0).unwrap();
|
||||
for item in path {
|
||||
let Some(Value::AttrSet(attrs)) = data.get(&item?) else {
|
||||
return Ok(false)
|
||||
let Some(Value::AttrSet(attrs)) = data.get(&item?) else {
|
||||
return Ok(false);
|
||||
};
|
||||
data = attrs.as_inner();
|
||||
}
|
||||
Ok(true)
|
||||
Ok(data.get(&last?).is_some())
|
||||
}
|
||||
|
||||
pub fn update(&mut self, other: &AttrSet) {
|
||||
|
||||
@@ -10,10 +10,7 @@ pub struct Func<'gc> {
|
||||
|
||||
impl<'gc> Func<'gc> {
|
||||
pub fn new(func: &'gc ir::Func, env: Rc<VmEnv>) -> Self {
|
||||
Self {
|
||||
func,
|
||||
env,
|
||||
}
|
||||
Self { func, env }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ use std::rc::Weak;
|
||||
use ecow::EcoVec;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use crate::engine::Engine;
|
||||
use crate::env::VmEnv;
|
||||
use crate::ty::public as p;
|
||||
use crate::engine::Engine;
|
||||
|
||||
use super::Value;
|
||||
|
||||
@@ -36,7 +36,9 @@ impl Deref for List {
|
||||
|
||||
impl List {
|
||||
pub fn new() -> Self {
|
||||
List { data: EcoVec::new() }
|
||||
List {
|
||||
data: EcoVec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::cell::RefCell;
|
||||
use std::hash::Hash;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::RwLock;
|
||||
use std::rc::Rc;
|
||||
|
||||
use derive_more::{IsVariant, Unwrap};
|
||||
use ecow::EcoString;
|
||||
@@ -9,11 +8,11 @@ use hashbrown::HashSet;
|
||||
use replace_with::replace_with_or_abort;
|
||||
|
||||
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::env::{VmEnv, VmEnvWeak};
|
||||
use crate::error::*;
|
||||
|
||||
mod attrset;
|
||||
mod func;
|
||||
@@ -27,30 +26,14 @@ pub use primop::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum EnvRef {
|
||||
Strong(Rc<VmEnv>),
|
||||
Weak(Weak<VmEnv>)
|
||||
Strong(VmEnv),
|
||||
Weak(VmEnvWeak),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ThunkRef {
|
||||
pub idx: usize,
|
||||
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!()
|
||||
}
|
||||
pub env: Option<EnvRef>,
|
||||
}
|
||||
|
||||
impl ThunkRef {
|
||||
@@ -61,12 +44,19 @@ impl ThunkRef {
|
||||
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 upgrade(&mut self) {
|
||||
if let EnvRef::Weak(weak) = &*self {
|
||||
*self = EnvRef::Strong(weak.upgrade().unwrap())
|
||||
pub fn upgraded(self) -> VmEnv {
|
||||
match self {
|
||||
EnvRef::Weak(weak) => weak.upgrade(),
|
||||
EnvRef::Strong(strong) => strong,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,13 +68,13 @@ pub enum Value {
|
||||
Bool(bool),
|
||||
String(EcoString),
|
||||
Null,
|
||||
Thunk(Rc<RwLock<Thunk>>),
|
||||
Thunk(ThunkRef),
|
||||
AttrSet(Rc<AttrSet>),
|
||||
List(List),
|
||||
Catchable(EcoString),
|
||||
PrimOp(Rc<PrimOp>),
|
||||
PartialPrimOp(Rc<PartialPrimOp>),
|
||||
Func(Rc<RwLock<ThunkRef>>),
|
||||
Func(ThunkRef),
|
||||
}
|
||||
|
||||
impl Hash for Value {
|
||||
@@ -137,13 +127,13 @@ pub enum ValueAsRef<'v> {
|
||||
Bool(bool),
|
||||
String(&'v EcoString),
|
||||
Null,
|
||||
Thunk(&'v RwLock<Thunk>),
|
||||
Thunk(&'v ThunkRef),
|
||||
AttrSet(&'v AttrSet),
|
||||
List(&'v List),
|
||||
Catchable(&'v str),
|
||||
PrimOp(&'v PrimOp),
|
||||
PartialPrimOp(&'v PartialPrimOp),
|
||||
Func(&'v RwLock<ThunkRef>),
|
||||
Func(&'v ThunkRef),
|
||||
}
|
||||
|
||||
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::*;
|
||||
if matches!(arg, Value::Catchable(_)) {
|
||||
*self = arg;
|
||||
@@ -206,6 +196,13 @@ impl Value {
|
||||
*self = match self {
|
||||
PrimOp(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(()),
|
||||
_ => 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 {
|
||||
Value::AttrSet(attrs) => attrs
|
||||
.select(path),
|
||||
Value::AttrSet(attrs) => attrs.select(path),
|
||||
Value::Catchable(_) => return Ok(self),
|
||||
_ => Err(Error::EvalError(format!(
|
||||
"cannot select from {:?}",
|
||||
@@ -403,7 +402,11 @@ impl Value {
|
||||
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 {
|
||||
Value::AttrSet(attrs) => attrs.select(path).unwrap_or(default),
|
||||
Value::Catchable(_) => return Ok(self),
|
||||
@@ -418,7 +421,7 @@ impl Value {
|
||||
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 {
|
||||
let val = Value::Bool(attrs.has_attr(path)?);
|
||||
*self = val;
|
||||
@@ -438,13 +441,16 @@ impl Value {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn force(&mut self, engine: &Engine) -> Result<&mut Self> {
|
||||
if let Value::Thunk(thunk) = &*self {
|
||||
let val = {
|
||||
let mut thunk = thunk.write().unwrap();
|
||||
thunk.force(engine)
|
||||
}?;
|
||||
*self = val;
|
||||
pub fn force(&mut self, engine: &mut Engine) -> Result<&mut Self> {
|
||||
if let Value::Thunk(thunk) = self {
|
||||
unsafe {
|
||||
let old = std::ptr::read(thunk);
|
||||
let mut env = old.env.unwrap().upgraded();
|
||||
std::ptr::write(
|
||||
self,
|
||||
engine.eval_thunk(old.idx, &mut env)?,
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
@@ -477,4 +483,3 @@ impl Value {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::rc::Rc;
|
||||
|
||||
use derive_more::Constructor;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::engine::Engine;
|
||||
use crate::error::Result;
|
||||
|
||||
use super::Value;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
|
||||
use std::ops::Deref;
|
||||
use std::sync::LazyLock;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||
use ecow::EcoString;
|
||||
|
||||
Reference in New Issue
Block a user