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}