🙃
This commit is contained in:
@@ -266,106 +266,6 @@ fn eval_range(
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
|
||||
match (lval, rval) {
|
||||
(Eval::Literal(a), Eval::Literal(b)) => {
|
||||
if let Some(res) = eval_numeric_infix(a, b, |x, y| x + y) {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
// Try string concatenation
|
||||
if let (Literal::String(x), Literal::String(y)) = (a, b) {
|
||||
let mut res = x.to_owned();
|
||||
res.push_str(y);
|
||||
return Ok(Eval::Literal(Literal::String(res)));
|
||||
}
|
||||
|
||||
Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected string or numeric types for ADD function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
})
|
||||
}
|
||||
_ => Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected string or numeric types for ADD function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_sub(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
|
||||
match (lval, rval) {
|
||||
(Eval::Literal(a), Eval::Literal(b)) => {
|
||||
if let Some(res) = eval_numeric_infix(a, b, |x, y| x - y) {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected numeric types for SUB function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
})
|
||||
}
|
||||
_ => Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected numeric types for SUB function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
|
||||
match (lval, rval) {
|
||||
(Eval::Literal(a), Eval::Literal(b)) => {
|
||||
if let Some(res) = eval_numeric_infix(a, b, |x, y| x * y) {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected numeric types for MUL function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
})
|
||||
}
|
||||
_ => Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected numeric types for MUL function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
|
||||
match (lval, rval) {
|
||||
(Eval::Literal(a), Eval::Literal(b)) => {
|
||||
if let (Literal::Number(_), Literal::Number(y)) = (a, b) {
|
||||
if *y == 0f64 {
|
||||
return Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Attempted to divide by zero.".into(),
|
||||
code: LeadErrCode::DivZero,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(res) = eval_numeric_infix(a, b, |x, y| x / y) {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected numeric types for DIV function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
})
|
||||
}
|
||||
_ => Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected numeric types for DIV function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_pos(val: &Eval) -> Result<Eval, LeadErr> {
|
||||
match val {
|
||||
|
||||
@@ -10,7 +10,47 @@ use crate::{
|
||||
|
||||
// -------------------------------------------------- //
|
||||
|
||||
fn eval_unary_numeric(
|
||||
fn eval_const(args: &Vec<Expr>, value: Eval, label: &str) -> Result<Eval, LeadErr> {
|
||||
if args.len() != 0 {
|
||||
return Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: format!("{label} function requires no arguments."),
|
||||
code: LeadErrCode::Invalid,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
macro_rules! const_func {
|
||||
($fn_name:ident, $value:expr, $label:expr) => {
|
||||
pub fn $fn_name(args: &Vec<Expr>) -> Result<Eval, LeadErr> {
|
||||
eval_const(args, $value, $label)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const_func!(
|
||||
eval_pi,
|
||||
Eval::Literal(Literal::Number(std::f64::consts::PI)),
|
||||
"PI"
|
||||
);
|
||||
|
||||
const_func!(
|
||||
eval_tau,
|
||||
Eval::Literal(Literal::Number(std::f64::consts::TAU)),
|
||||
"TAU"
|
||||
);
|
||||
|
||||
const_func!(
|
||||
eval_sqrt2,
|
||||
Eval::Literal(Literal::Number(std::f64::consts::SQRT_2)),
|
||||
"SQRT2"
|
||||
);
|
||||
|
||||
// -------------------------------------------------- //
|
||||
|
||||
fn eval_unary(
|
||||
args: &Vec<Expr>,
|
||||
precs: &mut HashSet<CellRef>,
|
||||
grid: Option<&Grid>,
|
||||
@@ -39,69 +79,103 @@ fn eval_unary_numeric(
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! unary_numeric_func {
|
||||
macro_rules! unary_func {
|
||||
($fn_name:ident, $func:expr, $label:expr) => {
|
||||
pub fn $fn_name(
|
||||
args: &Vec<Expr>,
|
||||
precs: &mut HashSet<CellRef>,
|
||||
grid: Option<&Grid>,
|
||||
) -> Result<Eval, LeadErr> {
|
||||
eval_unary_numeric(args, precs, grid, $func, $label)
|
||||
eval_unary(args, precs, grid, $func, $label)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unary_numeric_func!(eval_exp, |x| x.exp(), "EXP");
|
||||
unary_numeric_func!(eval_log, |x| x.ln(), "LOG");
|
||||
unary_numeric_func!(eval_sqrt, |x| x.sqrt(), "SQRT");
|
||||
unary_numeric_func!(eval_abs, |x| x.abs(), "ABS");
|
||||
unary_func!(eval_exp, |x| x.exp(), "EXP");
|
||||
unary_func!(eval_log, |x| x.ln(), "LOG");
|
||||
unary_func!(eval_sqrt, |x| x.sqrt(), "SQRT");
|
||||
unary_func!(eval_abs, |x| x.abs(), "ABS");
|
||||
|
||||
unary_numeric_func!(eval_sin, |x| x.sin(), "SIN");
|
||||
unary_numeric_func!(eval_cos, |x| x.cos(), "COS");
|
||||
unary_numeric_func!(eval_tan, |x| x.tan(), "TAN");
|
||||
unary_func!(eval_sin, |x| x.sin(), "SIN");
|
||||
unary_func!(eval_cos, |x| x.cos(), "COS");
|
||||
unary_func!(eval_tan, |x| x.tan(), "TAN");
|
||||
|
||||
unary_numeric_func!(eval_asin, |x| x.asin(), "ASIN");
|
||||
unary_numeric_func!(eval_acos, |x| x.acos(), "ACOS");
|
||||
unary_numeric_func!(eval_atan, |x| x.atan(), "ATAN");
|
||||
unary_func!(eval_asin, |x| x.asin(), "ASIN");
|
||||
unary_func!(eval_acos, |x| x.acos(), "ACOS");
|
||||
unary_func!(eval_atan, |x| x.atan(), "ATAN");
|
||||
|
||||
// -------------------------------------------------- //
|
||||
|
||||
fn eval_const(args: &Vec<Expr>, value: Eval, label: &str) -> Result<Eval, LeadErr> {
|
||||
if args.len() != 0 {
|
||||
return Err(LeadErr {
|
||||
fn eval_infix(
|
||||
lhs: &Eval,
|
||||
rhs: &Eval,
|
||||
func: fn(f64, f64) -> f64,
|
||||
func_name: &str,
|
||||
) -> Result<Eval, LeadErr> {
|
||||
let err = LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: format!("{label} function requires no arguments."),
|
||||
code: LeadErrCode::Invalid,
|
||||
});
|
||||
desc: format!("{func_name} function requires a numeric argument."),
|
||||
code: LeadErrCode::TypeErr,
|
||||
};
|
||||
|
||||
let l = match lhs.to_owned() {
|
||||
Eval::Literal(Literal::Number(num)) => num,
|
||||
Eval::CellRef { eval, .. } => match *eval {
|
||||
Eval::Literal(Literal::Number(num)) => num,
|
||||
_ => return Err(err),
|
||||
},
|
||||
_ => return Err(err),
|
||||
};
|
||||
|
||||
let r = match rhs.to_owned() {
|
||||
Eval::Literal(Literal::Number(num)) => num,
|
||||
Eval::CellRef { eval, .. } => match *eval {
|
||||
Eval::Literal(Literal::Number(num)) => num,
|
||||
_ => return Err(err),
|
||||
},
|
||||
_ => return Err(err),
|
||||
};
|
||||
|
||||
Ok(Eval::Literal(Literal::Number(func(l, r))))
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
macro_rules! const_numeric_func {
|
||||
($fn_name:ident, $value:expr, $label:expr) => {
|
||||
pub fn $fn_name(args: &Vec<Expr>) -> Result<Eval, LeadErr> {
|
||||
eval_const(args, $value, $label)
|
||||
macro_rules! infix {
|
||||
($fn_name:ident, $func:expr, $label:expr) => {
|
||||
pub fn $fn_name(lhs: &Eval, rhs: &Eval) -> Result<Eval, LeadErr> {
|
||||
eval_infix(lhs, rhs, $func, $label)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const_numeric_func!(
|
||||
eval_pi,
|
||||
Eval::Literal(Literal::Number(std::f64::consts::PI)),
|
||||
"PI"
|
||||
);
|
||||
// Can concat string as well
|
||||
pub fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
|
||||
match (lval, rval) {
|
||||
(Eval::Literal(a), Eval::Literal(b)) => {
|
||||
if let Ok(res) = eval_infix(lval, rval, |x, y| x + y, "ADD") {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
const_numeric_func!(
|
||||
eval_tau,
|
||||
Eval::Literal(Literal::Number(std::f64::consts::TAU)),
|
||||
"TAU"
|
||||
);
|
||||
// Try string concatenation
|
||||
if let (Literal::String(x), Literal::String(y)) = (a, b) {
|
||||
let mut res = x.to_owned();
|
||||
res.push_str(y);
|
||||
return Ok(Eval::Literal(Literal::String(res)));
|
||||
}
|
||||
|
||||
const_numeric_func!(
|
||||
eval_sqrt2,
|
||||
Eval::Literal(Literal::Number(std::f64::consts::SQRT_2)),
|
||||
"SQRT2"
|
||||
);
|
||||
Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected string or numeric types for ADD function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
})
|
||||
}
|
||||
_ => Err(LeadErr {
|
||||
title: "Evaluation error.".into(),
|
||||
desc: "Expected string or numeric types for ADD function.".into(),
|
||||
code: LeadErrCode::Unsupported,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------- //
|
||||
infix!(eval_sub, |x, y| x - y, "SUB");
|
||||
infix!(eval_mul, |x, y| x * y, "MUL");
|
||||
infix!(eval_div, |x, y| x / y, "DIV");
|
||||
|
||||
Reference in New Issue
Block a user