Files
deriv/src/binding.rs
T

188 lines
4.6 KiB
Rust

use crate::token::Token;
use crate::expression::Expression;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Associativity {
Left,
Right,
Full,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum Power {
Minimum,
Addition,
Multiplication,
Exponentiation,
Maximum,
}
#[derive(Copy, Clone, Debug)]
pub struct Binding {
power: Power,
associativity: Associativity,
}
impl Binding {
pub fn left(power: Power) -> Self {
Self { power, associativity: Associativity::Left }
}
pub fn right(power: Power) -> Self {
Self { power, associativity: Associativity::Right }
}
pub fn full(power: Power) -> Self {
Self { power, associativity: Associativity::Full }
}
pub fn of_operator(token: &Token) -> Self {
if token.starts_expression() {
Binding::full(Power::Multiplication)
} else {
match token {
Token::Plus => Binding::full(Power::Addition),
Token::Minus => Binding::left(Power::Addition),
Token::Times => Binding::full(Power::Multiplication),
Token::Divide => Binding::left(Power::Multiplication),
Token::Caret => Binding::right(Power::Exponentiation),
Token::CloseParen => Binding::left(Power::Minimum),
_ => unreachable!(),
}
}
}
pub fn of_expression(expr: &Expression) -> Self {
match expr {
Expression::Sum(_, _) => Self::full(Power::Addition),
Expression::Difference(_, _) => Self::left(Power::Addition),
Expression::Product(_, _) => Self::full(Power::Multiplication),
Expression::Quotient(_, _) => Self::left(Power::Multiplication),
Expression::Exponent(_, _) => Self::right(Power::Exponentiation),
Expression::Integer(_) => Self::left(Power::Maximum),
Expression::Symbol(_) => Self::left(Power::Maximum),
}
}
}
impl std::cmp::PartialEq for Binding {
fn eq(&self, other: &Self) -> bool
{
self.associativity == Associativity::Full
&& self.power == other.power
}
}
impl std::cmp::PartialOrd for Binding {
fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering>
{
Some(if self.power < rhs.power {
std::cmp::Ordering::Less
} else if self.power > rhs.power {
std::cmp::Ordering::Greater
} else {
match self.associativity {
Associativity::Left => std::cmp::Ordering::Less,
Associativity::Right => std::cmp::Ordering::Greater,
Associativity::Full => std::cmp::Ordering::Equal,
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn left_assoc_min_is_less_than_left_assoc_add() {
assert_eq!(
Binding::left(Power::Minimum).partial_cmp(
&Binding::left(Power::Addition)),
Some(std::cmp::Ordering::Less));
}
#[test]
fn left_assoc_add_is_less_than_left_assoc_add() {
assert_eq!(
Binding::left(Power::Addition).partial_cmp(
&Binding::left(Power::Addition)),
Some(std::cmp::Ordering::Less));
}
#[test]
fn left_assoc_mult_is_greater_than_left_assoc_add() {
assert_eq!(
Binding::left(Power::Multiplication).partial_cmp(
&Binding::left(Power::Addition)),
Some(std::cmp::Ordering::Greater));
}
#[test]
fn right_assoc_min_is_less_than_right_assoc_add() {
assert_eq!(
Binding::right(Power::Minimum).partial_cmp(
&Binding::right(Power::Addition)),
Some(std::cmp::Ordering::Less));
}
#[test]
fn right_assoc_add_is_greater_than_right_assoc_add() {
assert_eq!(
Binding::right(Power::Addition).partial_cmp(
&Binding::right(Power::Addition)),
Some(std::cmp::Ordering::Greater));
}
#[test]
fn right_assoc_mul_is_greater_than_right_assoc_add() {
assert_eq!(
Binding::right(Power::Multiplication).partial_cmp(
&Binding::right(Power::Addition)),
Some(std::cmp::Ordering::Greater));
}
#[test]
fn full_assoc_min_is_less_than_full_assoc_add() {
assert_eq!(
Binding::full(Power::Minimum).partial_cmp(
&Binding::full(Power::Addition)),
Some(std::cmp::Ordering::Less));
}
#[test]
fn full_assoc_add_is_equal_to_full_assoc_add() {
assert_eq!(
Binding::full(Power::Addition).partial_cmp(
&Binding::full(Power::Addition)),
Some(std::cmp::Ordering::Equal));
}
#[test]
fn full_assoc_mul_is_greater_than_full_assoc_add() {
assert_eq!(
Binding::full(Power::Multiplication).partial_cmp(
&Binding::full(Power::Addition)),
Some(std::cmp::Ordering::Greater));
}
#[test]
fn left_assoc_min_is_not_equal_to_left_assoc_min() {
assert_ne!(
Binding::left(Power::Minimum), Binding::left(Power::Minimum));
}
#[test]
fn right_assoc_min_is_not_equal_to_right_assoc_min() {
assert_ne!(
Binding::right(Power::Minimum), Binding::right(Power::Minimum));
}
#[test]
fn full_assoc_min_is_equal_to_full_assoc_min() {
assert_eq!(
Binding::full(Power::Minimum), Binding::left(Power::Minimum));
}
}