mirror of
https://github.com/MorizzG/rlox.git
synced 2025-12-06 04:12:42 +00:00
113 lines
4.2 KiB
Rust
113 lines
4.2 KiB
Rust
|
|
use std::fmt::Display;
|
||
|
|
|
||
|
|
use crate::error::EvalError;
|
||
|
|
use crate::parser::expr::{BinaryOp, Expr, Literal, UnaryOp};
|
||
|
|
|
||
|
|
pub type EvalResult = Result<Primitive, EvalError>;
|
||
|
|
|
||
|
|
/*====================================================================================================================*/
|
||
|
|
|
||
|
|
pub fn evaluate(expr: Expr) -> EvalResult {
|
||
|
|
expr.eval()
|
||
|
|
}
|
||
|
|
|
||
|
|
/*====================================================================================================================*/
|
||
|
|
|
||
|
|
#[derive(Debug, PartialEq)]
|
||
|
|
pub enum Primitive {
|
||
|
|
String(String),
|
||
|
|
Number(f64),
|
||
|
|
Bool(bool),
|
||
|
|
Nil,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Primitive {
|
||
|
|
fn is_truthy(&self) -> bool {
|
||
|
|
match self {
|
||
|
|
Primitive::Bool(false) | Primitive::Nil => false,
|
||
|
|
_ => true,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Display for Primitive {
|
||
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
|
|
match self {
|
||
|
|
Primitive::String(s) => write!(f, "\"{s}\""),
|
||
|
|
Primitive::Number(num) => write!(f, "{num}"),
|
||
|
|
Primitive::Bool(b) => write!(f, "{b}"),
|
||
|
|
Primitive::Nil => write!(f, "nil"),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*====================================================================================================================*/
|
||
|
|
|
||
|
|
trait Eval {
|
||
|
|
fn eval(self) -> EvalResult;
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Eval for Literal {
|
||
|
|
fn eval(self) -> EvalResult {
|
||
|
|
match self {
|
||
|
|
Literal::String(s) => Ok(Primitive::String(s)),
|
||
|
|
Literal::Number(num) => Ok(Primitive::Number(num)),
|
||
|
|
Literal::Bool(b) => Ok(Primitive::Bool(b)),
|
||
|
|
Literal::Nil => Ok(Primitive::Nil),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Eval for Expr {
|
||
|
|
fn eval(self) -> EvalResult {
|
||
|
|
match self {
|
||
|
|
Expr::Literal(literal) => literal.eval(),
|
||
|
|
Expr::Unary(op, expr) => {
|
||
|
|
let arg = expr.eval()?;
|
||
|
|
|
||
|
|
match (op, arg) {
|
||
|
|
(UnaryOp::Negate, Primitive::Number(num)) => Ok(Primitive::Number(-num)),
|
||
|
|
(UnaryOp::Not, Primitive::Bool(b)) => Ok(Primitive::Bool(!b)),
|
||
|
|
(UnaryOp::Not, primitive) => Ok(Primitive::Bool(!primitive.is_truthy())),
|
||
|
|
(op, arg) => Err(EvalError::UnaryOpInvalidArgument { op, arg }),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Expr::Binary(left_expr, op, right_expr) => {
|
||
|
|
use Primitive::{Bool, Number, String};
|
||
|
|
|
||
|
|
let left = left_expr.eval()?;
|
||
|
|
let right = right_expr.eval()?;
|
||
|
|
|
||
|
|
match (left, op, right) {
|
||
|
|
(Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)),
|
||
|
|
(Number(left), BinaryOp::Subtract, Number(right)) => Ok(Number(left - right)),
|
||
|
|
(Number(left), BinaryOp::Multiply, Number(right)) => Ok(Number(left * right)),
|
||
|
|
(Number(left), BinaryOp::Divide, Number(right)) => {
|
||
|
|
if right == 0.0 {
|
||
|
|
return Err(EvalError::DivisionByZero);
|
||
|
|
}
|
||
|
|
Ok(Number(left / right))
|
||
|
|
}
|
||
|
|
|
||
|
|
(String(left), BinaryOp::Add, String(right)) => Ok(String(left + &right)),
|
||
|
|
|
||
|
|
(left, BinaryOp::Equal, right) => Ok(Bool(left == right)),
|
||
|
|
(left, BinaryOp::NotEqual, right) => Ok(Bool(left != right)),
|
||
|
|
|
||
|
|
(Number(left), BinaryOp::Less, Number(right)) => Ok(Bool(left < right)),
|
||
|
|
(Number(left), BinaryOp::LessEqual, Number(right)) => Ok(Bool(left <= right)),
|
||
|
|
(Number(left), BinaryOp::Greater, Number(right)) => Ok(Bool(left > right)),
|
||
|
|
(Number(left), BinaryOp::GreaterEqual, Number(right)) => Ok(Bool(left >= right)),
|
||
|
|
|
||
|
|
(String(left), BinaryOp::Less, String(right)) => Ok(Bool(left < right)),
|
||
|
|
(String(left), BinaryOp::LessEqual, String(right)) => Ok(Bool(left <= right)),
|
||
|
|
(String(left), BinaryOp::Greater, String(right)) => Ok(Bool(left > right)),
|
||
|
|
(String(left), BinaryOp::GreaterEqual, String(right)) => Ok(Bool(left >= right)),
|
||
|
|
|
||
|
|
(left, op, right) => Err(EvalError::BinaryOpInvalidArguments { left, op, right }),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Expr::Grouping(expr) => expr.eval(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|