runmat-vm 0.5.4

RunMat virtual machine and bytecode interpreter
Documentation
#![allow(clippy::result_large_err)]

use futures::executor::block_on;
use runmat_builtins::Value;
use runmat_hir::LoweringContext;
use runmat_runtime::RuntimeError;

const EXEC_STACK_BYTES: usize = 32 * 1024 * 1024;

struct VmThreadStateGuard;

impl VmThreadStateGuard {
    fn enter() -> Self {
        runmat_vm::reset_thread_state_for_tests();
        Self
    }
}

impl Drop for VmThreadStateGuard {
    fn drop(&mut self) {
        runmat_vm::reset_thread_state_for_tests();
    }
}

fn run_with_stack<T>(f: impl FnOnce() -> T) -> Result<T, RuntimeError> {
    let _state_guard = VmThreadStateGuard::enter();
    Ok(stacker::grow(EXEC_STACK_BYTES, f))
}

pub fn compile_source(source: &str) -> Result<runmat_vm::Bytecode, RuntimeError> {
    let ast = runmat_parser::parse(source).map_err(|err| RuntimeError::new(err.to_string()))?;
    let hir = runmat_hir::lower(&ast, &LoweringContext::empty())
        .map_err(|err| RuntimeError::from(runmat_vm::CompileError::from(err)))?;
    let mir = runmat_mir::lowering::lower_assembly(&hir.assembly)
        .map_err(|err| RuntimeError::new(format!("{err:?}")))?;
    let entrypoint = hir.assembly.entrypoints[0].id;
    runmat_vm::compile(&hir.assembly, &mir, entrypoint).map_err(RuntimeError::from)
}

#[allow(dead_code)]
pub fn execute_source(source: &str) -> Result<Vec<Value>, RuntimeError> {
    let bc = compile_source(source)?;
    interpret(&bc)
}

#[allow(dead_code)]
pub fn interpret(bytecode: &runmat_vm::Bytecode) -> Result<Vec<Value>, RuntimeError> {
    let bytecode = bytecode.clone();
    run_with_stack(move || block_on(runmat_vm::interpret(&bytecode)))?
}