feat: recursive builtins
This commit is contained in:
@@ -6,7 +6,7 @@ use nixjit::*;
|
|||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let mut rl = DefaultEditor::new()?;
|
let mut rl = DefaultEditor::new()?;
|
||||||
loop {
|
loop {
|
||||||
let readline = rl.readline(">> ");
|
let readline = rl.readline("nixjit-repl> ");
|
||||||
match readline {
|
match readline {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
if expr.trim().is_empty() {
|
if expr.trim().is_empty() {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::ty::common::Symbol;
|
use crate::ty::common::Symbol;
|
||||||
use crate::ty::internal::{AttrSet, Const, PrimOp, Value};
|
use crate::ty::internal::{Const, PrimOp, RecAttrSet, Thunk, Value, _Thunk};
|
||||||
use crate::vm::Env;
|
use crate::vm::Env;
|
||||||
|
|
||||||
pub fn env() -> Arc<Env> {
|
pub fn env() -> Arc<Env> {
|
||||||
@@ -42,15 +43,20 @@ pub fn env() -> Arc<Env> {
|
|||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut builtins = AttrSet::empty();
|
let builtins_env = Env::empty();
|
||||||
|
let map = builtins_env.enter_rec();
|
||||||
for primop in primops {
|
for primop in primops {
|
||||||
env.insert(
|
env.insert(
|
||||||
Symbol::from(format!("__{}", primop.name)),
|
Symbol::from(format!("__{}", primop.name)),
|
||||||
Value::PrimOp(primop.clone()),
|
Value::PrimOp(primop.clone()),
|
||||||
);
|
);
|
||||||
builtins.push_attr(Symbol::from(primop.name), Value::PrimOp(primop));
|
map.borrow_mut().insert_mut(Symbol::from(primop.name), Value::PrimOp(primop));
|
||||||
}
|
}
|
||||||
|
let builtins = Value::RecAttrSet(RecAttrSet::from_inner(map.clone()));
|
||||||
|
let thunk= Thunk { thunk: RefCell::new(_Thunk::Value(Box::new(builtins.clone()))), env: RefCell::default() };
|
||||||
|
thunk.capture(Arc::new(builtins_env));
|
||||||
|
map.borrow_mut().insert_mut(Symbol::from("builtins"), Value::Thunk(thunk));
|
||||||
|
|
||||||
env.insert(Symbol::from("builtins"), Value::AttrSet(builtins));
|
env.insert(Symbol::from("builtins"), builtins);
|
||||||
env
|
env
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,27 +337,6 @@ pub enum Param {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<i::Param> for Param {
|
|
||||||
fn into(self) -> i::Param {
|
|
||||||
use i::Param::*;
|
|
||||||
match self {
|
|
||||||
Param::Ident(ident) => Ident(ident),
|
|
||||||
Param::Formals {
|
|
||||||
formals,
|
|
||||||
ellipsis,
|
|
||||||
alias,
|
|
||||||
} => Formals {
|
|
||||||
formals: formals
|
|
||||||
.into_iter()
|
|
||||||
.map(|(ident, default)| (ident, default.map(|thunk| thunk.idx)))
|
|
||||||
.collect(),
|
|
||||||
ellipsis,
|
|
||||||
alias,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Downgrade
|
trait Downgrade
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|||||||
@@ -146,6 +146,10 @@ impl RecAttrSet {
|
|||||||
self.data.borrow().clone()
|
self.data.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_inner(data: Arc<RefCell<HashTrieMapSync<Symbol, Value>>>) -> Self {
|
||||||
|
RecAttrSet { data }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn force_deep(&mut self, vm: &VM) -> Result<()> {
|
pub fn force_deep(&mut self, vm: &VM) -> Result<()> {
|
||||||
let mut map: Vec<_> = self
|
let mut map: Vec<_> = self
|
||||||
.data
|
.data
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use ecow::EcoString;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rpds::HashTrieMap;
|
use rpds::HashTrieMap;
|
||||||
|
|
||||||
use crate::bytecode::{OpCodes, ThunkIdx};
|
use crate::bytecode::OpCodes;
|
||||||
use crate::ty::internal::{Thunk, Value};
|
use crate::ty::internal::{Thunk, Value};
|
||||||
|
|
||||||
use crate::vm::{CapturedEnv, VM};
|
use crate::vm::{CapturedEnv, VM};
|
||||||
@@ -11,7 +11,7 @@ use crate::vm::{CapturedEnv, VM};
|
|||||||
pub enum Param {
|
pub enum Param {
|
||||||
Ident(EcoString),
|
Ident(EcoString),
|
||||||
Formals {
|
Formals {
|
||||||
formals: Vec<(EcoString, Option<ThunkIdx>)>,
|
formals: Vec<(EcoString, Option<Thunk>)>,
|
||||||
ellipsis: bool,
|
ellipsis: bool,
|
||||||
alias: Option<EcoString>,
|
alias: Option<EcoString>,
|
||||||
},
|
},
|
||||||
@@ -60,7 +60,7 @@ impl Func {
|
|||||||
for (formal, default) in formals {
|
for (formal, default) in formals {
|
||||||
let arg = arg
|
let arg = arg
|
||||||
.select(formal.clone().into())
|
.select(formal.clone().into())
|
||||||
.or_else(|| default.map(|idx| Value::Thunk(Thunk(idx))))
|
.or_else(|| default.map(|thunk| Value::Thunk(thunk)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
new.insert_mut(formal.into(), arg);
|
new.insert_mut(formal.into(), arg);
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ impl Func {
|
|||||||
formals.push((param, None));
|
formals.push((param, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_default_param(&mut self, default: ThunkIdx) {
|
pub fn push_default_param(&mut self, default: Thunk) {
|
||||||
let Param::Formals { formals, .. } = self.param.as_mut().unwrap() else {
|
let Param::Formals { formals, .. } = self.param.as_mut().unwrap() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
use anyhow::Result;
|
use std::cell::RefCell;
|
||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use derive_more::{IsVariant, Unwrap};
|
||||||
|
|
||||||
|
use super::common::Catchable;
|
||||||
use super::common as c;
|
use super::common as c;
|
||||||
use super::public as p;
|
use super::public as p;
|
||||||
|
|
||||||
use c::Symbol;
|
use c::Symbol;
|
||||||
|
|
||||||
use crate::vm::VM;
|
use crate::vm::{VM, Env};
|
||||||
|
use crate::bytecode::OpCodes;
|
||||||
|
|
||||||
mod attrset;
|
mod attrset;
|
||||||
mod cnst;
|
mod cnst;
|
||||||
@@ -26,8 +31,75 @@ pub trait ToPublic {
|
|||||||
fn to_public(self, vm: &VM) -> p::Value;
|
fn to_public(self, vm: &VM) -> p::Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Constructor)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Thunk(usize);
|
pub struct Thunk {
|
||||||
|
pub thunk: RefCell<_Thunk>,
|
||||||
|
pub env: RefCell<Option<Arc<Env>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, IsVariant, Unwrap, Clone)]
|
||||||
|
pub enum _Thunk {
|
||||||
|
Code(OpCodes),
|
||||||
|
SuspendedFrom(*const Thunk),
|
||||||
|
Value(Box<Value>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Thunk {
|
||||||
|
pub fn new(opcodes: OpCodes) -> Thunk {
|
||||||
|
Thunk {
|
||||||
|
thunk: RefCell::new(_Thunk::Code(opcodes)),
|
||||||
|
env: RefCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_code(&self) -> OpCodes {
|
||||||
|
self.thunk.borrow().clone().unwrap_code()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capture(&self, env: Arc<Env>) {
|
||||||
|
*self.env.borrow_mut() = Some(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn force(&self, vm: &VM) -> Result<Value> {
|
||||||
|
{
|
||||||
|
match &*self.thunk.borrow() {
|
||||||
|
_Thunk::Value(value) => return Ok(value.as_ref().clone()),
|
||||||
|
_Thunk::SuspendedFrom(from) => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"already suspended from {from:p} (infinite recursion encountered)"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_Thunk::Code(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let opcodes = std::mem::replace(
|
||||||
|
&mut *self.thunk.borrow_mut(),
|
||||||
|
_Thunk::SuspendedFrom(self as *const Thunk),
|
||||||
|
)
|
||||||
|
.unwrap_code();
|
||||||
|
let value = vm
|
||||||
|
.eval(opcodes, self.env.borrow().clone().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let _ = std::mem::replace(
|
||||||
|
&mut *self.thunk.borrow_mut(),
|
||||||
|
_Thunk::Value(value.clone().into()),
|
||||||
|
);
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> Option<Value> {
|
||||||
|
match &*self.thunk.borrow() {
|
||||||
|
_Thunk::Value(value) => Some(value.as_ref().clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Thunk {
|
||||||
|
fn eq(&self, _: &Self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, IsVariant, Unwrap, Clone, PartialEq)]
|
#[derive(Debug, IsVariant, Unwrap, Clone, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
@@ -104,6 +176,21 @@ impl Value {
|
|||||||
|
|
||||||
use Value::Const as VmConst;
|
use Value::Const as VmConst;
|
||||||
impl Value {
|
impl Value {
|
||||||
|
pub fn typename(&self) -> &'static str {
|
||||||
|
use Value::*;
|
||||||
|
match self {
|
||||||
|
Const(_) => todo!(),
|
||||||
|
Thunk(_) => "thunk",
|
||||||
|
AttrSet(_) => "set",
|
||||||
|
RecAttrSet(_) => "set",
|
||||||
|
List(_) => "list",
|
||||||
|
Catchable(_) => todo!(),
|
||||||
|
PrimOp(_) => "lambda",
|
||||||
|
PartialPrimOp(_) => "lambda",
|
||||||
|
Func(_) => "lambda"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn callable(&self) -> bool {
|
pub fn callable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::PrimOp(_) | Value::PartialPrimOp(_) | Value::Func(_) => true,
|
Value::PrimOp(_) | Value::PartialPrimOp(_) | Value::Func(_) => true,
|
||||||
@@ -133,6 +220,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
func
|
func
|
||||||
}
|
}
|
||||||
|
x @ Catchable(_) => x,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,6 +229,7 @@ impl Value {
|
|||||||
use Const::*;
|
use Const::*;
|
||||||
match self {
|
match self {
|
||||||
VmConst(Bool(bool)) => VmConst(Bool(!bool)),
|
VmConst(Bool(bool)) => VmConst(Bool(!bool)),
|
||||||
|
x @ Value::Catchable(_) => x,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,7 +380,7 @@ impl Value {
|
|||||||
)))));
|
)))));
|
||||||
*self = val;
|
*self = val;
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
*self = Value::Catchable(Catchable::new(Some(format!("cannot select from {:?}", self.typename()))))
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -333,7 +422,7 @@ impl Value {
|
|||||||
|
|
||||||
pub fn force(&mut self, vm: &VM) -> Result<&mut Self> {
|
pub fn force(&mut self, vm: &VM) -> Result<&mut Self> {
|
||||||
if let Value::Thunk(thunk) = self {
|
if let Value::Thunk(thunk) = self {
|
||||||
let value = vm.get_thunk_value(thunk.0)?;
|
let value = thunk.force(vm)?;
|
||||||
*self = value
|
*self = value
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@@ -342,7 +431,7 @@ impl Value {
|
|||||||
pub fn force_deep(&mut self, vm: &VM) -> Result<&mut Self> {
|
pub fn force_deep(&mut self, vm: &VM) -> Result<&mut Self> {
|
||||||
match self {
|
match self {
|
||||||
Value::Thunk(thunk) => {
|
Value::Thunk(thunk) => {
|
||||||
let mut value = vm.get_thunk_value(thunk.0)?;
|
let mut value = thunk.force(vm)?;
|
||||||
value.force_deep(vm)?;
|
value.force_deep(vm)?;
|
||||||
*self = value;
|
*self = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,14 @@ pub struct AttrSet {
|
|||||||
|
|
||||||
impl Debug for AttrSet {
|
impl Debug for AttrSet {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
|
use Value::*;
|
||||||
write!(f, "{{ ")?;
|
write!(f, "{{ ")?;
|
||||||
for (k, v) in self.data.iter() {
|
for (k, v) in self.data.iter() {
|
||||||
write!(f, "{k:?} = {v:?}; ")?;
|
match v {
|
||||||
|
List(_) => write!(f, "{k:?} = [ ... ]; ")?,
|
||||||
|
AttrSet(_) => write!(f, "{k:?} = {{ ... }}; ")?,
|
||||||
|
v => write!(f, "{k:?} = {v:?}; ")?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
mod env;
|
mod env;
|
||||||
mod stack;
|
mod stack;
|
||||||
mod vm;
|
mod vm;
|
||||||
mod vmthunk;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ fn test_attrs() {
|
|||||||
);
|
);
|
||||||
test_expr("{ a.b = 1; } ? a.b", boolean!(true));
|
test_expr("{ a.b = 1; } ? a.b", boolean!(true));
|
||||||
test_expr(
|
test_expr(
|
||||||
"{ a.b = 1; } // { a.c = 2 }",
|
"{ a.b = 1; } // { a.c = 2; }",
|
||||||
attrs! { symbol!("a") => attrs!{ symbol!("c") => thunk!() } },
|
attrs! { symbol!("a") => attrs!{ symbol!("c") => thunk!() } },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/vm/vm.rs
22
src/vm/vm.rs
@@ -10,7 +10,6 @@ use crate::ty::public as p;
|
|||||||
|
|
||||||
use super::env::Env;
|
use super::env::Env;
|
||||||
use super::stack::{STACK_SIZE, Stack};
|
use super::stack::{STACK_SIZE, Stack};
|
||||||
use super::vmthunk::*;
|
|
||||||
|
|
||||||
pub fn run(prog: Program) -> Result<p::Value> {
|
pub fn run(prog: Program) -> Result<p::Value> {
|
||||||
let vm = VM::new(prog.thunks);
|
let vm = VM::new(prog.thunks);
|
||||||
@@ -18,20 +17,20 @@ pub fn run(prog: Program) -> Result<p::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct VM {
|
pub struct VM {
|
||||||
thunks: Box<[VmThunk]>,
|
thunks: Box<[Thunk]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VM {
|
impl VM {
|
||||||
fn new(thunks: Thunks) -> Self {
|
fn new(thunks: Thunks) -> Self {
|
||||||
let thunks = thunks
|
let thunks = thunks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|bytecode::Thunk { opcodes }| VmThunk::new(opcodes))
|
.map(|bytecode::Thunk { opcodes }| Thunk::new(opcodes))
|
||||||
.collect();
|
.collect();
|
||||||
VM { thunks }
|
VM { thunks }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_thunk_value(&self, idx: usize) -> Result<Value> {
|
pub fn get_thunk(&self, idx: usize) -> Thunk {
|
||||||
self.thunks.get(idx).unwrap().force(self)
|
self.thunks[idx].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(&self, opcodes: OpCodes, env: Arc<Env>) -> Result<Value> {
|
pub fn eval(&self, opcodes: OpCodes, env: Arc<Env>) -> Result<Value> {
|
||||||
@@ -63,10 +62,10 @@ impl VM {
|
|||||||
OpCode::Const { value } => stack.push(Value::Const(value))?,
|
OpCode::Const { value } => stack.push(Value::Const(value))?,
|
||||||
OpCode::LoadThunk { idx } => {
|
OpCode::LoadThunk { idx } => {
|
||||||
self.thunks[idx].capture(env);
|
self.thunks[idx].capture(env);
|
||||||
stack.push(Value::Thunk(Thunk::new(idx)))?
|
stack.push(Value::Thunk(self.thunks[idx].clone()))?
|
||||||
}
|
}
|
||||||
OpCode::LoadValue { idx } => {
|
OpCode::LoadValue { idx } => {
|
||||||
stack.push(self.get_thunk_value(idx)?)?;
|
stack.push(self.get_thunk(idx).force(self)?)?;
|
||||||
}
|
}
|
||||||
OpCode::ForceValue => {
|
OpCode::ForceValue => {
|
||||||
stack.tos_mut()?.force(self)?;
|
stack.tos_mut()?.force(self)?;
|
||||||
@@ -116,7 +115,7 @@ impl VM {
|
|||||||
.tos_mut()?
|
.tos_mut()?
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap_func()
|
.unwrap_func()
|
||||||
.push_default_param(idx);
|
.push_default_param(self.get_thunk(idx));
|
||||||
}
|
}
|
||||||
OpCode::SetEllipsis => {
|
OpCode::SetEllipsis => {
|
||||||
stack.tos_mut()?.as_mut().unwrap_func().set_ellipsis();
|
stack.tos_mut()?.as_mut().unwrap_func().set_ellipsis();
|
||||||
@@ -187,6 +186,7 @@ impl VM {
|
|||||||
let default = stack.pop()?;
|
let default = stack.pop()?;
|
||||||
stack
|
stack
|
||||||
.tos_mut()?
|
.tos_mut()?
|
||||||
|
.force(self)?
|
||||||
.select_with_default(Symbol::new(sym), default);
|
.select_with_default(Symbol::new(sym), default);
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamic => {
|
OpCode::SelectDynamic => {
|
||||||
@@ -202,16 +202,16 @@ impl VM {
|
|||||||
val.force(self)?;
|
val.force(self)?;
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.select_with_default(sym, default);
|
stack.tos_mut()?.force(self)?.select_with_default(sym, default);
|
||||||
}
|
}
|
||||||
OpCode::HasAttr { sym } => {
|
OpCode::HasAttr { sym } => {
|
||||||
stack.tos_mut()?.has_attr(Symbol::new(sym));
|
stack.tos_mut()?.force(self)?.has_attr(Symbol::new(sym));
|
||||||
}
|
}
|
||||||
OpCode::HasDynamicAttr => {
|
OpCode::HasDynamicAttr => {
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop().unwrap();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.has_attr(sym);
|
stack.tos_mut()?.force(self)?.has_attr(sym);
|
||||||
}
|
}
|
||||||
OpCode::LookUp { sym } => {
|
OpCode::LookUp { sym } => {
|
||||||
stack.push(
|
stack.push(
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
|
||||||
|
|
||||||
use crate::bytecode::OpCodes;
|
|
||||||
|
|
||||||
use super::env::Env;
|
|
||||||
use super::vm::VM;
|
|
||||||
use crate::ty::internal::Value;
|
|
||||||
|
|
||||||
pub struct VmThunk {
|
|
||||||
thunk: RefCell<_VmThunk>,
|
|
||||||
env: RefCell<Option<Arc<Env>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(IsVariant, Unwrap, Clone)]
|
|
||||||
enum _VmThunk {
|
|
||||||
Code(OpCodes),
|
|
||||||
SuspendedFrom(*const VmThunk),
|
|
||||||
Value(Value),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VmThunk {
|
|
||||||
pub fn new(opcodes: OpCodes) -> VmThunk {
|
|
||||||
VmThunk {
|
|
||||||
thunk: RefCell::new(_VmThunk::Code(opcodes)),
|
|
||||||
env: RefCell::new(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unwrap_code(&self) -> OpCodes {
|
|
||||||
self.thunk.borrow().clone().unwrap_code()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn capture(&self, env: Arc<Env>) {
|
|
||||||
*self.env.borrow_mut() = Some(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn force(&self, vm: &VM) -> Result<Value> {
|
|
||||||
{
|
|
||||||
match &*self.thunk.borrow() {
|
|
||||||
_VmThunk::Value(value) => return Ok(value.clone()),
|
|
||||||
_VmThunk::SuspendedFrom(from) => {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"already suspended from {from:p} (infinite recursion encountered)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_VmThunk::Code(_) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let opcodes = std::mem::replace(
|
|
||||||
&mut *self.thunk.borrow_mut(),
|
|
||||||
_VmThunk::SuspendedFrom(self as *const VmThunk),
|
|
||||||
)
|
|
||||||
.unwrap_code();
|
|
||||||
let value = vm
|
|
||||||
.eval(opcodes, self.env.borrow().clone().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
let _ = std::mem::replace(
|
|
||||||
&mut *self.thunk.borrow_mut(),
|
|
||||||
_VmThunk::Value(value.clone()),
|
|
||||||
);
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value(&self) -> Option<Value> {
|
|
||||||
match &*self.thunk.borrow() {
|
|
||||||
_VmThunk::Value(value) => Some(value.clone()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user