1
0
Files
developing-compilers/src/ast/mod.rs
2024-11-13 19:41:56 +03:00

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("/"),
}
}
}
}