Create binding power algebra handling associativity
This commit is contained in:
1 parent
fbab9c521d
commit
aad169c24f
2 files changed
+188
No files matched your search
+187
@@ -0,0 +1,187 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod token;
|
||||
pub mod expression;
|
||||
pub mod binding;
|
||||
|
||||
pub mod lex;
|
||||
Reference in new issue
Block a user