rs_teststand/expression/operator/
mod.rs1pub mod arithmetic;
35pub mod assignment;
36pub mod bitwise;
37pub mod comparison;
38pub mod logical;
39pub mod other;
40
41pub use arithmetic::ArithmeticOperator;
42pub use assignment::AssignmentOperator;
43pub use bitwise::BitwiseOperator;
44pub use comparison::ComparisonOperator;
45pub use logical::LogicalOperator;
46pub use other::OtherOperator;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub enum Arity {
51 Unary,
53 Binary,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub enum OperatorClass {
60 Arithmetic,
62 Assignment,
64 Bitwise,
66 Comparison,
68 Logical,
70 Other,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
79pub enum Operator {
80 Arithmetic(ArithmeticOperator),
82 Assignment(AssignmentOperator),
84 Bitwise(BitwiseOperator),
86 Comparison(ComparisonOperator),
88 Logical(LogicalOperator),
90 Other(OtherOperator),
92}
93
94impl Operator {
95 #[must_use]
97 pub const fn symbol(self) -> &'static str {
98 match self {
99 Self::Arithmetic(operator) => operator.symbol(),
100 Self::Assignment(operator) => operator.symbol(),
101 Self::Bitwise(operator) => operator.symbol(),
102 Self::Comparison(operator) => operator.symbol(),
103 Self::Logical(operator) => operator.symbol(),
104 Self::Other(operator) => operator.symbol(),
105 }
106 }
107
108 #[must_use]
110 pub const fn class(self) -> OperatorClass {
111 match self {
112 Self::Arithmetic(_) => OperatorClass::Arithmetic,
113 Self::Assignment(_) => OperatorClass::Assignment,
114 Self::Bitwise(_) => OperatorClass::Bitwise,
115 Self::Comparison(_) => OperatorClass::Comparison,
116 Self::Logical(_) => OperatorClass::Logical,
117 Self::Other(_) => OperatorClass::Other,
118 }
119 }
120
121 #[must_use]
126 pub const fn arity(self) -> Option<Arity> {
127 Some(match self {
128 Self::Arithmetic(operator) => operator.arity(),
129 Self::Assignment(operator) => operator.arity(),
130 Self::Bitwise(operator) => operator.arity(),
131 Self::Comparison(operator) => operator.arity(),
132 Self::Logical(operator) => operator.arity(),
133 Self::Other(_) => return None,
134 })
135 }
136
137 #[must_use]
139 pub const fn precedence(self) -> Option<u8> {
140 match self {
141 Self::Arithmetic(operator) => Some(operator.precedence()),
142 Self::Bitwise(operator) => Some(operator.precedence()),
143 Self::Comparison(operator) => Some(operator.precedence()),
144 Self::Logical(operator) => Some(operator.precedence()),
145 Self::Assignment(operator) => operator.precedence(),
146 Self::Other(_) => None,
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::{
154 ArithmeticOperator, BitwiseOperator, ComparisonOperator, LogicalOperator, Operator,
155 OperatorClass, OtherOperator,
156 };
157
158 #[test]
159 fn the_wrapper_reports_the_family_it_holds() {
160 assert_eq!(
161 Operator::Arithmetic(ArithmeticOperator::Add).class(),
162 OperatorClass::Arithmetic
163 );
164 assert_eq!(
165 Operator::Bitwise(BitwiseOperator::AndWord).class(),
166 OperatorClass::Bitwise
167 );
168 assert_eq!(
169 Operator::Logical(LogicalOperator::And).class(),
170 OperatorClass::Logical
171 );
172 }
173
174 #[test]
175 fn the_word_forms_are_bitwise_and_the_doubled_symbols_are_logical() {
176 assert_eq!(
179 Operator::Bitwise(BitwiseOperator::AndWord).class(),
180 OperatorClass::Bitwise
181 );
182 assert_eq!(
183 Operator::Logical(LogicalOperator::And).class(),
184 OperatorClass::Logical
185 );
186 assert_eq!(BitwiseOperator::AndWord.symbol(), "AND");
187 assert_eq!(LogicalOperator::And.symbol(), "&&");
188 }
189
190 #[test]
191 fn structural_elements_have_no_arity_or_precedence() {
192 let subscript = Operator::Other(OtherOperator::Subscript);
193 assert_eq!(subscript.arity(), None);
194 assert_eq!(subscript.precedence(), None);
195 }
196
197 #[test]
198 fn the_measured_order_holds_across_families() {
199 let tighter = |left: Operator, right: Operator| {
202 left.precedence()
203 .zip(right.precedence())
204 .is_some_and(|(l, r)| l < r)
205 };
206 assert!(tighter(
207 Operator::Arithmetic(ArithmeticOperator::Multiply),
208 Operator::Arithmetic(ArithmeticOperator::Add)
209 ));
210 assert!(tighter(
211 Operator::Arithmetic(ArithmeticOperator::Add),
212 Operator::Bitwise(BitwiseOperator::ShiftLeft)
213 ));
214 assert!(tighter(
215 Operator::Bitwise(BitwiseOperator::ShiftLeft),
216 Operator::Comparison(ComparisonOperator::Equal)
217 ));
218 assert!(tighter(
219 Operator::Comparison(ComparisonOperator::Equal),
220 Operator::Bitwise(BitwiseOperator::And)
221 ));
222 assert!(tighter(
223 Operator::Bitwise(BitwiseOperator::Or),
224 Operator::Logical(LogicalOperator::And)
225 ));
226 assert!(tighter(
227 Operator::Logical(LogicalOperator::And),
228 Operator::Logical(LogicalOperator::Or)
229 ));
230 }
231}