1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! Errors from variable assignments or operations.

use std::{error::Error, fmt};

use crate::line::Variable;

use std::cmp::Ordering;

impl Error for VariableError {}

#[derive(Clone, Debug)]
/// Error from invalid variable assignments or operations.
pub struct VariableError {
    /// Variable that caused or detected the error.
    pub variable: Variable,
    /// Error variant.
    pub kind: VariableErrorKind,
}

impl VariableError {
    pub(crate) fn from_kind<T: Into<Variable>>(variable: T, kind: VariableErrorKind) -> Self {
        VariableError {
            variable: variable.into(),
            kind,
        }
    }
}

#[derive(Clone, Debug)]
/// Error variant for variable type errors.
pub enum VariableErrorKind {
    /// Divided with or took the remainer from 0.
    DividedByZero {
        /// Zero-valued variable in the operation.
        other: Variable,
        /// Character representation of the operation that caused the error (`/`, `%`).
        operator: char,
    },
    /// Two variables could not be compared to each other like this.
    InvalidComparison {
        /// Other variable in the comparison.
        other: Variable,
        /// Type of comparison betweeen `variable` and `other`.
        comparison: Ordering,
    },
    /// Tried to operate on the variable with an operation that is not allowed for it.
    InvalidOperation {
        /// Other variable in the operation.
        other: Variable,
        /// Character representation of operation (`+`, `-`, `*`, `/`, `%`).
        operator: char,
    },
    /// A new variable type was attempted to be assigned to the current variable.
    NonMatchingAssignment {
        /// Variable that was to be assigned but has non-matching type.
        other: Variable,
    },
}

impl fmt::Display for VariableError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use VariableErrorKind::*;

        let variable = &self.variable;

        match &self.kind {
            DividedByZero { other, operator } => write!(
                f,
                "Attempted to divide by 0 in the operation '{} {} {}'",
                variable.to_string_simple(),
                operator,
                other.to_string_simple()
            ),
            InvalidComparison { other, comparison } => {
                let operator = match comparison {
                    Ordering::Equal => "==",
                    Ordering::Less => ">",
                    Ordering::Greater => "<",
                };

                write!(
                    f,
                    "Cannot compare variable of type '{}' to '{}' using the '{op}' operator \
                     (in: '{} {op} {}')",
                    variable.variant_string(),
                    other.variant_string(),
                    variable.to_string_simple(),
                    other.to_string_simple(),
                    op = operator
                )
            }
            InvalidOperation { other, operator } => write!(
                f,
                "Operation '{op}' is not allowed between variables of type '{}' and '{}' \
                 (in: '{} {op} {}')",
                variable.variant_string(),
                other.variant_string(),
                variable.to_string_simple(),
                other.to_string_simple(),
                op = operator
            ),
            NonMatchingAssignment { other } => write!(
                f,
                "Cannot assign a value of type '{}' to a variable of type '{}' \
                 (variables cannot change type)",
                other.variant_string(),
                variable.variant_string()
            ),
        }
    }
}