🙃
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> {
|
fn eval_pos(val: &Eval) -> Result<Eval, LeadErr> {
|
||||||
match val {
|
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>,
|
args: &Vec<Expr>,
|
||||||
precs: &mut HashSet<CellRef>,
|
precs: &mut HashSet<CellRef>,
|
||||||
grid: Option<&Grid>,
|
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) => {
|
($fn_name:ident, $func:expr, $label:expr) => {
|
||||||
pub fn $fn_name(
|
pub fn $fn_name(
|
||||||
args: &Vec<Expr>,
|
args: &Vec<Expr>,
|
||||||
precs: &mut HashSet<CellRef>,
|
precs: &mut HashSet<CellRef>,
|
||||||
grid: Option<&Grid>,
|
grid: Option<&Grid>,
|
||||||
) -> Result<Eval, LeadErr> {
|
) -> 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_func!(eval_exp, |x| x.exp(), "EXP");
|
||||||
unary_numeric_func!(eval_log, |x| x.ln(), "LOG");
|
unary_func!(eval_log, |x| x.ln(), "LOG");
|
||||||
unary_numeric_func!(eval_sqrt, |x| x.sqrt(), "SQRT");
|
unary_func!(eval_sqrt, |x| x.sqrt(), "SQRT");
|
||||||
unary_numeric_func!(eval_abs, |x| x.abs(), "ABS");
|
unary_func!(eval_abs, |x| x.abs(), "ABS");
|
||||||
|
|
||||||
unary_numeric_func!(eval_sin, |x| x.sin(), "SIN");
|
unary_func!(eval_sin, |x| x.sin(), "SIN");
|
||||||
unary_numeric_func!(eval_cos, |x| x.cos(), "COS");
|
unary_func!(eval_cos, |x| x.cos(), "COS");
|
||||||
unary_numeric_func!(eval_tan, |x| x.tan(), "TAN");
|
unary_func!(eval_tan, |x| x.tan(), "TAN");
|
||||||
|
|
||||||
unary_numeric_func!(eval_asin, |x| x.asin(), "ASIN");
|
unary_func!(eval_asin, |x| x.asin(), "ASIN");
|
||||||
unary_numeric_func!(eval_acos, |x| x.acos(), "ACOS");
|
unary_func!(eval_acos, |x| x.acos(), "ACOS");
|
||||||
unary_numeric_func!(eval_atan, |x| x.atan(), "ATAN");
|
unary_func!(eval_atan, |x| x.atan(), "ATAN");
|
||||||
|
|
||||||
// -------------------------------------------------- //
|
// -------------------------------------------------- //
|
||||||
|
|
||||||
fn eval_const(args: &Vec<Expr>, value: Eval, label: &str) -> Result<Eval, LeadErr> {
|
fn eval_infix(
|
||||||
if args.len() != 0 {
|
lhs: &Eval,
|
||||||
return Err(LeadErr {
|
rhs: &Eval,
|
||||||
|
func: fn(f64, f64) -> f64,
|
||||||
|
func_name: &str,
|
||||||
|
) -> Result<Eval, LeadErr> {
|
||||||
|
let err = LeadErr {
|
||||||
title: "Evaluation error.".into(),
|
title: "Evaluation error.".into(),
|
||||||
desc: format!("{label} function requires no arguments."),
|
desc: format!("{func_name} function requires a numeric argument."),
|
||||||
code: LeadErrCode::Invalid,
|
code: LeadErrCode::TypeErr,
|
||||||
});
|
};
|
||||||
}
|
|
||||||
|
|
||||||
Ok(value)
|
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))))
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! const_numeric_func {
|
macro_rules! infix {
|
||||||
($fn_name:ident, $value:expr, $label:expr) => {
|
($fn_name:ident, $func:expr, $label:expr) => {
|
||||||
pub fn $fn_name(args: &Vec<Expr>) -> Result<Eval, LeadErr> {
|
pub fn $fn_name(lhs: &Eval, rhs: &Eval) -> Result<Eval, LeadErr> {
|
||||||
eval_const(args, $value, $label)
|
eval_infix(lhs, rhs, $func, $label)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const_numeric_func!(
|
// Can concat string as well
|
||||||
eval_pi,
|
pub fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, LeadErr> {
|
||||||
Eval::Literal(Literal::Number(std::f64::consts::PI)),
|
match (lval, rval) {
|
||||||
"PI"
|
(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!(
|
// Try string concatenation
|
||||||
eval_tau,
|
if let (Literal::String(x), Literal::String(y)) = (a, b) {
|
||||||
Eval::Literal(Literal::Number(std::f64::consts::TAU)),
|
let mut res = x.to_owned();
|
||||||
"TAU"
|
res.push_str(y);
|
||||||
);
|
return Ok(Eval::Literal(Literal::String(res)));
|
||||||
|
}
|
||||||
|
|
||||||
const_numeric_func!(
|
Err(LeadErr {
|
||||||
eval_sqrt2,
|
title: "Evaluation error.".into(),
|
||||||
Eval::Literal(Literal::Number(std::f64::consts::SQRT_2)),
|
desc: "Expected string or numeric types for ADD function.".into(),
|
||||||
"SQRT2"
|
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