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}