use crate::lexer::TokenKind;
pub fn infix_binding_power(op: &TokenKind) -> Option<(u8, u8)> {
Some(match op {
TokenKind::Implies => (3, 2),
TokenKind::Bind => (10, 9),
TokenKind::Pipe => (21, 20),
TokenKind::At => (31, 30),
TokenKind::Compose => (40, 41),
TokenKind::Arrow => (50, 51),
TokenKind::DotDot => (55, 55),
TokenKind::Or => (61, 60),
TokenKind::And => (71, 70),
TokenKind::Eq | TokenKind::Ne => (80, 80),
TokenKind::Lt | TokenKind::Le | TokenKind::Greater | TokenKind::GreaterEqual => (90, 90),
TokenKind::Plus | TokenKind::Minus => (101, 100),
TokenKind::Star | TokenKind::Slash | TokenKind::Percent => (111, 110),
TokenKind::Caret => (120, 121),
TokenKind::As => (131, 130),
TokenKind::Dot => (141, 140),
_ => return None,
})
}
pub fn prefix_binding_power(op: &TokenKind) -> Option<u8> {
match op {
TokenKind::Minus => Some(130), TokenKind::Bang => Some(130), TokenKind::Star => Some(130), TokenKind::Quote => Some(135), TokenKind::Comma => Some(135), TokenKind::Reflect => Some(135), _ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_assignment_is_right_associative() {
let (left, right) = infix_binding_power(&TokenKind::Bind).unwrap();
assert!(left > right, "Assignment should be right associative");
}
#[test]
fn test_pipe_is_left_associative() {
let (left, right) = infix_binding_power(&TokenKind::Pipe).unwrap();
assert!(
left > right,
"Pipe should be left associative (left > right)"
);
}
#[test]
fn test_equality_is_non_associative() {
let (left, right) = infix_binding_power(&TokenKind::Eq).unwrap();
assert_eq!(left, right, "Equality should be non-associative");
}
#[test]
fn test_compose_is_right_associative() {
let (left, right) = infix_binding_power(&TokenKind::Compose).unwrap();
assert!(
left < right,
"Compose should be right associative (left < right)"
);
}
#[test]
fn test_precedence_order() {
assert!(
infix_binding_power(&TokenKind::Bind).unwrap().0
< infix_binding_power(&TokenKind::Pipe).unwrap().0
);
assert!(
infix_binding_power(&TokenKind::Pipe).unwrap().0
< infix_binding_power(&TokenKind::At).unwrap().0
);
assert!(
infix_binding_power(&TokenKind::At).unwrap().0
< infix_binding_power(&TokenKind::Compose).unwrap().0
);
assert!(
infix_binding_power(&TokenKind::Dot).unwrap().0
> infix_binding_power(&TokenKind::Caret).unwrap().0
);
}
#[test]
fn test_prefix_binding_power() {
assert_eq!(prefix_binding_power(&TokenKind::Minus), Some(130));
assert_eq!(prefix_binding_power(&TokenKind::Bang), Some(130));
assert_eq!(prefix_binding_power(&TokenKind::Quote), Some(135));
assert_eq!(prefix_binding_power(&TokenKind::Reflect), Some(135));
}
#[test]
fn test_invalid_operators() {
assert_eq!(infix_binding_power(&TokenKind::Gene), None);
assert_eq!(prefix_binding_power(&TokenKind::Trait), None);
}
}