diff --git a/backend/src/evaluator/mod.rs b/backend/src/evaluator/mod.rs index e4cb9d4..851d3de 100644 --- a/backend/src/evaluator/mod.rs +++ b/backend/src/evaluator/mod.rs @@ -119,7 +119,33 @@ fn evaluate_expr( } Expr::Group(g) => evaluate_expr(g, precs, grid)?, Expr::Function { name, args } => match name.as_str() { - "AVG" => eval_avg(args, precs, grid)?, + // "AVG" => eval_avg(args, precs, grid)?, + "AVG" => eval_numeric_func( + args, + precs, + grid, + |nums| { + let mut res = 0.0; + let mut count = 0; + + for num in nums { + res += num; + count += 1; + } + + if count == 0 { + Err(LeadErr { + title: "Evaluation error.".into(), + desc: "Attempted to divide by zero.".into(), + code: LeadErrCode::DivZero, + }) + } else { + Ok(res / count as f64) + } + }, + "AVG".into(), + Some(0f64), + )?, "EXP" => eval_single_arg_numeric(args, precs, grid, |x| x.exp(), "EXP".into())?, "SIN" => eval_single_arg_numeric(args, precs, grid, |x| x.sin(), "SIN".into())?, "COS" => eval_single_arg_numeric(args, precs, grid, |x| x.cos(), "COS".into())?, diff --git a/backend/src/evaluator/utils.rs b/backend/src/evaluator/utils.rs index 9af59fc..b18da67 100644 --- a/backend/src/evaluator/utils.rs +++ b/backend/src/evaluator/utils.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::{collections::HashSet, default}; use crate::{ cell::CellRef, @@ -74,3 +74,67 @@ pub fn eval_n_arg_numeric( Ok(Eval::Literal(Literal::Number(func(numbers)))) } + +pub fn eval_numeric_func( + args: &Vec, + precs: &mut HashSet, + grid: Option<&Grid>, + func: fn(Vec) -> Result, + func_name: String, + unset_val: Option, +) -> Result { + let mut numeric_args = Vec::new(); + + for arg in args { + match evaluate_expr(arg, precs, grid)? { + Eval::Literal(Literal::Number(num)) => { + numeric_args.push(num); + } + Eval::Range(range) => { + for cell in range { + let Eval::CellRef { eval, reference: _ } = cell else { + return Err(LeadErr { + title: "Evaluation error.".into(), + desc: format!( + "Found non-cellref in RANGE during {func_name} evaluation." + ), + code: LeadErrCode::Server, + }); + }; + + if let Eval::Literal(Literal::Number(num)) = *eval { + numeric_args.push(num); + } else if matches!(*eval, Eval::Unset) { + if let Some(default) = unset_val { + numeric_args.push(default); + } else { + return Err(LeadErr { + title: "Evaluation error.".into(), + desc: format!("{func_name} does not support unset cells."), + code: LeadErrCode::Unsupported, + }); + } + } else { + return Err(LeadErr { + title: "Evaluation error.".into(), + desc: format!("Expected numeric types for {func_name} function."), + code: LeadErrCode::Unsupported, + }); + } + } + } + _ => { + return Err(LeadErr { + title: "Evaluation error.".into(), + desc: format!("Expected numeric types for {func_name} function."), + code: LeadErrCode::Unsupported, + }); + } + } + } + + match func(numeric_args) { + Ok(res) => Ok(Eval::Literal(Literal::Number(res))), + Err(e) => Err(e), + } +}