inkling/error/parse/
condition.rs

1//! Errors from parsing conditions in lines.
2
3use std::{error::Error, fmt};
4
5use crate::error::parse::{expression::ExpressionError, variable::VariableError};
6
7#[derive(Debug)]
8/// Error from parsing `Condition` objects.
9pub struct ConditionError {
10    /// Content of string that caused the error.
11    pub content: String,
12    /// Error variant.
13    pub kind: ConditionErrorKind,
14}
15
16#[derive(Debug)]
17/// Variant of `Condition` parsing error.
18pub enum ConditionErrorKind {
19    /// The first item in a condition was not `Blank` or any other item was not `And` or `Or`.
20    ///
21    /// This is an internal consistency check from parsing a condition. Every subsequent
22    /// condition to the first should be preceeded by an `and` or `or` marker, while the
23    /// first condition should not be. After parsing the condition we assert that this is true.
24    /// If not, some internal shenanigans are going on, but this should be unreachable.
25    BadLink,
26    /// Could not parse a number from the condition.
27    BadValue,
28    /// Generic error.
29    CouldNotParse,
30    /// Could not parse an expression for either side of a `lhs (cmp) rhs` condition.
31    InvalidExpression(ExpressionError),
32    /// Could not parse a variable.
33    InvalidVariable(VariableError),
34    /// The line had multiple else statements.
35    MultipleElseStatements,
36    /// There was no condition in the line.
37    NoCondition,
38    /// Found unmatched parenthesis.
39    UnmatchedParenthesis,
40}
41
42impl Error for ConditionError {
43    fn source(&self) -> Option<&(dyn Error + 'static)> {
44        Some(&self.kind)
45    }
46}
47
48impl Error for ConditionErrorKind {
49    fn source(&self) -> Option<&(dyn Error + 'static)> {
50        match &self {
51            ConditionErrorKind::InvalidVariable(err) => Some(err),
52            _ => None,
53        }
54    }
55}
56
57impl_from_error![
58    ConditionErrorKind;
59    [InvalidExpression, ExpressionError],
60    [InvalidVariable, VariableError]
61];
62
63impl fmt::Display for ConditionError {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        write!(f, "{} (condition string: '{}')", &self.kind, &self.content)
66    }
67}
68
69impl fmt::Display for ConditionErrorKind {
70    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71        use ConditionErrorKind::*;
72
73        match &self {
74            BadLink => write!(
75                f,
76                "internal error: did not correctly partition conditions into parts separated \
77                 by `and`/`or` markers"
78            ),
79            BadValue => write!(f, "could not parse a number from the condition value"),
80            CouldNotParse => write!(f, "incorrectly formatted condition"),
81            InvalidExpression(err) => write!(
82                f,
83                "could not parse left or right hand side expression for a comparison: {}",
84                err
85            ),
86            InvalidVariable(err) => write!(f, "could not parse variable in condition: {}", err),
87            MultipleElseStatements => write!(f, "found multiple else statements in condition"),
88            NoCondition => write!(f, "condition string was empty"),
89            UnmatchedParenthesis => write!(f, "contained unmatched parenthesis"),
90        }
91    }
92}
93
94impl ConditionError {
95    /// Quickly construct an error from the kind and line.
96    pub(crate) fn from_kind<T: Into<String>>(content: T, kind: ConditionErrorKind) -> Self {
97        ConditionError {
98            content: content.into(),
99            kind,
100        }
101    }
102}