Skip to main content

runmat_vm/interpreter/
errors.rs

1use crate::bytecode::Bytecode;
2use crate::runtime::call_stack::error_namespace;
3use miette::{SourceOffset, SourceSpan};
4use runmat_runtime::{build_runtime_error, RuntimeError};
5use runmat_thread_local::runmat_thread_local;
6use std::cell::Cell;
7
8runmat_thread_local! {
9    static CURRENT_PC: Cell<usize> = const { Cell::new(0) };
10}
11
12#[inline]
13pub fn set_vm_pc(pc: usize) {
14    CURRENT_PC.with(|cell| cell.set(pc));
15}
16
17#[inline]
18pub fn current_vm_pc() -> usize {
19    CURRENT_PC.with(|cell| cell.get())
20}
21
22pub fn attach_span_at(bytecode: &Bytecode, pc: usize, mut err: RuntimeError) -> RuntimeError {
23    if err.span.is_none() {
24        if let Some(span) = bytecode.instr_spans.get(pc) {
25            let len = span.end.saturating_sub(span.start).max(1);
26            err.span = Some(SourceSpan::new(SourceOffset::from(span.start), len));
27        }
28    }
29    err
30}
31
32pub fn attach_span_from_pc(bytecode: &Bytecode, err: RuntimeError) -> RuntimeError {
33    let pc = current_vm_pc();
34    attach_span_at(bytecode, pc, err)
35}
36
37#[inline]
38pub fn mex(id: &str, msg: &str) -> RuntimeError {
39    let suffix = match id.find(':') {
40        Some(pos) => &id[pos + 1..],
41        None => id,
42    };
43    let ident = format!("{}:{suffix}", error_namespace());
44    build_runtime_error(msg.to_string())
45        .with_identifier(ident)
46        .build()
47}
48
49#[inline]
50pub fn ensure_runtime_error_identifier(mut err: RuntimeError) -> RuntimeError {
51    if err.identifier.is_none() {
52        err.identifier = Some(format!("{}:RuntimeError", error_namespace()));
53    }
54    err
55}