pub mod arithmetic;
pub mod assignment;
pub mod bitwise;
pub mod comparison;
pub mod logical;
pub mod other;
pub use arithmetic::ArithmeticOperator;
pub use assignment::AssignmentOperator;
pub use bitwise::BitwiseOperator;
pub use comparison::ComparisonOperator;
pub use logical::LogicalOperator;
pub use other::OtherOperator;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Arity {
Unary,
Binary,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OperatorClass {
Arithmetic,
Assignment,
Bitwise,
Comparison,
Logical,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Operator {
Arithmetic(ArithmeticOperator),
Assignment(AssignmentOperator),
Bitwise(BitwiseOperator),
Comparison(ComparisonOperator),
Logical(LogicalOperator),
Other(OtherOperator),
}
impl Operator {
#[must_use]
pub const fn symbol(self) -> &'static str {
match self {
Self::Arithmetic(operator) => operator.symbol(),
Self::Assignment(operator) => operator.symbol(),
Self::Bitwise(operator) => operator.symbol(),
Self::Comparison(operator) => operator.symbol(),
Self::Logical(operator) => operator.symbol(),
Self::Other(operator) => operator.symbol(),
}
}
#[must_use]
pub const fn class(self) -> OperatorClass {
match self {
Self::Arithmetic(_) => OperatorClass::Arithmetic,
Self::Assignment(_) => OperatorClass::Assignment,
Self::Bitwise(_) => OperatorClass::Bitwise,
Self::Comparison(_) => OperatorClass::Comparison,
Self::Logical(_) => OperatorClass::Logical,
Self::Other(_) => OperatorClass::Other,
}
}
#[must_use]
pub const fn arity(self) -> Option<Arity> {
Some(match self {
Self::Arithmetic(operator) => operator.arity(),
Self::Assignment(operator) => operator.arity(),
Self::Bitwise(operator) => operator.arity(),
Self::Comparison(operator) => operator.arity(),
Self::Logical(operator) => operator.arity(),
Self::Other(_) => return None,
})
}
#[must_use]
pub const fn precedence(self) -> Option<u8> {
match self {
Self::Arithmetic(operator) => Some(operator.precedence()),
Self::Bitwise(operator) => Some(operator.precedence()),
Self::Comparison(operator) => Some(operator.precedence()),
Self::Logical(operator) => Some(operator.precedence()),
Self::Assignment(operator) => operator.precedence(),
Self::Other(_) => None,
}
}
}
#[cfg(test)]
mod tests {
use super::{
ArithmeticOperator, BitwiseOperator, ComparisonOperator, LogicalOperator, Operator,
OperatorClass, OtherOperator,
};
#[test]
fn the_wrapper_reports_the_family_it_holds() {
assert_eq!(
Operator::Arithmetic(ArithmeticOperator::Add).class(),
OperatorClass::Arithmetic
);
assert_eq!(
Operator::Bitwise(BitwiseOperator::AndWord).class(),
OperatorClass::Bitwise
);
assert_eq!(
Operator::Logical(LogicalOperator::And).class(),
OperatorClass::Logical
);
}
#[test]
fn the_word_forms_are_bitwise_and_the_doubled_symbols_are_logical() {
assert_eq!(
Operator::Bitwise(BitwiseOperator::AndWord).class(),
OperatorClass::Bitwise
);
assert_eq!(
Operator::Logical(LogicalOperator::And).class(),
OperatorClass::Logical
);
assert_eq!(BitwiseOperator::AndWord.symbol(), "AND");
assert_eq!(LogicalOperator::And.symbol(), "&&");
}
#[test]
fn structural_elements_have_no_arity_or_precedence() {
let subscript = Operator::Other(OtherOperator::Subscript);
assert_eq!(subscript.arity(), None);
assert_eq!(subscript.precedence(), None);
}
#[test]
fn the_measured_order_holds_across_families() {
let tighter = |left: Operator, right: Operator| {
left.precedence()
.zip(right.precedence())
.is_some_and(|(l, r)| l < r)
};
assert!(tighter(
Operator::Arithmetic(ArithmeticOperator::Multiply),
Operator::Arithmetic(ArithmeticOperator::Add)
));
assert!(tighter(
Operator::Arithmetic(ArithmeticOperator::Add),
Operator::Bitwise(BitwiseOperator::ShiftLeft)
));
assert!(tighter(
Operator::Bitwise(BitwiseOperator::ShiftLeft),
Operator::Comparison(ComparisonOperator::Equal)
));
assert!(tighter(
Operator::Comparison(ComparisonOperator::Equal),
Operator::Bitwise(BitwiseOperator::And)
));
assert!(tighter(
Operator::Bitwise(BitwiseOperator::Or),
Operator::Logical(LogicalOperator::And)
));
assert!(tighter(
Operator::Logical(LogicalOperator::And),
Operator::Logical(LogicalOperator::Or)
));
}
}