Skip to main content

sui_bytecode/
error.rs

1//! Error types for the bytecode compiler and VM.
2
3/// Errors produced during bytecode compilation.
4#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
5pub enum CompileError {
6    /// An AST construct that the compiler does not yet support.
7    #[error("unsupported expression: {0}")]
8    Unsupported(String),
9    /// A required AST child node was missing.
10    #[error("missing AST node: {0}")]
11    MissingNode(String),
12    /// The constant pool exceeded the u16 index limit.
13    #[error("constant pool overflow (>{max} constants)", max = u16::MAX)]
14    ConstantPoolOverflow,
15    /// A jump target exceeded the u16 offset limit.
16    #[error("jump offset overflow")]
17    JumpOverflow,
18    /// A local variable count exceeded the u16 limit.
19    #[error("too many local variables")]
20    TooManyLocals,
21    /// Syntax error in the input.
22    #[error("parse error: {0}")]
23    ParseError(String),
24}
25
26/// Errors produced during bytecode VM execution.
27#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
28pub enum VMError {
29    /// A type mismatch at runtime.
30    #[error("type error in {context}: expected {expected}, got {got}")]
31    TypeError {
32        expected: &'static str,
33        got: &'static str,
34        context: String,
35    },
36    /// Integer division by zero.
37    #[error("division by zero")]
38    DivisionByZero,
39    /// An assertion failed.
40    #[error("assertion failed")]
41    AssertionFailed,
42    /// Stack underflow (internal compiler/VM bug).
43    #[error("stack underflow")]
44    StackUnderflow,
45    /// Invalid opcode byte encountered.
46    #[error("invalid opcode: {0}")]
47    InvalidOpcode(u8),
48    /// Attempt to call a non-function value.
49    #[error("not a function: {0}")]
50    NotCallable(String),
51    /// An undefined variable was referenced.
52    #[error("undefined variable: {0}")]
53    UndefinedVariable(String),
54    /// An attribute was not found in an attrset.
55    #[error("attribute not found: {0}")]
56    AttrNotFound(String),
57    /// Internal VM error (should not happen in correct programs).
58    #[error("internal error: {0}")]
59    Internal(String),
60    /// Maximum call depth exceeded.
61    #[error("stack overflow: call depth exceeded")]
62    StackOverflow,
63    /// A `throw` or `abort` was invoked.
64    #[error("{0}")]
65    Throw(String),
66    /// An unknown builtin was referenced.
67    #[error("unknown builtin: {0}")]
68    UnknownBuiltin(String),
69    /// A thunk entered infinite recursion (blackhole).
70    #[error("infinite recursion detected")]
71    InfiniteRecursion,
72    /// An I/O error during import.
73    #[error("import error: {0}")]
74    ImportError(String),
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn compile_error_display() {
83        let e = CompileError::Unsupported("with".to_string());
84        assert!(e.to_string().contains("with"));
85    }
86
87    #[test]
88    fn vm_error_display() {
89        let e = VMError::DivisionByZero;
90        assert!(e.to_string().contains("division by zero"));
91    }
92
93    #[test]
94    fn type_error_display() {
95        let e = VMError::TypeError {
96            expected: "int",
97            got: "string",
98            context: "addition".to_string(),
99        };
100        let msg = e.to_string();
101        assert!(msg.contains("int"));
102        assert!(msg.contains("string"));
103        assert!(msg.contains("addition"));
104    }
105}