feat: ref

This commit is contained in:
2025-05-11 10:19:55 +08:00
parent cbb29276d8
commit 7cbb082dc4
12 changed files with 180 additions and 165 deletions

View File

@@ -1,3 +1,4 @@
use std::cell::OnceCell;
use std::sync::Arc;
use crate::builtins::env;
@@ -19,17 +20,30 @@ mod stack;
mod test;
pub fn run(prog: Program) -> Result<p::Value> {
let vm = VM::new(prog.thunks, prog.funcs);
Ok(vm.eval(prog.top_level, env())?.to_public(&vm))
let vm = VM::new(
prog.thunks,
prog.funcs
.into_iter()
.map(|f| Func {
env: OnceCell::new(),
param: f.param,
opcodes: f.opcodes,
})
.collect(),
);
let env = env();
let temp = vm.eval(prog.top_level, env)?;
let temp = temp.to_public(&vm);
Ok(temp)
}
pub struct VM {
thunks: Box<[Thunk]>,
funcs: Box<[Func]>,
pub struct VM<'vm> {
thunks: Box<[Thunk<'vm>]>,
funcs: Box<[Func<'vm>]>,
}
impl VM {
fn new(thunks: Box<[OpCodes]>, funcs: Box<[Func]>) -> Self {
impl<'vm> VM<'vm> {
fn new(thunks: Box<[OpCodes]>, funcs: Box<[Func<'vm>]>) -> Self {
let thunks = thunks
.into_iter()
.map(|opcodes| Thunk::new(opcodes))
@@ -37,15 +51,15 @@ impl VM {
VM { thunks, funcs }
}
pub fn get_thunk(&self, idx: usize) -> &Thunk {
&self.thunks[idx]
pub fn get_thunk(&self, idx: usize) -> &'vm Thunk<'vm> {
unsafe { &*(&self.thunks[idx] as *const _) }
}
pub fn get_func(&self, idx: usize) -> &Func {
&self.funcs[idx]
pub fn get_func(&self, idx: usize) -> &'vm Func<'vm> {
unsafe { &*(&self.funcs[idx] as *const _) }
}
pub fn eval(&self, opcodes: OpCodes, env: Arc<Env>) -> Result<Value> {
pub fn eval(&self, opcodes: OpCodes, env: Arc<Env<'vm>>) -> Result<Value<'vm>> {
let mut stack = Stack::<STACK_SIZE>::new();
let mut iter = opcodes.into_iter();
while let Some(opcode) = iter.next() {
@@ -61,12 +75,13 @@ impl VM {
}
#[inline]
fn single_op<const CAP: usize>(
fn single_op<'s, const CAP: usize>(
&self,
opcode: OpCode,
stack: &mut Stack<CAP>,
env: Arc<Env>,
) -> Result<usize> {
stack: &'s mut Stack<'vm, CAP>,
env: Arc<Env<'vm>>,
) -> Result<usize>
{
match opcode {
OpCode::Illegal => panic!("illegal opcode"),
OpCode::Const { value } => stack.push(Value::Const(value))?,
@@ -101,8 +116,9 @@ impl VM {
stack.push(func.call(self, args)?)?;
}
OpCode::Func { idx } => {
self.get_func(idx).env.get_or_init(|| env.captured());
stack.push(Value::Func(idx))?;
let func = self.get_func(idx);
func.env.get_or_init(|| env.captured());
stack.push(Value::Func(func))?;
}
OpCode::UnOp { op } => {
use UnOp::*;