128 lines
3.2 KiB
Rust
128 lines
3.2 KiB
Rust
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<T>(&self, lhs: T, rhs: T) -> T
|
|
where
|
|
T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
|
|
{
|
|
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<u8> for BinOp {
|
|
type Error = u8;
|
|
|
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
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("/"),
|
|
}
|
|
}
|
|
}
|
|
}
|