feat: recursive builtins
This commit is contained in:
@@ -146,6 +146,10 @@ impl RecAttrSet {
|
||||
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<()> {
|
||||
let mut map: Vec<_> = self
|
||||
.data
|
||||
|
||||
@@ -2,7 +2,7 @@ use ecow::EcoString;
|
||||
use itertools::Itertools;
|
||||
use rpds::HashTrieMap;
|
||||
|
||||
use crate::bytecode::{OpCodes, ThunkIdx};
|
||||
use crate::bytecode::OpCodes;
|
||||
use crate::ty::internal::{Thunk, Value};
|
||||
|
||||
use crate::vm::{CapturedEnv, VM};
|
||||
@@ -11,7 +11,7 @@ use crate::vm::{CapturedEnv, VM};
|
||||
pub enum Param {
|
||||
Ident(EcoString),
|
||||
Formals {
|
||||
formals: Vec<(EcoString, Option<ThunkIdx>)>,
|
||||
formals: Vec<(EcoString, Option<Thunk>)>,
|
||||
ellipsis: bool,
|
||||
alias: Option<EcoString>,
|
||||
},
|
||||
@@ -60,7 +60,7 @@ impl Func {
|
||||
for (formal, default) in formals {
|
||||
let arg = arg
|
||||
.select(formal.clone().into())
|
||||
.or_else(|| default.map(|idx| Value::Thunk(Thunk(idx))))
|
||||
.or_else(|| default.map(|thunk| Value::Thunk(thunk)))
|
||||
.unwrap();
|
||||
new.insert_mut(formal.into(), arg);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ impl Func {
|
||||
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 {
|
||||
panic!()
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@ pub struct AttrSet {
|
||||
|
||||
impl Debug for AttrSet {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
use Value::*;
|
||||
write!(f, "{{ ")?;
|
||||
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, "}}")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user