Skip to main content

rib/interpreter/
rib_runtime_error.rs

1use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue;
2use crate::{InstructionId, TypeHint};
3use crate::{Value, ValueAndType};
4use std::fmt::{Display, Formatter};
5
6#[derive(Debug)]
7pub enum RibRuntimeError {
8    ArithmeticError {
9        message: String,
10    },
11    CastError {
12        from: CastFrom,
13        to: TypeHint,
14    },
15    ExhaustedIterator,
16    FieldNotFound {
17        field: String,
18    },
19    FunctionInvokeError {
20        function_name: String,
21        error: Box<dyn std::error::Error + Send + Sync>,
22    },
23    IndexOutOfBound {
24        index: usize,
25        size: usize,
26    },
27    InfiniteComputation {
28        message: String,
29    },
30    InputNotFound(String),
31    InvariantViolation(InvariantViolation),
32    InvalidComparison {
33        message: String,
34        left: Option<ValueAndType>,
35        right: Option<ValueAndType>,
36    },
37    NoResult,
38    ThrownError(String),
39    TypeMismatch {
40        expected: Vec<TypeHint>,
41        found: InvalidItem,
42    },
43}
44
45impl std::error::Error for RibRuntimeError {}
46
47#[derive(Debug, Clone, PartialEq)]
48pub enum CastFrom {
49    FromValue(Value),
50    FromType(TypeHint),
51    FromCustom(String),
52}
53
54impl Display for CastFrom {
55    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
56        match self {
57            CastFrom::FromValue(value) => write!(f, "{value:?}"),
58            CastFrom::FromType(typ) => write!(f, "{typ}"),
59            CastFrom::FromCustom(custom) => write!(f, "{custom}"),
60        }
61    }
62}
63
64#[derive(Debug, Clone, PartialEq)]
65pub enum InvalidItem {
66    RuntimeValue(Value),
67    Type(TypeHint),
68    Custom(String),
69}
70
71pub fn arithmetic_error(message: &str) -> RibRuntimeError {
72    RibRuntimeError::ArithmeticError {
73        message: message.to_string(),
74    }
75}
76
77pub fn cast_error(from: Value, to: TypeHint) -> RibRuntimeError {
78    RibRuntimeError::CastError {
79        from: CastFrom::FromValue(from),
80        to,
81    }
82}
83
84pub fn cast_error_custom<T: Display>(from: T, to: TypeHint) -> RibRuntimeError {
85    RibRuntimeError::CastError {
86        from: CastFrom::FromCustom(from.to_string()),
87        to,
88    }
89}
90
91pub fn empty_stack() -> RibRuntimeError {
92    RibRuntimeError::InvariantViolation(InvariantViolation::InsufficientStackItems(1))
93}
94
95pub fn exhausted_iterator() -> RibRuntimeError {
96    RibRuntimeError::ExhaustedIterator
97}
98
99pub fn field_not_found(field_name: &str) -> RibRuntimeError {
100    RibRuntimeError::FieldNotFound {
101        field: field_name.to_string(),
102    }
103}
104
105pub fn function_invoke_fail(
106    function_name: &str,
107    error: Box<dyn std::error::Error + Send + Sync>,
108) -> RibRuntimeError {
109    RibRuntimeError::FunctionInvokeError {
110        function_name: function_name.to_string(),
111        error,
112    }
113}
114
115pub fn index_out_of_bound(index: usize, size: usize) -> RibRuntimeError {
116    RibRuntimeError::IndexOutOfBound { index, size }
117}
118
119pub fn infinite_computation(message: &str) -> RibRuntimeError {
120    RibRuntimeError::InfiniteComputation {
121        message: message.to_string(),
122    }
123}
124
125pub fn input_not_found(input_name: &str) -> RibRuntimeError {
126    RibRuntimeError::InputNotFound(input_name.to_string())
127}
128
129pub fn instruction_jump_error(instruction_id: InstructionId) -> RibRuntimeError {
130    RibRuntimeError::InvariantViolation(InvariantViolation::InstructionJumpError(instruction_id))
131}
132
133pub fn insufficient_stack_items(size: usize) -> RibRuntimeError {
134    RibRuntimeError::InvariantViolation(InvariantViolation::InsufficientStackItems(size))
135}
136
137pub fn invalid_comparison(
138    message: &str,
139    left: Option<ValueAndType>,
140    right: Option<ValueAndType>,
141) -> RibRuntimeError {
142    RibRuntimeError::InvalidComparison {
143        message: message.to_string(),
144        left,
145        right,
146    }
147}
148
149pub fn invalid_type_with_stack_value(
150    expected: Vec<TypeHint>,
151    found: RibInterpreterStackValue,
152) -> RibRuntimeError {
153    RibRuntimeError::TypeMismatch {
154        expected,
155        found: InvalidItem::Custom(found.to_string()),
156    }
157}
158
159pub fn type_mismatch_with_value(expected: Vec<TypeHint>, found: Value) -> RibRuntimeError {
160    RibRuntimeError::TypeMismatch {
161        expected,
162        found: InvalidItem::RuntimeValue(found),
163    }
164}
165
166pub fn type_mismatch_with_type_hint(expected: Vec<TypeHint>, found: TypeHint) -> RibRuntimeError {
167    RibRuntimeError::TypeMismatch {
168        expected,
169        found: InvalidItem::Type(found),
170    }
171}
172
173pub fn no_result() -> RibRuntimeError {
174    RibRuntimeError::NoResult
175}
176
177pub fn throw_error(message: &str) -> RibRuntimeError {
178    RibRuntimeError::ThrownError(message.to_string())
179}
180
181#[derive(Debug, Clone, PartialEq)]
182pub enum InvariantViolation {
183    InsufficientStackItems(usize),
184    InternalCorruptedState(String),
185    InstructionJumpError(InstructionId),
186}
187
188impl Display for RibRuntimeError {
189    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190        match self {
191            RibRuntimeError::InputNotFound(input_name) => {
192                write!(f, "input not found: {input_name}")
193            }
194            RibRuntimeError::ExhaustedIterator => write!(f, "no more values in iterator"),
195            RibRuntimeError::FieldNotFound { field } => {
196                write!(f, "field not found: {field}")
197            }
198            RibRuntimeError::InvariantViolation(violation) => {
199                write!(f, "internal error: {violation:?}")
200            }
201            RibRuntimeError::ThrownError(message) => write!(f, "error: {message}"),
202            RibRuntimeError::CastError { from, to } => {
203                write!(f, "cast error from {from} to {to}")
204            }
205            RibRuntimeError::TypeMismatch { expected, found } => {
206                write!(
207                    f,
208                    "runtime type mismatch: expected {expected:?}, found {found:?}"
209                )
210            }
211            RibRuntimeError::NoResult => write!(f, "No result"),
212            RibRuntimeError::InfiniteComputation { message } => {
213                write!(f, "infinite computation detected: {message}")
214            }
215            RibRuntimeError::IndexOutOfBound { index, size } => {
216                write!(f, "index out of bound: {index} (size: {size})")
217            }
218            RibRuntimeError::InvalidComparison {
219                message,
220                left,
221                right,
222            } => match (left, right) {
223                (Some(left), Some(right)) => {
224                    write!(
225                        f,
226                        "Invalid comparison: {message} (left: {left}, right: {right})"
227                    )
228                }
229                _ => {
230                    write!(f, "Invalid comparison: {message} ")
231                }
232            },
233            RibRuntimeError::ArithmeticError { message } => {
234                write!(f, "arithmetic error: {message}")
235            }
236            RibRuntimeError::FunctionInvokeError {
237                function_name,
238                error,
239            } => {
240                write!(f, "failed to invoke function {function_name}: {error}")
241            }
242        }
243    }
244}