rib/interpreter/
rib_runtime_error.rs

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