This commit is contained in:
2025-09-10 02:17:25 +10:00
parent c88d1965c3
commit 2c058a654f
11 changed files with 236 additions and 63 deletions

View File

@@ -19,6 +19,7 @@ pub enum LeadErrCode {
Syntax,
Server,
Unsupported,
Invalid,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

View File

@@ -7,6 +7,7 @@ use crate::common::Literal;
use crate::grid::Grid;
use crate::parser::*;
use std::collections::HashSet;
use std::f64;
use std::fmt;
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
@@ -117,6 +118,15 @@ 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)?,
"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())?,
"TAN" => eval_single_arg_numeric(args, precs, grid, |x| x.tan(), "TAN".into())?,
"ASIN" => eval_single_arg_numeric(args, precs, grid, |x| x.asin(), "ASIN".into())?,
"ACOS" => eval_single_arg_numeric(args, precs, grid, |x| x.acos(), "ACOS".into())?,
"ATAN" => eval_single_arg_numeric(args, precs, grid, |x| x.atan(), "ATAN".into())?,
"PI" => eval_const(args, Eval::Literal(Literal::Number(f64::consts::PI)))?,
"TAU" => eval_const(args, Eval::Literal(Literal::Number(f64::consts::TAU)))?,
it => {
return Err(LeadErr {
title: "Evaluation error.".into(),
@@ -256,6 +266,49 @@ 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 {
title: "Evaluation error.".into(),
desc: format!("PI function requires no arguments."),
code: LeadErrCode::Invalid,
});
}
Ok(value)
}
fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
match (lval, rval) {
(Eval::Literal(a), Eval::Literal(b)) => {

View File

@@ -79,17 +79,23 @@ async fn accept_connection(stream: TcpStream) {
}
}
let msg = LeadMsg {
cell: None,
raw: None,
eval: None,
bulk_msgs: Some(msgs),
msg_type: MsgType::Bulk,
};
if msgs.len() == 1 {
let _ = write
.send(serde_json::to_string(&msgs.get(0)).unwrap().into())
.await;
} else if msgs.len() > 1 {
let msg = LeadMsg {
cell: None,
raw: None,
eval: None,
bulk_msgs: Some(msgs),
msg_type: MsgType::Bulk,
};
let _ = write
.send(serde_json::to_string(&msg).unwrap().into())
.await;
let _ = write
.send(serde_json::to_string(&msg).unwrap().into())
.await;
}
}
Err(e) => {
let res = LeadMsg {

View File

@@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use crate::{cell::CellRef, evaluator::Eval};
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum MsgType {
Set,
@@ -11,7 +11,7 @@ pub enum MsgType {
Bulk,
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct LeadMsg {
pub msg_type: MsgType,
pub cell: Option<CellRef>,