use super::Arity;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BitwiseOperator {
And,
Or,
Xor,
Not,
ShiftLeft,
ShiftRight,
AndWord,
OrWord,
XorWord,
NotWord,
}
impl BitwiseOperator {
pub const ALL: [Self; 10] = [
Self::And,
Self::Or,
Self::Xor,
Self::Not,
Self::ShiftLeft,
Self::ShiftRight,
Self::AndWord,
Self::OrWord,
Self::XorWord,
Self::NotWord,
];
#[must_use]
pub const fn symbol(self) -> &'static str {
match self {
Self::And => "&",
Self::Or => "|",
Self::Xor => "^",
Self::Not => "~",
Self::ShiftLeft => "<<",
Self::ShiftRight => ">>",
Self::AndWord => "AND",
Self::OrWord => "OR",
Self::XorWord => "XOR",
Self::NotWord => "NOT",
}
}
#[must_use]
pub const fn arity(self) -> Arity {
match self {
Self::Not | Self::NotWord => Arity::Unary,
_ => Arity::Binary,
}
}
#[must_use]
pub const fn precedence(self) -> u8 {
match self {
Self::Not | Self::NotWord => 1,
Self::ShiftLeft | Self::ShiftRight => 4,
Self::And | Self::AndWord => 6,
Self::Xor | Self::XorWord => 7,
Self::Or | Self::OrWord => 8,
}
}
#[must_use]
pub const fn alternate_spelling(self) -> Option<Self> {
Some(match self {
Self::And => Self::AndWord,
Self::AndWord => Self::And,
Self::Or => Self::OrWord,
Self::OrWord => Self::Or,
Self::Xor => Self::XorWord,
Self::XorWord => Self::Xor,
Self::Not => Self::NotWord,
Self::NotWord => Self::Not,
_ => return None,
})
}
}
#[cfg(test)]
mod tests {
use super::BitwiseOperator;
#[test]
fn and_binds_tighter_than_xor_which_binds_tighter_than_or() {
assert!(BitwiseOperator::And.precedence() < BitwiseOperator::Xor.precedence());
assert!(BitwiseOperator::Xor.precedence() < BitwiseOperator::Or.precedence());
}
#[test]
fn word_and_symbol_spellings_agree() {
for operator in BitwiseOperator::ALL {
let Some(other) = operator.alternate_spelling() else {
continue;
};
assert_eq!(operator.precedence(), other.precedence(), "{operator:?}");
assert_eq!(operator.arity(), other.arity(), "{operator:?}");
}
}
#[test]
fn shifts_bind_looser_than_arithmetic_but_tighter_than_comparison() {
use crate::expression::{ArithmeticOperator, ComparisonOperator};
assert!(ArithmeticOperator::Add.precedence() < BitwiseOperator::ShiftLeft.precedence());
assert!(BitwiseOperator::ShiftLeft.precedence() < ComparisonOperator::Equal.precedence());
}
}