pub mod typed; pub mod untyped; use core::fmt; use std::ops::{Add, Div, Mul, Sub}; pub use untyped::UntypedExpr; #[derive(Debug, Copy, Clone)] pub struct Span { pub start: usize, pub end: usize, } impl Span { pub fn new(start: usize, end: usize) -> Self { Self { start, end } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinOp { Add, Sub, Mul, Div, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OpCommutative { Yes(BinOp), No, } impl BinOp { pub fn precedence(&self) -> u8 { match self { BinOp::Add => 1, BinOp::Sub => 1, BinOp::Mul => 2, BinOp::Div => 2, } } pub fn commutative(&self, other: &Self) -> bool { matches!(self.commutative_expr(other), OpCommutative::Yes(_)) } pub fn swappable(&self, other: &Self) -> bool { if let OpCommutative::Yes(new_op) = self.commutative_expr(other) { other == self && new_op == *other } else { false } } pub fn commutative_expr(&self, other: &Self) -> OpCommutative { match (self, other) { (BinOp::Add, BinOp::Add) => OpCommutative::Yes(BinOp::Add), (BinOp::Add, BinOp::Sub) => OpCommutative::Yes(BinOp::Sub), (BinOp::Sub, BinOp::Add) => OpCommutative::Yes(BinOp::Sub), (BinOp::Sub, BinOp::Sub) => OpCommutative::Yes(BinOp::Add), (BinOp::Mul, BinOp::Mul) => OpCommutative::Yes(BinOp::Mul), (BinOp::Mul, BinOp::Div) => OpCommutative::Yes(BinOp::Div), (BinOp::Div, BinOp::Mul) => OpCommutative::Yes(BinOp::Div), (BinOp::Div, BinOp::Div) => OpCommutative::Yes(BinOp::Mul), _ => OpCommutative::No, } } pub fn evaluate(&self, lhs: T, rhs: T) -> T where T: Add + Sub + Mul + Div, { match self { BinOp::Add => lhs + rhs, BinOp::Sub => lhs - rhs, BinOp::Mul => lhs * rhs, BinOp::Div => lhs / rhs, } } } impl From<&BinOp> for u8 { fn from(value: &BinOp) -> Self { match value { BinOp::Add => 1, BinOp::Sub => 2, BinOp::Mul => 3, BinOp::Div => 4, } } } impl TryFrom for BinOp { type Error = u8; fn try_from(value: u8) -> Result { match value { 1 => Ok(BinOp::Add), 2 => Ok(BinOp::Sub), 3 => Ok(BinOp::Mul), 4 => Ok(BinOp::Div), b => Err(b), } } } impl fmt::Display for BinOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { match self { BinOp::Add => f.write_str("add"), BinOp::Sub => f.write_str("sub"), BinOp::Mul => f.write_str("mul"), BinOp::Div => f.write_str("div"), } } else { match self { BinOp::Add => f.write_str("+"), BinOp::Sub => f.write_str("-"), BinOp::Mul => f.write_str("*"), BinOp::Div => f.write_str("/"), } } } }