feat: recursive builtins

This commit is contained in:
2025-05-05 16:43:14 +08:00
parent bd783f1b96
commit 550ad54f30
11 changed files with 134 additions and 126 deletions

View File

@@ -1,12 +1,17 @@
use anyhow::Result;
use derive_more::{Constructor, IsVariant, Unwrap};
use std::cell::RefCell;
use std::sync::Arc;
use anyhow::{anyhow, Result};
use derive_more::{IsVariant, Unwrap};
use super::common::Catchable;
use super::common as c;
use super::public as p;
use c::Symbol;
use crate::vm::VM;
use crate::vm::{VM, Env};
use crate::bytecode::OpCodes;
mod attrset;
mod cnst;
@@ -26,8 +31,75 @@ pub trait ToPublic {
fn to_public(self, vm: &VM) -> p::Value;
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Constructor)]
pub struct Thunk(usize);
#[derive(Debug, Clone)]
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)]
pub enum Value {
@@ -104,6 +176,21 @@ impl Value {
use Value::Const as VmConst;
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 {
match self {
Value::PrimOp(_) | Value::PartialPrimOp(_) | Value::Func(_) => true,
@@ -133,6 +220,7 @@ impl Value {
}
func
}
x @ Catchable(_) => x,
_ => todo!(),
}
}
@@ -141,6 +229,7 @@ impl Value {
use Const::*;
match self {
VmConst(Bool(bool)) => VmConst(Bool(!bool)),
x @ Value::Catchable(_) => x,
_ => todo!(),
}
}
@@ -291,7 +380,7 @@ impl Value {
)))));
*self = val;
} else {
todo!()
*self = Value::Catchable(Catchable::new(Some(format!("cannot select from {:?}", self.typename()))))
}
self
}
@@ -333,7 +422,7 @@ impl Value {
pub fn force(&mut self, vm: &VM) -> Result<&mut Self> {
if let Value::Thunk(thunk) = self {
let value = vm.get_thunk_value(thunk.0)?;
let value = thunk.force(vm)?;
*self = value
}
Ok(self)
@@ -342,7 +431,7 @@ impl Value {
pub fn force_deep(&mut self, vm: &VM) -> Result<&mut Self> {
match self {
Value::Thunk(thunk) => {
let mut value = vm.get_thunk_value(thunk.0)?;
let mut value = thunk.force(vm)?;
value.force_deep(vm)?;
*self = value;
}