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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//
// Interface traits
//

//
// NonterminalValue: Clone + PartialEq
//

/// Describes requirements for types of non-terminal symbol values.
///
/// Any type that is cloneable and comparable by `==` automatically satisfies `NonterminalValue`.
pub trait NonterminalValue: Clone + PartialEq {
    // Empty
}

impl<Nt> NonterminalValue for Nt
    where Nt: Clone + PartialEq {
    // Empty
}

//
// TerminalValue: Clone
//

/// Describes requirements for types of terminal symbol values.
///
/// Any cloneable type automatically satisfies `TerminalValue`.
pub trait TerminalValue: Clone {
    // Empty
}

impl<T> TerminalValue for T
    where T: Clone {
    // Empty
}

//
// Interface types
//

//
// enum Symbol<Nt, T>: Debug + Clone + Copy + PartialEq
//

/// Used to describe non-terminal and terminal symbols in [`Rule`](struct.Rule.html)s
/// and grammar input sequences for [`Expander::expand()`](struct.Expander.html#method.expand).
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Symbol<Nt, T> {
    /// Variant for non-terminal symbols - ones which can be further expanded,
    /// can appear on left-hand side of rules and cannot appear in a successful expansion result.
    Nonterminal(Nt),
    /// Variant for terminal symbols - ones which will not be replaced during expansion,
    /// cannot appear on left-hand side of rules and will be the only ones in a successful expansion result.
    Terminal(T)
}

impl<Nt, T> Symbol<Nt, T> {
    /// Returns `true` if the [`Symbol`](enum.Symbol.html)
    /// is [`Terminal`](enum.Symbol.html#variant.Terminal).
    pub fn is_terminal(&self) -> bool {
        matches!(self, Self::Terminal(_))
    }

    /// Returns `true` if the [`Symbol`](enum.Symbol.html)
    /// is [`Nonterminal`](enum.Symbol.html#variant.Nonterminal).
    pub fn is_nonterminal(&self) -> bool {
        !self.is_terminal()
    }

    /// Returns the contained [`Nonterminal`](enum.Symbol.html#variant.Nonterminal) value,
    /// consuming the `self` value.
    ///
    /// # Panics
    /// Panics if the `self` value is actually [`Terminal`](enum.Symbol.html#variant.Terminal).
    pub fn unwrap_nonterm(self) -> Nt {
        self.expect_nonterm(
            "unwrap_nonterm() must be used only on non-terminal symbols"
        )
    }

    /// Returns the contained [`Nonterminal`](enum.Symbol.html#variant.Nonterminal) value,
    /// consuming the `self` value.
    ///
    /// # Panics
    /// Panics with a custom `message` if the `self` value is actually [`Terminal`](enum.Symbol.html#variant.Terminal).
    pub fn expect_nonterm(self, message: &'static str) -> Nt {
        if let Self::Nonterminal(value) = self {
            value
        } else {
            panic!("{}", message);
        }
    }

    /// Returns the contained [`Terminal`](enum.Symbol.html#variant.Terminal) value,
    /// consuming the `self` value.
    ///
    /// # Panics
    /// Panics if the `self` value is actually [`Nonterminal`](enum.Symbol.html#variant.Nonterminal).
    pub fn unwrap_term(self) -> T {
        self.expect_term(
            "unwrap_term() must be used only on terminal symbols"
        )
    }

    /// Returns the contained [`Terminal`](enum.Symbol.html#variant.Terminal) value,
    /// consuming the `self` value.
    ///
    /// # Panics
    /// Panics with a custom `message` if the `self` value is actually [`Nonterminal`](enum.Symbol.html#variant.Nonterminal).
    pub fn expect_term(self, message: &'static str) -> T {
        if let Self::Terminal(value) = self {
            value
        } else {
            panic!("{}", message);
        }
    }
}

//
// struct Rule<Nt, T>: Debug + Clone + PartialEq
//

/// Describes a rule (or production) of a context-free grammar.
#[derive(Debug, Clone, PartialEq)]
pub struct Rule<Nt, T> {
    /// Left-hand side of the rule (a single non-terminal symbol value).
    pub pattern:     Nt,
    /// Right-hand side of the rule (any sequence of symbols,
    /// with which to replace the encountered `pattern`).
    pub replacement: Vec<Symbol<Nt, T>>
}

impl<Nt, T> Rule<Nt, T> {
    pub fn new(pattern: Nt, replacement: Vec<Symbol<Nt, T>>) -> Self {
        Self{
            pattern,
            replacement
        }
    }
}