Improved evaluator errors

pull/2/head
Mark 2023-04-10 18:53:35 -07:00
parent 0134bc5c12
commit ad3ae83c66
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
5 changed files with 40 additions and 19 deletions

View File

@ -11,6 +11,7 @@ use termion::{
style, style,
}; };
use crate::tokens::EvalError;
use super::promptbuffer::PromptBuffer; use super::promptbuffer::PromptBuffer;
use crate::parser; use crate::parser;
@ -103,9 +104,19 @@ pub fn main() -> Result<(), std::io::Error> {
)?; )?;
}, },
Err(_) => { Err(EvalError::BadMath) => {
write!( write!(
stdout, "\n {}{}Mathematical Error: {}Failed to evaluate expression.{}\r\n\n", stdout, "\n {}{}Mathematical Error: {}Failed to evaluate expression{}\r\n\n",
style::Bold,
color::Fg(color::Red),
style::Reset,
color::Fg(color::Reset),
)?;
},
Err(EvalError::IncompatibleUnit) => {
write!(
stdout, "\n {}{}Evaluation Error: {}Incompatible units{}\r\n\n",
style::Bold, style::Bold,
color::Fg(color::Red), color::Fg(color::Red),
style::Reset, style::Reset,

View File

@ -1,6 +1,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::tokens::Token; use crate::tokens::Token;
use crate::tokens::EvalError;
use crate::tokens::Operator; use crate::tokens::Operator;
#[derive(Debug)] #[derive(Debug)]
@ -65,13 +66,13 @@ impl Function {
} }
} }
pub fn apply(&self, args: &VecDeque<Token>) -> Result<Token, ()> { pub fn apply(&self, args: &VecDeque<Token>) -> Result<Token, EvalError> {
if args.len() != 1 {panic!()}; if args.len() != 1 {panic!()};
let a = args[0].as_number(); let a = args[0].as_number();
let Token::Number(q) = a else {panic!()}; let Token::Number(q) = a else {panic!()};
if !q.unitless() { if !q.unitless() {
return Err(()); return Err(EvalError::IncompatibleUnit);
} }
match self { match self {

View File

@ -4,4 +4,9 @@ mod token;
pub use crate::tokens::token::Token; pub use crate::tokens::token::Token;
pub use crate::tokens::function::Function; pub use crate::tokens::function::Function;
pub use crate::tokens::operator::Operator; pub use crate::tokens::operator::Operator;
pub enum EvalError {
BadMath,
IncompatibleUnit
}

View File

@ -3,8 +3,10 @@ use std::cmp::Ordering;
use crate::tokens::Token; use crate::tokens::Token;
use crate::tokens::Function; use crate::tokens::Function;
use crate::tokens::EvalError;
use crate::quantity::Quantity; use crate::quantity::Quantity;
/// Operator types, in order of increasing priority. /// Operator types, in order of increasing priority.
#[derive(Debug)] #[derive(Debug)]
#[derive(Clone)] #[derive(Clone)]
@ -331,7 +333,7 @@ impl Operator {
} }
impl Operator{ impl Operator{
pub fn apply(&self, args: &VecDeque<Token>) -> Result<Token, ()> { pub fn apply(&self, args: &VecDeque<Token>) -> Result<Token, EvalError> {
match self { match self {
Operator::ImplicitMultiply | Operator::ImplicitMultiply |
Operator::Sqrt | Operator::Sqrt |
@ -352,7 +354,7 @@ impl Operator{
let args = args[0].as_number(); let args = args[0].as_number();
if let Token::Number(v) = args { if let Token::Number(v) = args {
if v.is_zero() { return Err(()); } if v.is_zero() { return Err(EvalError::BadMath); }
return Ok(Token::Number( return Ok(Token::Number(
Quantity::new_rational(1f64).unwrap()/v Quantity::new_rational(1f64).unwrap()/v
)); ));
@ -371,7 +373,7 @@ impl Operator{
if let Token::Number(v) = j { if let Token::Number(v) = j {
if sum.unit() != v.unit() { if sum.unit() != v.unit() {
return Err(()); return Err(EvalError::IncompatibleUnit);
} }
sum += v; sum += v;
@ -406,12 +408,12 @@ impl Operator{
if let Token::Number(vb) = b { if let Token::Number(vb) = b {
if !(va.unitless() && vb.unitless()) { if !(va.unitless() && vb.unitless()) {
return Err(()); return Err(EvalError::IncompatibleUnit);
} }
if vb <= Quantity::new_rational(1f64).unwrap() { return Err(()); } if vb <= Quantity::new_rational(1f64).unwrap() { return Err(EvalError::BadMath); }
if va.fract() != Quantity::new_rational(0f64).unwrap() { return Err(()); } if va.fract() != Quantity::new_rational(0f64).unwrap() { return Err(EvalError::BadMath); }
if vb.fract() != Quantity::new_rational(0f64).unwrap() { return Err(()); } if vb.fract() != Quantity::new_rational(0f64).unwrap() { return Err(EvalError::BadMath); }
return Ok(Token::Number(va%vb)); return Ok(Token::Number(va%vb));
} else { panic!(); } } else { panic!(); }
@ -427,11 +429,11 @@ impl Operator{
if let Token::Number(vb) = b { if let Token::Number(vb) = b {
if va.unit() != vb.unit() { if va.unit() != vb.unit() {
return Err(()); return Err(EvalError::IncompatibleUnit);
} }
let p = va.pow(vb); let p = va.pow(vb);
if p.is_nan() {return Err(());} if p.is_nan() {return Err(EvalError::BadMath);}
return Ok(Token::Number(p)); return Ok(Token::Number(p));
} else { panic!(); } } else { panic!(); }
} else { panic!(); } } else { panic!(); }
@ -444,11 +446,11 @@ impl Operator{
if let Token::Number(v) = args { if let Token::Number(v) = args {
if !v.unitless() { if !v.unitless() {
return Err(()); return Err(EvalError::IncompatibleUnit);
} }
if !v.fract().is_zero() { return Err(()); } if !v.fract().is_zero() { return Err(EvalError::BadMath); }
if v > Quantity::new_rational(50_000f64).unwrap() { return Err(()); } if v > Quantity::new_rational(50_000f64).unwrap() { return Err(EvalError::IncompatibleUnit); }
let mut prod = Quantity::new_rational(1f64).unwrap(); let mut prod = Quantity::new_rational(1f64).unwrap();
let mut u = v.clone(); let mut u = v.clone();

View File

@ -1,8 +1,10 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::tokens::EvalError;
use crate::tokens::Operator; use crate::tokens::Operator;
use crate::quantity::Quantity; use crate::quantity::Quantity;
/// Tokens represent logical objects in an expession. /// Tokens represent logical objects in an expession.
/// ///
/// Tokens starting with `Pre*` are intermediate tokens, and /// Tokens starting with `Pre*` are intermediate tokens, and
@ -60,7 +62,7 @@ impl Token {
} }
#[inline(always)] #[inline(always)]
pub fn eval(&self) -> Result<Token, ()> { pub fn eval(&self) -> Result<Token, EvalError> {
Ok(match self { Ok(match self {
Token::Number(_) => { self.clone() }, Token::Number(_) => { self.clone() },
Token::Constant(v,_) => { Token::Number(v.clone()) }, Token::Constant(v,_) => { Token::Number(v.clone()) },
@ -96,7 +98,7 @@ impl Token {
} }
pub fn evaluate(&self) -> Result<Token, ()> { pub fn evaluate(&self) -> Result<Token, EvalError> {
let mut g = self.clone(); let mut g = self.clone();
let mut coords: Vec<usize> = Vec::with_capacity(16); let mut coords: Vec<usize> = Vec::with_capacity(16);
coords.push(0); coords.push(0);