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 token;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
|
pub mod binding;
|
||||||
|
|
||||||
pub mod lex;
|
pub mod lex;
|
||||||
Reference in new issue
Block a user