jetcrab\vm\executor/error_handler.rs
1//! # Execution Error Handler
2//!
3//! Defines all error types that can occur during VM execution and provides
4//! comprehensive error handling capabilities.
5//!
6//! ## Error Categories
7//!
8//! - **Stack Errors**: Underflow, overflow, invalid operations
9//! - **Type Errors**: Invalid type conversions, unsupported operations
10//! - **Runtime Errors**: General execution failures, exceptions
11//! - **Memory Errors**: Heap allocation failures, invalid references
12//! - **Control Flow Errors**: Invalid jumps, function call failures
13//!
14//! ## Error Handling Strategy
15//!
16//! The VM uses a comprehensive error handling strategy:
17//!
18//! 1. **Immediate Detection**: Errors are detected as soon as they occur
19//! 2. **Detailed Information**: Each error contains context about what went wrong
20//! 3. **Recovery Options**: Some errors can be recovered from automatically
21//! 4. **User Feedback**: Clear error messages for debugging
22//!
23//! ## Usage
24//!
25//! ```rust
26//! use jetcrab::vm::executor::error_handler::ExecutionError;
27//!
28//! match some_operation() {
29//! Ok(result) => println!("Success: {:?}", result),
30//! Err(ExecutionError::StackUnderflow) => {
31//! eprintln!("Stack underflow occurred");
32//! }
33//! Err(ExecutionError::TypeError(msg)) => {
34//! eprintln!("Type error: {}", msg);
35//! }
36//! Err(e) => eprintln!("Other error: {:?}", e),
37//! }
38//! ```
39
40use std::error::Error;
41use std::fmt;
42
43/// Represents all possible errors that can occur during VM execution
44///
45/// This enum provides a comprehensive set of error types covering
46/// all aspects of virtual machine operation.
47#[derive(Debug, Clone)]
48pub enum ExecutionError {
49 /// Stack is empty when trying to pop a value
50 StackUnderflow,
51
52 /// Stack is full when trying to push a value
53 StackOverflow,
54
55 /// Invalid type conversion or operation
56 TypeError(String),
57
58 /// General runtime execution error
59 RuntimeError(String),
60
61 /// Invalid memory access or allocation failure
62 MemoryError(String),
63
64 /// Invalid instruction or bytecode
65 InvalidInstruction(String),
66
67 /// Function call or return error
68 FunctionError(String),
69
70 /// Variable access or assignment error
71 VariableError(String),
72
73 /// Heap allocation or garbage collection error
74 HeapError(String),
75
76 /// Control flow error (invalid jumps, etc.)
77 ControlFlowError(String),
78
79 /// Built-in function error
80 BuiltinError(String),
81
82 /// Division by zero
83 DivisionByZero,
84
85 /// Invalid array index
86 InvalidIndex(usize),
87
88 /// Property not found on object
89 PropertyNotFound(String),
90
91 /// Method not found on object
92 MethodNotFound(String),
93
94 /// Invalid argument count for function call
95 InvalidArgumentCount {
96 expected: usize,
97 received: usize,
98 },
99
100 /// Recursion limit exceeded
101 RecursionLimitExceeded(usize),
102
103 /// Timeout during execution
104 ExecutionTimeout,
105
106 /// Unsupported operation
107 UnsupportedOperation(String),
108}
109
110impl fmt::Display for ExecutionError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 match self {
113 ExecutionError::StackUnderflow => write!(f, "Stack underflow"),
114 ExecutionError::StackOverflow => write!(f, "Stack overflow"),
115 ExecutionError::TypeError(msg) => write!(f, "Type error: {}", msg),
116 ExecutionError::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
117 ExecutionError::MemoryError(msg) => write!(f, "Memory error: {}", msg),
118 ExecutionError::InvalidInstruction(msg) => write!(f, "Invalid instruction: {}", msg),
119 ExecutionError::FunctionError(msg) => write!(f, "Function error: {}", msg),
120 ExecutionError::VariableError(msg) => write!(f, "Variable error: {}", msg),
121 ExecutionError::HeapError(msg) => write!(f, "Heap error: {}", msg),
122 ExecutionError::ControlFlowError(msg) => write!(f, "Control flow error: {}", msg),
123 ExecutionError::BuiltinError(msg) => write!(f, "Built-in error: {}", msg),
124 ExecutionError::DivisionByZero => write!(f, "Division by zero"),
125 ExecutionError::InvalidIndex(idx) => write!(f, "Invalid index: {}", idx),
126 ExecutionError::PropertyNotFound(prop) => write!(f, "Property not found: {}", prop),
127 ExecutionError::MethodNotFound(method) => write!(f, "Method not found: {}", method),
128 ExecutionError::InvalidArgumentCount { expected, received } => {
129 write!(f, "Invalid argument count: expected {}, received {}", expected, received)
130 }
131 ExecutionError::RecursionLimitExceeded(limit) => {
132 write!(f, "Recursion limit exceeded: {}", limit)
133 }
134 ExecutionError::ExecutionTimeout => write!(f, "Execution timeout"),
135 ExecutionError::UnsupportedOperation(op) => write!(f, "Unsupported operation: {}", op),
136 }
137 }
138}
139
140impl Error for ExecutionError {}
141
142impl ExecutionError {
143 /// Creates a new type error with the given message
144 ///
145 /// # Arguments
146 /// * `message` - The error message
147 ///
148 /// # Returns
149 /// * A new `ExecutionError::TypeError`
150 ///
151 /// # Examples
152 ///
153 /// ```rust
154 /// let error = ExecutionError::new_type_error("Cannot add string and number");
155 /// assert!(matches!(error, ExecutionError::TypeError(_)));
156 /// ```
157 pub fn new_type_error(message: impl Into<String>) -> Self {
158 ExecutionError::TypeError(message.into())
159 }
160
161 /// Creates a new runtime error with the given message
162 ///
163 /// # Arguments
164 /// * `message` - The error message
165 ///
166 /// # Returns
167 /// * A new `ExecutionError::RuntimeError`
168 ///
169 /// # Examples
170 ///
171 /// ```rust
172 /// let error = ExecutionError::new_runtime_error("Function execution failed");
173 /// assert!(matches!(error, ExecutionError::RuntimeError(_)));
174 /// ```
175 pub fn new_runtime_error(message: impl Into<String>) -> Self {
176 ExecutionError::RuntimeError(message.into())
177 }
178
179 /// Creates a new memory error with the given message
180 ///
181 /// # Arguments
182 /// * `message` - The error message
183 ///
184 /// # Returns
185 /// * A new `ExecutionError::MemoryError`
186 ///
187 /// # Examples
188 ///
189 /// ```rust
190 /// let error = ExecutionError::new_memory_error("Heap allocation failed");
191 /// assert!(matches!(error, ExecutionError::MemoryError(_)));
192 /// ```
193 pub fn new_memory_error(message: impl Into<String>) -> Self {
194 ExecutionError::MemoryError(message.into())
195 }
196
197 /// Creates a new function error with the given message
198 ///
199 /// # Arguments
200 /// * `message` - The error message
201 ///
202 /// # Returns
203 /// * A new `ExecutionError::FunctionError`
204 ///
205 /// # Examples
206 ///
207 /// ```rust
208 /// let error = ExecutionError::new_function_error("Invalid function call");
209 /// assert!(matches!(error, ExecutionError::FunctionError(_)));
210 /// ```
211 pub fn new_function_error(message: impl Into<String>) -> Self {
212 ExecutionError::FunctionError(message.into())
213 }
214
215 /// Creates a new variable error with the given message
216 ///
217 /// # Arguments
218 /// * `message` - The error message
219 ///
220 /// # Returns
221 /// * A new `ExecutionError::VariableError`
222 ///
223 /// # Examples
224 ///
225 /// ```rust
226 /// let error = ExecutionError::new_variable_error("Variable not defined");
227 /// assert!(matches!(error, ExecutionError::VariableError(_)));
228 /// ```
229 pub fn new_variable_error(message: impl Into<String>) -> Self {
230 ExecutionError::VariableError(message.into())
231 }
232
233 /// Creates a new heap error with the given message
234 ///
235 /// # Arguments
236 /// * `message` - The error message
237 ///
238 /// # Returns
239 /// * A new `ExecutionError::HeapError`
240 ///
241 /// # Examples
242 ///
243 /// ```rust
244 /// let error = ExecutionError::new_heap_error("Garbage collection failed");
245 /// assert!(matches!(error, ExecutionError::HeapError(_)));
246 /// ```
247 pub fn new_heap_error(message: impl Into<String>) -> Self {
248 ExecutionError::HeapError(message.into())
249 }
250
251 /// Creates a new control flow error with the given message
252 ///
253 /// # Arguments
254 /// * `message` - The error message
255 ///
256 /// # Returns
257 /// * A new `ExecutionError::ControlFlowError`
258 ///
259 /// # Examples
260 ///
261 /// ```rust
262 /// let error = ExecutionError::new_control_flow_error("Invalid jump target");
263 /// assert!(matches!(error, ExecutionError::ControlFlowError(_)));
264 /// ```
265 pub fn new_control_flow_error(message: impl Into<String>) -> Self {
266 ExecutionError::ControlFlowError(message.into())
267 }
268
269 /// Creates a new built-in error with the given message
270 ///
271 /// # Arguments
272 /// * `message` - The error message
273 ///
274 /// # Returns
275 /// * A new `ExecutionError::BuiltinError`
276 ///
277 /// # Examples
278 ///
279 /// ```rust
280 /// let error = ExecutionError::new_builtin_error("Console not available");
281 /// assert!(matches!(error, ExecutionError::BuiltinError(_)));
282 /// ```
283 pub fn new_builtin_error(message: impl Into<String>) -> Self {
284 ExecutionError::BuiltinError(message.into())
285 }
286
287 /// Creates a new unsupported operation error with the given message
288 ///
289 /// # Arguments
290 /// * `message` - The error message
291 ///
292 /// # Returns
293 /// * A new `ExecutionError::UnsupportedOperation`
294 ///
295 /// # Examples
296 ///
297 /// ```rust
298 /// let error = ExecutionError::new_unsupported_operation("BigInt operations");
299 /// assert!(matches!(error, ExecutionError::UnsupportedOperation(_)));
300 /// ```
301 pub fn new_unsupported_operation(message: impl Into<String>) -> Self {
302 ExecutionError::UnsupportedOperation(message.into())
303 }
304
305 /// Checks if this error is recoverable
306 ///
307 /// Some errors can be recovered from automatically, while others
308 /// require manual intervention or indicate a serious problem.
309 ///
310 /// # Returns
311 /// * `true` if the error is recoverable
312 /// * `false` if the error requires manual intervention
313 ///
314 /// # Examples
315 ///
316 /// ```rust
317 /// let stack_error = ExecutionError::StackUnderflow;
318 /// assert!(stack_error.is_recoverable());
319 ///
320 /// let type_error = ExecutionError::TypeError("Invalid operation".to_string());
321 /// assert!(!type_error.is_recoverable());
322 /// ```
323 pub fn is_recoverable(&self) -> bool {
324 matches!(
325 self,
326 ExecutionError::StackUnderflow
327 | ExecutionError::StackOverflow
328 | ExecutionError::InvalidIndex(_)
329 | ExecutionError::PropertyNotFound(_)
330 | ExecutionError::MethodNotFound(_)
331 )
332 }
333
334 /// Checks if this error is fatal
335 ///
336 /// Fatal errors cannot be recovered from and typically indicate
337 /// a serious problem with the program or VM state.
338 ///
339 /// # Returns
340 /// * `true` if the error is fatal
341 /// * `false` if the error is not fatal
342 ///
343 /// # Examples
344 ///
345 /// ```rust
346 /// let memory_error = ExecutionError::MemoryError("Heap corruption".to_string());
347 /// assert!(memory_error.is_fatal());
348 ///
349 /// let stack_error = ExecutionError::StackUnderflow;
350 /// assert!(!stack_error.is_fatal());
351 /// ```
352 pub fn is_fatal(&self) -> bool {
353 matches!(
354 self,
355 ExecutionError::MemoryError(_)
356 | ExecutionError::InvalidInstruction(_)
357 | ExecutionError::RecursionLimitExceeded(_)
358 | ExecutionError::ExecutionTimeout
359 )
360 }
361
362 /// Gets a user-friendly error message
363 ///
364 /// Returns a formatted error message suitable for display to users.
365 ///
366 /// # Returns
367 /// * A formatted error message string
368 ///
369 /// # Examples
370 ///
371 /// ```rust
372 /// let error = ExecutionError::TypeError("Cannot add string and number".to_string());
373 /// let message = error.get_user_message();
374 /// assert!(message.contains("Type error"));
375 /// ```
376 pub fn get_user_message(&self) -> String {
377 match self {
378 ExecutionError::StackUnderflow => "Stack is empty".to_string(),
379 ExecutionError::StackOverflow => "Stack is full".to_string(),
380 ExecutionError::TypeError(msg) => format!("Type error: {}", msg),
381 ExecutionError::RuntimeError(msg) => format!("Runtime error: {}", msg),
382 ExecutionError::MemoryError(msg) => format!("Memory error: {}", msg),
383 ExecutionError::InvalidInstruction(msg) => format!("Invalid instruction: {}", msg),
384 ExecutionError::FunctionError(msg) => format!("Function error: {}", msg),
385 ExecutionError::VariableError(msg) => format!("Variable error: {}", msg),
386 ExecutionError::HeapError(msg) => format!("Heap error: {}", msg),
387 ExecutionError::ControlFlowError(msg) => format!("Control flow error: {}", msg),
388 ExecutionError::BuiltinError(msg) => format!("Built-in error: {}", msg),
389 ExecutionError::DivisionByZero => "Division by zero".to_string(),
390 ExecutionError::InvalidIndex(idx) => format!("Invalid index: {}", idx),
391 ExecutionError::PropertyNotFound(prop) => format!("Property not found: '{}'", prop),
392 ExecutionError::MethodNotFound(method) => format!("Method not found: '{}'", method),
393 ExecutionError::InvalidArgumentCount { expected, received } => {
394 format!("Invalid argument count: expected {}, received {}", expected, received)
395 }
396 ExecutionError::RecursionLimitExceeded(limit) => {
397 format!("Recursion limit exceeded: {}", limit)
398 }
399 ExecutionError::ExecutionTimeout => "Execution timeout".to_string(),
400 ExecutionError::UnsupportedOperation(op) => format!("Unsupported operation: {}", op),
401 }
402 }
403
404 /// Gets a debug error message
405 ///
406 /// Returns a detailed error message suitable for debugging and development.
407 ///
408 /// # Returns
409 /// * A detailed debug message string
410 ///
411 /// # Examples
412 ///
413 /// ```rust
414 /// let error = ExecutionError::TypeError("Cannot add string and number".to_string());
415 /// let debug_msg = error.get_debug_message();
416 /// assert!(debug_msg.contains("TypeError"));
417 /// ```
418 pub fn get_debug_message(&self) -> String {
419 format!("{:?}", self)
420 }
421}