#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum CompileError {
#[error("unsupported expression: {0}")]
Unsupported(String),
#[error("missing AST node: {0}")]
MissingNode(String),
#[error("constant pool overflow (>{max} constants)", max = u16::MAX)]
ConstantPoolOverflow,
#[error("jump offset overflow")]
JumpOverflow,
#[error("too many local variables")]
TooManyLocals,
#[error("parse error: {0}")]
ParseError(String),
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum VMError {
#[error("type error in {context}: expected {expected}, got {got}")]
TypeError {
expected: &'static str,
got: &'static str,
context: String,
},
#[error("division by zero")]
DivisionByZero,
#[error("assertion failed")]
AssertionFailed,
#[error("stack underflow")]
StackUnderflow,
#[error("invalid opcode: {0}")]
InvalidOpcode(u8),
#[error("not a function: {0}")]
NotCallable(String),
#[error("undefined variable: {0}")]
UndefinedVariable(String),
#[error("attribute not found: {0}")]
AttrNotFound(String),
#[error("internal error: {0}")]
Internal(String),
#[error("stack overflow: call depth exceeded")]
StackOverflow,
#[error("{0}")]
Throw(String),
#[error("unknown builtin: {0}")]
UnknownBuiltin(String),
#[error("infinite recursion detected")]
InfiniteRecursion,
#[error("import error: {0}")]
ImportError(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compile_error_display() {
let e = CompileError::Unsupported("with".to_string());
assert!(e.to_string().contains("with"));
}
#[test]
fn vm_error_display() {
let e = VMError::DivisionByZero;
assert!(e.to_string().contains("division by zero"));
}
#[test]
fn type_error_display() {
let e = VMError::TypeError {
expected: "int",
got: "string",
context: "addition".to_string(),
};
let msg = e.to_string();
assert!(msg.contains("int"));
assert!(msg.contains("string"));
assert!(msg.contains("addition"));
}
}