This commit is contained in:
2025-08-30 22:40:36 +10:00
parent 3522b1acc2
commit cf63513999
4 changed files with 234 additions and 36 deletions

View File

@@ -1,8 +1,10 @@
use crate::cell::{Cell, CellRef};
use crate::parser::*;
use crate::tokenizer::Literal;
use std::collections::HashMap;
use std::fmt;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub enum Eval {
Literal(Literal),
Expr(Expr),
@@ -17,25 +19,70 @@ impl fmt::Display for Eval {
}
}
pub fn _evaluate(expr: &mut Expr) -> Result<Eval, String> {
let res = match expr {
Expr::Literal(lit) => Eval::Literal(lit.clone()),
Expr::Infix { op, lhs, rhs } => {
let lval = _evaluate(lhs)?;
let rval = _evaluate(rhs)?;
pub struct Evaluator {
cells: HashMap<CellRef, Cell>,
}
match op {
InfixOp::ADD => eval_add(&lval, &rval)?,
InfixOp::SUB => eval_sub(&lval, &rval)?,
InfixOp::MUL => eval_mul(&lval, &rval)?,
InfixOp::DIV => eval_div(&lval, &rval)?,
_ => return Err(format!("Evaluation error: Unsupported operator {:?}", op)),
}
impl Evaluator {
pub fn new() -> Evaluator {
return Evaluator {
cells: HashMap::new(),
};
}
pub fn set_cell(&mut self, cell_ref: CellRef, raw_val: String) -> Result<(), String> {
if self.cells.contains_key(&cell_ref) && self.cells[&cell_ref].raw() == raw_val {
return Ok(());
}
it => return Err(format!("Evaluation error: Unsupported expression {:?}", it)),
};
Ok(res)
let mut eval: Option<Eval> = None;
if let Some(c) = raw_val.chars().nth(0)
&& c == '='
{
if let Ok(e) = self.evaluate(raw_val[1..].to_owned()) {
eval = Some(e);
};
}
self.cells.insert(cell_ref, Cell::new(eval, raw_val));
Ok(())
}
pub fn get_cell(&mut self, cell_ref: CellRef) -> Result<(String, Option<Eval>), String> {
if !self.cells.contains_key(&cell_ref) {
return Err(format!("Cell at {:?} not found.", cell_ref));
}
let cell = &self.cells[&cell_ref];
Ok((cell.raw(), cell.eval()))
}
pub fn evaluate(&self, str: String) -> Result<Eval, String> {
let mut expr = parse(&str)?;
self.evaluate_expr(&mut expr)
}
fn evaluate_expr(&self, expr: &mut Expr) -> Result<Eval, String> {
let res = match expr {
Expr::Literal(lit) => Eval::Literal(lit.clone()),
Expr::Infix { op, lhs, rhs } => {
let lval = self.evaluate_expr(lhs)?;
let rval = self.evaluate_expr(rhs)?;
match op {
InfixOp::ADD => eval_add(&lval, &rval)?,
InfixOp::SUB => eval_sub(&lval, &rval)?,
InfixOp::MUL => eval_mul(&lval, &rval)?,
InfixOp::DIV => eval_div(&lval, &rval)?,
_ => return Err(format!("Evaluation error: Unsupported operator {:?}", op)),
}
}
it => return Err(format!("Evaluation error: Unsupported expression {:?}", it)),
};
Ok(res)
}
}
fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
@@ -59,16 +106,43 @@ fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
}
fn eval_sub(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
Err("Todo.".to_string())
match (lval, rval) {
(Eval::Literal(a), Eval::Literal(b)) => {
if let Some(res) = eval_numeric_infix(a, b, |x, y| x - y, |x, y| x - y) {
return Ok(Eval::Literal(res));
}
Err("Evaluation error: expected string or numeric types for SUB function.".to_string())
}
_ => return Err("Evalutation error: expected literals for SUB function.".to_string()),
}
}
fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
Err("Todo.".to_string())
match (lval, rval) {
(Eval::Literal(a), Eval::Literal(b)) => {
if let Some(res) = eval_numeric_infix(a, b, |x, y| x * y, |x, y| x * y) {
return Ok(Eval::Literal(res));
}
Err("Evaluation error: expected string or numeric types for MUL function.".to_string())
}
_ => return Err("Evalutation error: expected literals for MUL function.".to_string()),
}
}
fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
Err("Todo.".to_string())
match (lval, rval) {
(Eval::Literal(a), Eval::Literal(b)) => {
if let Some(res) = eval_numeric_infix(a, b, |x, y| x / y, |x, y| x / y) {
return Ok(Eval::Literal(res));
}
Err("Evaluation error: expected string or numeric types for DIV function.".to_string())
}
_ => return Err("Evalutation error: expected literals for DIV function.".to_string()),
}
}
pub fn eval_numeric_infix<FInt, FDouble>(
fn eval_numeric_infix<FInt, FDouble>(
lhs: &Literal,
rhs: &Literal,
int_op: FInt,