use crate::ast::BinOp;
use std::cmp::Ordering;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Precedence {
Logical,
Comparison,
AddSub,
MulDiv,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Associativity {
Left,
Right,
Not,
}
impl BinOp {
fn precedence(&self) -> Precedence {
match self {
Self::Or | Self::And => Precedence::Logical,
Self::Eq
| Self::Ne
| Self::Lt
| Self::Le
| Self::Gt
| Self::Ge => Precedence::Comparison,
Self::Mul | Self::Div | Self::Mod => Precedence::MulDiv,
Self::Add | Self::Sub => Precedence::AddSub,
}
}
fn associativity(&self) -> Associativity {
match self.precedence() {
Precedence::AddSub | Precedence::MulDiv | Precedence::Logical => {
Associativity::Left
}
Precedence::Comparison => Associativity::Not,
}
}
pub fn relative_associativity(&self, other: &Self) -> Associativity {
if let (BinOp::Or, BinOp::And) | (BinOp::And, BinOp::Or) =
(self, other)
{
return Associativity::Not;
}
match self.precedence().cmp(&other.precedence()) {
Ordering::Less => Associativity::Right,
Ordering::Greater => Associativity::Left,
Ordering::Equal => self.associativity(),
}
}
}
#[cfg(all(test, not(miri)))]
mod tests {
use crate::{ast::BinOp, parser::precedence::Associativity};
fn f(a: BinOp, b: BinOp) -> Associativity {
a.relative_associativity(&b)
}
#[test]
fn assoc() {
use Associativity::*;
use BinOp::*;
assert_eq!(f(Add, Add), Left);
assert_eq!(f(Mul, Add), Left);
assert_eq!(f(Add, Mul), Right);
assert_eq!(f(And, Or), Not);
assert_eq!(f(And, And), Left);
assert_eq!(f(Or, Or), Left);
assert_eq!(f(Eq, Eq), Not);
}
}