Merge remote-tracking branch 'origin'

This commit is contained in:
2025-09-12 01:46:41 +10:00
11 changed files with 520 additions and 168 deletions

View File

@@ -1,14 +1,16 @@
use serde::{Deserialize, Serialize};
use crate::cell::CellRef;
use crate::common::LeadErr;
use crate::common::LeadErrCode;
use crate::common::Literal;
use crate::grid::Grid;
use crate::parser::*;
use std::collections::HashSet;
use std::f64;
use std::fmt;
use crate::{
cell::CellRef,
common::{LeadErr, LeadErrCode, Literal},
evaluator::utils::*,
grid::Grid,
parser::*,
};
use std::{collections::HashSet, f64, fmt};
mod utils;
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
@@ -266,37 +268,6 @@ fn eval_avg(
}
}
fn eval_single_arg_numeric(
args: &Vec<Expr>,
precs: &mut HashSet<CellRef>,
grid: Option<&Grid>,
func: fn(f64) -> f64,
func_name: String,
) -> Result<Eval, LeadErr> {
if args.len() != 1 {
return Err(LeadErr {
title: "Evaluation error.".into(),
desc: format!("{func_name} function requires a single argument."),
code: LeadErrCode::Invalid,
});
}
let err = LeadErr {
title: "Evaluation error.".into(),
desc: format!("{func_name} function requires a numeric argument."),
code: LeadErrCode::TypeErr,
};
match evaluate_expr(&args[0], precs, grid)? {
Eval::Literal(Literal::Number(num)) => Ok(Eval::Literal(Literal::Number(func(num)))),
Eval::CellRef { eval, .. } => match *eval {
Eval::Literal(Literal::Number(n)) => Ok(Eval::Literal(Literal::Number(func(n)))),
_ => Err(err),
},
_ => Err(err),
}
}
fn eval_const(args: &Vec<Expr>, value: Eval) -> Result<Eval, LeadErr> {
if args.len() != 0 {
return Err(LeadErr {

View File

@@ -0,0 +1,76 @@
use std::collections::HashSet;
use crate::{
cell::CellRef,
common::{LeadErr, LeadErrCode, Literal},
evaluator::{Eval, evaluate_expr},
grid::Grid,
parser::Expr,
};
pub fn eval_single_arg_numeric(
args: &Vec<Expr>,
precs: &mut HashSet<CellRef>,
grid: Option<&Grid>,
func: fn(f64) -> f64,
func_name: String,
) -> Result<Eval, LeadErr> {
if args.len() != 1 {
return Err(LeadErr {
title: "Evaluation error.".into(),
desc: format!("{func_name} function requires a single argument."),
code: LeadErrCode::Invalid,
});
}
let err = LeadErr {
title: "Evaluation error.".into(),
desc: format!("{func_name} function requires a numeric argument."),
code: LeadErrCode::TypeErr,
};
match evaluate_expr(&args[0], precs, grid)? {
Eval::Literal(Literal::Number(num)) => Ok(Eval::Literal(Literal::Number(func(num)))),
Eval::CellRef { eval, .. } => match *eval {
Eval::Literal(Literal::Number(n)) => Ok(Eval::Literal(Literal::Number(func(n)))),
_ => Err(err),
},
_ => Err(err),
}
}
pub fn eval_n_arg_numeric(
n: usize,
args: &Vec<Expr>,
precs: &mut HashSet<CellRef>,
grid: Option<&Grid>,
func: fn(Vec<f64>) -> f64,
func_name: String,
) -> Result<Eval, LeadErr> {
if args.len() != n {
return Err(LeadErr {
title: "Evaluation error.".into(),
desc: format!("{func_name} function requires {n} argument(s)."),
code: LeadErrCode::Invalid,
});
}
let err = LeadErr {
title: "Evaluation error.".into(),
desc: format!("{func_name} function requires numeric argument(s)."),
code: LeadErrCode::TypeErr,
};
let mut numbers = Vec::with_capacity(n);
for arg in args {
match evaluate_expr(arg, precs, grid)? {
Eval::Literal(Literal::Number(num)) => numbers.push(num),
Eval::CellRef { eval, .. } => match *eval {
Eval::Literal(Literal::Number(num)) => numbers.push(num),
_ => return Err(err.clone()),
},
_ => return Err(err.clone()),
}
}
Ok(Eval::Literal(Literal::Number(func(numbers))))
}