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"
|
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",
|
||||||
|
|||||||
@@ -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"] }
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,4 +221,3 @@ fn bench_fib(b: &mut Bencher) {
|
|||||||
black_box(())
|
black_box(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
178
src/env.rs
178
src/env.rs
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|
||||||
|
|||||||
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::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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
22
src/stack.rs
22
src/stack.rs
@@ -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]
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user