#![allow(clippy::result_large_err)]
#[cfg(feature = "native-accel")]
pub mod accel_graph;
pub mod bytecode;
pub mod compiler;
pub mod functions;
#[cfg(feature = "native-accel")]
mod fusion_stack_layout;
pub mod gc_roots;
pub mod instr;
pub mod vm;
pub use bytecode::compile;
pub use functions::{Bytecode, ExecutionContext, UserFunction};
pub use instr::Instr;
pub use vm::{
interpret, interpret_with_vars, push_pending_workspace, set_call_stack_limit,
set_error_namespace, take_updated_workspace_state, InterpreterOutcome, InterpreterState,
PendingWorkspaceGuard, DEFAULT_CALLSTACK_LIMIT, DEFAULT_ERROR_NAMESPACE,
};
use miette::{SourceOffset, SourceSpan};
use runmat_builtins::Value;
use runmat_hir::{HirProgram, SemanticError, Span};
use runmat_runtime::{build_runtime_error, RuntimeError};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct CompileError {
pub message: String,
pub span: Option<Span>,
pub identifier: Option<String>,
}
impl CompileError {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
span: None,
identifier: None,
}
}
pub fn with_span(mut self, span: Span) -> Self {
self.span = Some(span);
self
}
pub fn with_identifier(mut self, identifier: impl Into<String>) -> Self {
self.identifier = Some(identifier.into());
self
}
}
impl std::fmt::Display for CompileError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for CompileError {}
impl From<String> for CompileError {
fn from(value: String) -> Self {
CompileError::new(value)
}
}
impl From<&str> for CompileError {
fn from(value: &str) -> Self {
CompileError::new(value)
}
}
impl From<SemanticError> for CompileError {
fn from(value: SemanticError) -> Self {
let mut err = CompileError::new(value.message);
if let Some(span) = value.span {
err = err.with_span(span);
}
if let Some(identifier) = value.identifier {
err = err.with_identifier(identifier);
}
err
}
}
impl From<CompileError> for RuntimeError {
fn from(value: CompileError) -> Self {
let mut builder = build_runtime_error(value.message);
if let Some(identifier) = value.identifier {
builder = builder.with_identifier(identifier);
}
if let Some(span) = value.span {
let len = span.end.saturating_sub(span.start).max(1);
builder = builder.with_span(SourceSpan::new(SourceOffset::from(span.start), len));
}
builder.build()
}
}
pub async fn execute(program: &HirProgram) -> Result<Vec<Value>, RuntimeError> {
let bc = compile(program, &HashMap::new()).map_err(RuntimeError::from)?;
interpret(&bc).await
}