Skip to main content

inkling/error/runtime/
variable.rs

1//! Errors from variable assignments or operations.
2
3use std::{error::Error, fmt};
4
5use crate::line::Variable;
6
7use std::cmp::Ordering;
8
9impl Error for VariableError {}
10
11#[derive(Clone, Debug)]
12/// Error from invalid variable assignments or operations.
13pub struct VariableError {
14    /// Variable that caused or detected the error.
15    pub variable: Variable,
16    /// Error variant.
17    pub kind: VariableErrorKind,
18}
19
20impl VariableError {
21    pub(crate) fn from_kind<T: Into<Variable>>(variable: T, kind: VariableErrorKind) -> Self {
22        VariableError {
23            variable: variable.into(),
24            kind,
25        }
26    }
27}
28
29#[derive(Clone, Debug)]
30/// Error variant for variable type errors.
31pub enum VariableErrorKind {
32    /// Divided with or took the remainer from 0.
33    DividedByZero {
34        /// Zero-valued variable in the operation.
35        other: Variable,
36        /// Character representation of the operation that caused the error (`/`, `%`).
37        operator: char,
38    },
39    /// Two variables could not be compared to each other like this.
40    InvalidComparison {
41        /// Other variable in the comparison.
42        other: Variable,
43        /// Type of comparison betweeen `variable` and `other`.
44        comparison: Ordering,
45    },
46    /// Tried to operate on the variable with an operation that is not allowed for it.
47    InvalidOperation {
48        /// Other variable in the operation.
49        other: Variable,
50        /// Character representation of operation (`+`, `-`, `*`, `/`, `%`).
51        operator: char,
52    },
53    /// A new variable type was attempted to be assigned to the current variable.
54    NonMatchingAssignment {
55        /// Variable that was to be assigned but has non-matching type.
56        other: Variable,
57    },
58}
59
60impl fmt::Display for VariableError {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        use VariableErrorKind::*;
63
64        let variable = &self.variable;
65
66        match &self.kind {
67            DividedByZero { other, operator } => write!(
68                f,
69                "Attempted to divide by 0 in the operation '{} {} {}'",
70                variable.to_string_simple(),
71                operator,
72                other.to_string_simple()
73            ),
74            InvalidComparison { other, comparison } => {
75                let operator = match comparison {
76                    Ordering::Equal => "==",
77                    Ordering::Less => ">",
78                    Ordering::Greater => "<",
79                };
80
81                write!(
82                    f,
83                    "Cannot compare variable of type '{}' to '{}' using the '{op}' operator \
84                     (in: '{} {op} {}')",
85                    variable.variant_string(),
86                    other.variant_string(),
87                    variable.to_string_simple(),
88                    other.to_string_simple(),
89                    op = operator
90                )
91            }
92            InvalidOperation { other, operator } => write!(
93                f,
94                "Operation '{op}' is not allowed between variables of type '{}' and '{}' \
95                 (in: '{} {op} {}')",
96                variable.variant_string(),
97                other.variant_string(),
98                variable.to_string_simple(),
99                other.to_string_simple(),
100                op = operator
101            ),
102            NonMatchingAssignment { other } => write!(
103                f,
104                "Cannot assign a value of type '{}' to a variable of type '{}' \
105                 (variables cannot change type)",
106                other.variant_string(),
107                variable.variant_string()
108            ),
109        }
110    }
111}