rs_teststand/expression/operator/
arithmetic.rs1use super::Arity;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum ArithmeticOperator {
19 Add,
21 Subtract,
23 Multiply,
25 Divide,
27 Modulo,
29 ModuloWord,
31 Increment,
33 Decrement,
35}
36
37impl ArithmeticOperator {
38 pub const ALL: [Self; 8] = [
40 Self::Add,
41 Self::Subtract,
42 Self::Multiply,
43 Self::Divide,
44 Self::Modulo,
45 Self::ModuloWord,
46 Self::Increment,
47 Self::Decrement,
48 ];
49
50 #[must_use]
52 pub const fn symbol(self) -> &'static str {
53 match self {
54 Self::Add => "+",
55 Self::Subtract => "-",
56 Self::Multiply => "*",
57 Self::Divide => "/",
58 Self::Modulo => "%",
59 Self::ModuloWord => "MOD",
60 Self::Increment => "++",
61 Self::Decrement => "--",
62 }
63 }
64
65 #[must_use]
67 pub const fn arity(self) -> Arity {
68 match self {
69 Self::Increment | Self::Decrement => Arity::Unary,
70 _ => Arity::Binary,
71 }
72 }
73
74 #[must_use]
76 pub const fn precedence(self) -> u8 {
77 match self {
78 Self::Increment | Self::Decrement => 1,
79 Self::Multiply | Self::Divide | Self::Modulo | Self::ModuloWord => 2,
80 Self::Add | Self::Subtract => 3,
81 }
82 }
83
84 #[must_use]
86 pub const fn alternate_spelling(self) -> Option<Self> {
87 Some(match self {
88 Self::Modulo => Self::ModuloWord,
89 Self::ModuloWord => Self::Modulo,
90 _ => return None,
91 })
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::ArithmeticOperator;
98 use crate::expression::Arity;
99
100 #[test]
101 fn multiplication_binds_tighter_than_addition() {
102 assert!(ArithmeticOperator::Multiply.precedence() < ArithmeticOperator::Add.precedence());
104 }
105
106 #[test]
107 fn the_two_remainder_spellings_agree() {
108 let symbol = ArithmeticOperator::Modulo;
110 let word = ArithmeticOperator::ModuloWord;
111 assert_eq!(symbol.precedence(), word.precedence());
112 assert_eq!(symbol.arity(), word.arity());
113 assert_eq!(symbol.alternate_spelling(), Some(word));
114 assert_eq!(word.alternate_spelling(), Some(symbol));
115 }
116
117 #[test]
118 fn increment_and_decrement_take_one_operand() {
119 assert_eq!(ArithmeticOperator::Increment.arity(), Arity::Unary);
120 assert_eq!(ArithmeticOperator::Decrement.arity(), Arity::Unary);
121 assert_eq!(ArithmeticOperator::Add.arity(), Arity::Binary);
122 }
123
124 #[test]
125 fn no_operator_spells_exponentiation() {
126 assert!(ArithmeticOperator::ALL.iter().all(|op| op.symbol() != "^"));
129 }
130}