fastn_resolved/evalexpr/error/mod.rs
1//! The `error` module contains the `Error` enum that contains all error types used by this crate.
2//!
3//! The `Error` enum implements constructors for its struct variants, because those are ugly to construct.
4//!
5//! The module also contains some helper functions starting with `expect_` that check for a condition and return `Err(_)` if the condition is not fulfilled.
6//! They are meant as shortcuts to not write the same error checking code everywhere.
7
8use fastn_resolved::evalexpr::{token::PartialToken, value::value_type::ValueType};
9
10use fastn_resolved::evalexpr::{operator::Operator, value::Value};
11
12// Exclude error display code from test coverage, as the code does not make sense to test.
13mod display;
14
15/// Errors used in this crate.
16#[derive(Debug, PartialEq)]
17#[non_exhaustive]
18pub enum EvalexprError {
19 /// An operator was called with a wrong amount of arguments.
20 WrongOperatorArgumentAmount {
21 /// The expected amount of arguments.
22 expected: usize,
23 /// The actual amount of arguments.
24 actual: usize,
25 },
26
27 /// A function was called with a wrong amount of arguments.
28 WrongFunctionArgumentAmount {
29 /// The expected amount of arguments.
30 expected: usize,
31 /// The actual amount of arguments.
32 actual: usize,
33 },
34
35 /// A string value was expected.
36 ExpectedString {
37 /// The actual value.
38 actual: Value,
39 },
40
41 /// An integer value was expected.
42 ExpectedInt {
43 /// The actual value.
44 actual: Value,
45 },
46
47 /// A float value was expected.
48 ExpectedFloat {
49 /// The actual value.
50 actual: Value,
51 },
52
53 /// A numeric value was expected.
54 /// Numeric values are the variants `Value::Int` and `Value::Float`.
55 ExpectedNumber {
56 /// The actual value.
57 actual: Value,
58 },
59
60 /// A numeric or string value was expected.
61 /// Numeric values are the variants `Value::Int` and `Value::Float`.
62 ExpectedNumberOrString {
63 /// The actual value.
64 actual: Value,
65 },
66
67 /// A boolean value was expected.
68 ExpectedBoolean {
69 /// The actual value.
70 actual: Value,
71 },
72
73 /// A tuple value was expected.
74 ExpectedTuple {
75 /// The actual value.
76 actual: Value,
77 },
78
79 /// A tuple value of a certain length was expected.
80 ExpectedFixedLenTuple {
81 /// The expected len
82 expected_len: usize,
83 /// The actual value.
84 actual: Value,
85 },
86
87 /// An empty value was expected.
88 ExpectedEmpty {
89 /// The actual value.
90 actual: Value,
91 },
92
93 /// Tried to append a child to a leaf node.
94 /// Leaf nodes cannot have children.
95 AppendedToLeafNode,
96
97 /// Tried to append a child to a node such that the precedence of the child is not higher.
98 /// This error should never occur.
99 /// If it does, please file a bug report.
100 PrecedenceViolation,
101
102 /// A `VariableIdentifier` operation did not find its value in the context.
103 VariableIdentifierNotFound(String),
104
105 /// A `FunctionIdentifier` operation did not find its value in the context.
106 FunctionIdentifierNotFound(String),
107
108 /// A value has the wrong type.
109 /// Only use this if there is no other error that describes the expected and provided types in more detail.
110 TypeError {
111 /// The expected types.
112 expected: Vec<ValueType>,
113 /// The actual value.
114 actual: Value,
115 },
116
117 /// An operator is used with a wrong combination of types.
118 WrongTypeCombination {
119 /// The operator that whose evaluation caused the error.
120 operator: Operator,
121 /// The types that were used in the operator causing it to fail.
122 actual: Vec<ValueType>,
123 },
124
125 /// An opening brace without a matching closing brace was found.
126 UnmatchedLBrace,
127
128 /// A closing brace without a matching opening brace was found.
129 UnmatchedRBrace,
130
131 /// Left of an opening brace or right of a closing brace is a token that does not expect the brace next to it.
132 /// For example, writing `4(5)` would yield this error, as the `4` does not have any operands.
133 MissingOperatorOutsideOfBrace,
134
135 /// A `PartialToken` is unmatched, such that it cannot be combined into a full `Token`.
136 /// This happens if for example a single `=` is found, surrounded by whitespace.
137 /// It is not a token, but it is part of the string representation of some tokens.
138 UnmatchedPartialToken {
139 /// The unmatched partial token.
140 first: PartialToken,
141 /// The token that follows the unmatched partial token and that cannot be matched to the partial token, or `None`, if `first` is the last partial token in the stream.
142 second: Option<PartialToken>,
143 },
144
145 /// An addition operation performed by Rust failed.
146 AdditionError {
147 /// The first argument of the addition.
148 augend: Value,
149 /// The second argument of the addition.
150 addend: Value,
151 },
152
153 /// A subtraction operation performed by Rust failed.
154 SubtractionError {
155 /// The first argument of the subtraction.
156 minuend: Value,
157 /// The second argument of the subtraction.
158 subtrahend: Value,
159 },
160
161 /// A negation operation performed by Rust failed.
162 NegationError {
163 /// The argument of the negation.
164 argument: Value,
165 },
166
167 /// A multiplication operation performed by Rust failed.
168 MultiplicationError {
169 /// The first argument of the multiplication.
170 multiplicand: Value,
171 /// The second argument of the multiplication.
172 multiplier: Value,
173 },
174
175 /// A division operation performed by Rust failed.
176 DivisionError {
177 /// The first argument of the division.
178 dividend: Value,
179 /// The second argument of the division.
180 divisor: Value,
181 },
182
183 /// A modulation operation performed by Rust failed.
184 ModulationError {
185 /// The first argument of the modulation.
186 dividend: Value,
187 /// The second argument of the modulation.
188 divisor: Value,
189 },
190
191 /// A regular expression could not be parsed
192 InvalidRegex {
193 /// The invalid regular expression
194 regex: String,
195 /// Failure message from the regex engine
196 message: String,
197 },
198
199 /// A modification was attempted on a `Context` that does not allow modifications.
200 ContextNotMutable,
201
202 /// An escape sequence within a string literal is illegal.
203 IllegalEscapeSequence(String),
204
205 /// A custom error explained by its message.
206 CustomMessage(String),
207}
208
209impl EvalexprError {
210 pub(crate) fn wrong_operator_argument_amount(actual: usize, expected: usize) -> Self {
211 EvalexprError::WrongOperatorArgumentAmount { actual, expected }
212 }
213
214 pub(crate) fn wrong_function_argument_amount(actual: usize, expected: usize) -> Self {
215 EvalexprError::WrongFunctionArgumentAmount { actual, expected }
216 }
217
218 /// Constructs `EvalexprError::TypeError{actual, expected}`.
219 pub fn type_error(actual: Value, expected: Vec<ValueType>) -> Self {
220 EvalexprError::TypeError { actual, expected }
221 }
222
223 /// Constructs `EvalexprError::WrongTypeCombination{operator, actual}`.
224 pub fn wrong_type_combination(operator: Operator, actual: Vec<ValueType>) -> Self {
225 EvalexprError::WrongTypeCombination { operator, actual }
226 }
227
228 /// Constructs `EvalexprError::ExpectedString{actual}`.
229 pub fn expected_string(actual: Value) -> Self {
230 EvalexprError::ExpectedString { actual }
231 }
232
233 /// Constructs `EvalexprError::ExpectedInt{actual}`.
234 pub fn expected_int(actual: Value) -> Self {
235 EvalexprError::ExpectedInt { actual }
236 }
237
238 /// Constructs `EvalexprError::ExpectedFloat{actual}`.
239 pub fn expected_float(actual: Value) -> Self {
240 EvalexprError::ExpectedFloat { actual }
241 }
242
243 /// Constructs `EvalexprError::ExpectedNumber{actual}`.
244 pub fn expected_number(actual: Value) -> Self {
245 EvalexprError::ExpectedNumber { actual }
246 }
247
248 /// Constructs `EvalexprError::ExpectedNumberOrString{actual}`.
249 pub fn expected_number_or_string(actual: Value) -> Self {
250 EvalexprError::ExpectedNumberOrString { actual }
251 }
252
253 /// Constructs `EvalexprError::ExpectedBoolean{actual}`.
254 pub fn expected_boolean(actual: Value) -> Self {
255 EvalexprError::ExpectedBoolean { actual }
256 }
257
258 /// Constructs `EvalexprError::ExpectedTuple{actual}`.
259 pub fn expected_tuple(actual: Value) -> Self {
260 EvalexprError::ExpectedTuple { actual }
261 }
262
263 /// Constructs `EvalexprError::ExpectedFixedLenTuple{expected_len, actual}`.
264 pub fn expected_fixed_len_tuple(expected_len: usize, actual: Value) -> Self {
265 EvalexprError::ExpectedFixedLenTuple {
266 expected_len,
267 actual,
268 }
269 }
270
271 /// Constructs `EvalexprError::ExpectedEmpty{actual}`.
272 pub fn expected_empty(actual: Value) -> Self {
273 EvalexprError::ExpectedEmpty { actual }
274 }
275
276 /// Constructs an error that expresses that the type of `expected` was expected, but `actual` was found.
277 pub(crate) fn expected_type(expected: &Value, actual: Value) -> Self {
278 match ValueType::from(expected) {
279 ValueType::String => Self::expected_string(actual),
280 ValueType::Int => Self::expected_int(actual),
281 ValueType::Float => Self::expected_float(actual),
282 ValueType::Boolean => Self::expected_boolean(actual),
283 ValueType::Tuple => Self::expected_tuple(actual),
284 ValueType::Empty => Self::expected_empty(actual),
285 }
286 }
287
288 pub(crate) fn unmatched_partial_token(
289 first: PartialToken,
290 second: Option<PartialToken>,
291 ) -> Self {
292 EvalexprError::UnmatchedPartialToken { first, second }
293 }
294
295 pub(crate) fn addition_error(augend: Value, addend: Value) -> Self {
296 EvalexprError::AdditionError { augend, addend }
297 }
298
299 pub(crate) fn subtraction_error(minuend: Value, subtrahend: Value) -> Self {
300 EvalexprError::SubtractionError {
301 minuend,
302 subtrahend,
303 }
304 }
305
306 pub(crate) fn negation_error(argument: Value) -> Self {
307 EvalexprError::NegationError { argument }
308 }
309
310 pub(crate) fn multiplication_error(multiplicand: Value, multiplier: Value) -> Self {
311 EvalexprError::MultiplicationError {
312 multiplicand,
313 multiplier,
314 }
315 }
316
317 pub(crate) fn division_error(dividend: Value, divisor: Value) -> Self {
318 EvalexprError::DivisionError { dividend, divisor }
319 }
320
321 pub(crate) fn modulation_error(dividend: Value, divisor: Value) -> Self {
322 EvalexprError::ModulationError { dividend, divisor }
323 }
324
325 /// Constructs `EvalexprError::InvalidRegex(regex)`
326 pub fn invalid_regex(regex: String, message: String) -> Self {
327 EvalexprError::InvalidRegex { regex, message }
328 }
329}
330
331/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongOperatorArgumentAmount)` otherwise.
332pub(crate) fn expect_operator_argument_amount(
333 actual: usize,
334 expected: usize,
335) -> EvalexprResult<()> {
336 if actual == expected {
337 Ok(())
338 } else {
339 Err(EvalexprError::wrong_operator_argument_amount(
340 actual, expected,
341 ))
342 }
343}
344
345/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise.
346pub fn expect_function_argument_amount(actual: usize, expected: usize) -> EvalexprResult<()> {
347 if actual == expected {
348 Ok(())
349 } else {
350 Err(EvalexprError::wrong_function_argument_amount(
351 actual, expected,
352 ))
353 }
354}
355
356/// Returns `Ok(())` if the given value is a string or a numeric
357pub fn expect_number_or_string(actual: &Value) -> EvalexprResult<()> {
358 match actual {
359 Value::String(_) | Value::Float(_) | Value::Int(_) => Ok(()),
360 _ => Err(EvalexprError::expected_number_or_string(actual.clone())),
361 }
362}
363
364impl std::error::Error for EvalexprError {}
365
366/// Standard result type used by this crate.
367pub type EvalexprResult<T> = Result<T, EvalexprError>;
368
369#[cfg(test)]
370mod tests {
371 use fastn_resolved::evalexpr::{EvalexprError, Value, ValueType};
372
373 /// Tests whose only use is to bring test coverage of trivial lines up, like trivial constructors.
374 #[test]
375 fn trivial_coverage_tests() {
376 assert_eq!(
377 EvalexprError::type_error(Value::Int(3), vec![ValueType::String]),
378 EvalexprError::TypeError {
379 actual: Value::Int(3),
380 expected: vec![ValueType::String]
381 }
382 );
383 assert_eq!(
384 EvalexprError::expected_type(&Value::String("abc".to_string()), Value::Empty),
385 EvalexprError::expected_string(Value::Empty)
386 );
387 assert_eq!(
388 EvalexprError::expected_type(&Value::Boolean(false), Value::Empty),
389 EvalexprError::expected_boolean(Value::Empty)
390 );
391 assert_eq!(
392 EvalexprError::expected_type(&Value::Tuple(vec![]), Value::Empty),
393 EvalexprError::expected_tuple(Value::Empty)
394 );
395 assert_eq!(
396 EvalexprError::expected_type(&Value::Empty, Value::String("abc".to_string())),
397 EvalexprError::expected_empty(Value::String("abc".to_string()))
398 );
399 }
400}