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
112
113
114
115
116
117
118
119
120
121
use std::fmt::{
    self,
    Debug,
    Display
};

use crate::grammar::{
    NonterminalValue,
    TerminalValue,
    Symbol
};

//
// Interface
//

//
// ErrorKind<Nt, T>: Debug + Copy
//

/// Enumerates kinds of possible errors during expansion.
#[allow(clippy::module_name_repetitions)]
#[derive(Clone, Copy)]
pub enum ErrorKind<Nt>
    where Nt: NonterminalValue
{
    NontermExpansionFailed(Nt),
    MaxIterationsReached(usize)
}

impl<Nt> Debug for ErrorKind<Nt>
    where Nt: NonterminalValue
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NontermExpansionFailed(_) =>  write!(
                f, "NontermExpansionFailed(_)"
            ),
            Self::MaxIterationsReached(iterations) => write!(
                f, "MaxIterationsReached({})", iterations
            )
        }
    }
}

//
// Error<Nt, T>: Error
//

/// Used as error variant for [`Result`](type.Result.html).
///
/// The reason for the error can be determined via the [`kind`](struct.Error.html#structfield.kind) field.
pub struct Error<Nt, T>
    where Nt: NonterminalValue,
          T:  TerminalValue
{
    pub state: Vec<Symbol<Nt, T>>,
    pub kind:  ErrorKind<Nt>
}

impl<Nt, T> Debug for Error<Nt, T>
    where Nt: NonterminalValue,
          T:  TerminalValue
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Error {{ state, kind: {:?} }}", self.kind)
    }
}

impl<Nt, T> Display for Error<Nt, T>
    where Nt: NonterminalValue,
          T:  TerminalValue
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.kind {
            ErrorKind::NontermExpansionFailed(_) => write!(
                f, "no rule to expand nonterminal symbol"
            ),
            ErrorKind::MaxIterationsReached(iterations) => write!(
                f,
                "reached the maximum {} iterations with {} nonterminal symbols still unexpanded",
                iterations,
                self.state.iter()
                    .filter(|symbol| symbol.is_nonterminal())
                    .count()
            )
        }
    }
}

impl<Nt, T> std::error::Error for Error<Nt, T> 
    where Nt: NonterminalValue,
          T:  TerminalValue
{
    // Default
}

impl<Nt, T> Error<Nt, T>
    where Nt: NonterminalValue,
          T:  TerminalValue
{
    //
    // Interface
    //

    pub fn nonterm_expansion_failed(state: Vec<Symbol<Nt, T>>, expanded_nonterm_value: Nt) -> Self {
        Self::new(state, ErrorKind::NontermExpansionFailed(expanded_nonterm_value))
    }

    pub fn max_iterations_reached(state: Vec<Symbol<Nt, T>>, iterations: usize) -> Self {
        Self::new(state, ErrorKind::MaxIterationsReached(iterations))
    }

    //
    // Service
    //

    fn new(state: Vec<Symbol<Nt, T>>, kind: ErrorKind<Nt>) -> Self {
        Self{state, kind}
    }
}