rust_forth_compiler/
error.rs

1use rust_simple_stack_processor::{GasLimit, StackMachineError};
2use thiserror::Error;
3
4/// This Enum lists the errors that the Forth Interpreter might return
5#[derive(Debug, Error)]
6pub enum ForthError {
7    #[error("Unknown error occurred")]
8    UnknownError,
9    #[error("Unknown token: {0}")]
10    UnknownToken(String),
11    #[error("Number stack underflow")]
12    NumberStackUnderflow,
13    #[error("Loop stack underflow")]
14    LoopStackUnderflow,
15    #[error("Scratch stack underflow")]
16    ScratchStackUnderflow,
17    #[error("Invalid cell operation")]
18    InvalidCellOperation,
19    #[error("Invalid syntax: {0}")]
20    InvalidSyntax(String),
21    #[error("Missing semicolon after colon")]
22    MissingSemicolonAfterColon,
23    #[error("Missing command after colon")]
24    MissingCommandAfterColon,
25    #[error("Semicolon before colon")]
26    SemicolonBeforeColon,
27    #[error("Unhandled trap ID: {unhandled_trap_id}")]
28    UnhandledTrap { unhandled_trap_id: i64 },
29    #[error("Ran out of gas: used {gas_used}, limit {gas_limit:?}")]
30    RanOutOfGas { gas_used: u64, gas_limit: GasLimit },
31    #[error("Internal numeric overflow")]
32    InternalNumericOverflow,
33}
34
35/// Convert StackMachineError to a ForthError so our Interpreter functions can
36/// return a single Error type.
37impl From<StackMachineError> for ForthError {
38    fn from(err: StackMachineError) -> ForthError {
39        match err {
40            StackMachineError::NumberStackUnderflow => ForthError::NumberStackUnderflow,
41            StackMachineError::LoopStackUnderflow => ForthError::LoopStackUnderflow,
42            StackMachineError::ScratchStackUnderflow => ForthError::ScratchStackUnderflow,
43            StackMachineError::InvalidCellOperation => ForthError::InvalidCellOperation,
44            StackMachineError::UnknownError => ForthError::UnknownError,
45            StackMachineError::UnhandledTrap { unhandled_trap_id } => {
46                ForthError::UnhandledTrap { unhandled_trap_id }
47            }
48            StackMachineError::RanOutOfGas {
49                gas_used,
50                gas_limit,
51            } => ForthError::RanOutOfGas {
52                gas_used,
53                gas_limit,
54            },
55            StackMachineError::NumericOverflow { failing_opcode: _ } => {
56                ForthError::InternalNumericOverflow
57            }
58            StackMachineError::DivisionByZero { failing_opcode: _ } => {
59                ForthError::InternalNumericOverflow
60            }
61            StackMachineError::TryFromIntError(_) => ForthError::InternalNumericOverflow,
62        }
63    }
64}
65
66/// Helper to convert ForthError codes to numeric codes for exit()
67impl From<ForthError> for i32 {
68    fn from(err: ForthError) -> Self {
69        match err {
70            ForthError::UnknownError => 2,
71            ForthError::UnknownToken(_) => 3,
72            ForthError::NumberStackUnderflow => 4,
73            ForthError::LoopStackUnderflow => 5,
74            ForthError::ScratchStackUnderflow => 13,
75            ForthError::InvalidCellOperation => 14,
76            ForthError::InvalidSyntax(_) => 6,
77            ForthError::MissingSemicolonAfterColon => 7,
78            ForthError::MissingCommandAfterColon => 8,
79            ForthError::SemicolonBeforeColon => 9,
80            ForthError::UnhandledTrap {
81                unhandled_trap_id: _,
82            } => 10,
83            ForthError::RanOutOfGas {
84                gas_used: _,
85                gas_limit: _,
86            } => 11,
87            ForthError::InternalNumericOverflow => 12,
88        }
89    }
90}