use super::types::ArithOp;
use crate::structure::{Ident, Reference};
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Lit(i64),
Var(Reference),
BinOp {
op: ArithOp,
lhs: Box<Expression>,
rhs: Box<Expression>,
},
Pow {
base: Box<Expression>,
exp: Box<Expression>,
},
FnCall { name: Ident, args: Vec<Expression> },
}
impl Expression {
#[must_use]
pub fn evaluate_constant(&self) -> Option<i64> {
match self {
Self::Lit(v) => Some(*v),
Self::Var(_) | Self::FnCall { .. } => None,
Self::BinOp { op, lhs, rhs } => {
let l = lhs.evaluate_constant()?;
let r = rhs.evaluate_constant()?;
match op {
ArithOp::Add => l.checked_add(r),
ArithOp::Sub => l.checked_sub(r),
ArithOp::Mul => l.checked_mul(r),
ArithOp::Div => {
if r == 0 {
None
} else {
l.checked_div(r)
}
}
}
}
Self::Pow { base, exp } => {
let b = base.evaluate_constant()?;
let e = exp.evaluate_constant()?;
let e_u32 = u32::try_from(e).ok()?;
b.checked_pow(e_u32)
}
}
}
}