Added basic math error checking

pull/2/head
Mark 2023-03-28 14:36:53 -07:00
parent eb101439d9
commit a90c00c18d
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
3 changed files with 62 additions and 25 deletions

View File

@ -30,7 +30,7 @@ pub fn evaluate(
let p = get_at_coords(&mut g, &coords); let p = get_at_coords(&mut g, &coords);
let e = p.eval(); let e = p.eval()?;
*p = e; *p = e;
if coords.len() == 0 { break 'outer; } if coords.len() == 0 { break 'outer; }

View File

@ -94,11 +94,12 @@ fn main() -> Result<(), std::io::Error> {
Ok(g) => { Ok(g) => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
RawTerminal::suspend_raw_mode(&stdout)?; RawTerminal::suspend_raw_mode(&stdout)?;
let g = evaluate::evaluate(g).unwrap(); let g = evaluate::evaluate(g);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
RawTerminal::activate_raw_mode(&stdout)?; RawTerminal::activate_raw_mode(&stdout)?;
if let Token::Number(v) = g { match g {
Ok(Token::Number(v)) => {
write!( write!(
stdout, "\r\n {}{}={} {v}{}\r\n\n", stdout, "\r\n {}{}={} {v}{}\r\n\n",
style::Bold, style::Bold,
@ -106,7 +107,19 @@ fn main() -> Result<(), std::io::Error> {
style::Reset, style::Reset,
color::Fg(color::Reset) color::Fg(color::Reset)
)?; )?;
} else { panic!(); } },
Err(_) => {
write!(
stdout, "\r\n {}{}Mathematical Error: {}Failed to evaluate expression.is{}\r\n\n",
style::Bold,
color::Fg(color::Red),
style::Reset,
color::Fg(color::Reset),
)?;
}
_ => panic!()
}
}, },
// Show parse error // Show parse error
@ -164,7 +177,7 @@ mod tests {
let s = String::from(s); let s = String::from(s);
let g = parser::parse(&s).unwrap(); let g = parser::parse(&s).unwrap();
let g = evaluate::evaluate(g).unwrap(); let g = evaluate::evaluate(g).unwrap();
let n = g.eval(); let n = g.eval().unwrap();
let tokens::Token::Number(v) = n else {panic!()}; let tokens::Token::Number(v) = n else {panic!()};
assert_eq!(v, r); assert_eq!(v, r);
} }

View File

@ -25,12 +25,12 @@ impl Token {
} }
#[inline(always)] #[inline(always)]
pub fn eval(&self) -> Token { pub fn eval(&self) -> Result<Token, ()> {
match self { Ok(match self {
Token::Number(v) => { Token::Number(*v) }, Token::Number(v) => { Token::Number(*v) },
Token::Constant(v,_) => { Token::Number(*v) }, Token::Constant(v,_) => { Token::Number(*v) },
Token::Operator(o,v) => { o.apply(v) } Token::Operator(o,v) => { o.apply(v)? }
} })
} }
// Temporary solution // Temporary solution
@ -162,7 +162,7 @@ impl Operator {
} }
impl Operator{ impl Operator{
pub fn apply(&self, args: &VecDeque<Token>) -> Token { pub fn apply(&self, args: &VecDeque<Token>) -> Result<Token, ()> {
match self { match self {
Operator::ImplicitMultiply | Operator::ImplicitMultiply |
Operator::Sqrt | Operator::Sqrt |
@ -175,7 +175,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 {
Token::Number(-v) return Ok(Token::Number(-v));
} else { panic!(); } } else { panic!(); }
}, },
@ -184,7 +184,8 @@ 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 {
Token::Number(1f64/v) if v == 0f64 { return Err(()); }
return Ok(Token::Number(1f64/v));
} else { panic!(); } } else { panic!(); }
}, },
@ -198,7 +199,7 @@ impl Operator{
panic!(); panic!();
} }
} }
Token::Number(sum) return Ok(Token::Number(sum));
}, },
Operator::Multiply => { Operator::Multiply => {
@ -211,7 +212,7 @@ impl Operator{
panic!(); panic!();
} }
} }
Token::Number(prod) return Ok(Token::Number(prod));
}, },
Operator::Modulo => { Operator::Modulo => {
@ -221,7 +222,11 @@ impl Operator{
if let Token::Number(va) = a { if let Token::Number(va) = a {
if let Token::Number(vb) = b { if let Token::Number(vb) = b {
Token::Number(va%vb) if vb <= 1f64 { return Err(()); }
if va.fract() != 0f64 { return Err(()); }
if vb.fract() != 0f64 { return Err(()); }
return Ok(Token::Number(va%vb));
} else { panic!(); } } else { panic!(); }
} else { panic!(); } } else { panic!(); }
}, },
@ -233,13 +238,32 @@ impl Operator{
if let Token::Number(va) = a { if let Token::Number(va) = a {
if let Token::Number(vb) = b { if let Token::Number(vb) = b {
Token::Number(va.powf(vb)) let p = va.powf(vb);
if p.is_nan() {return Err(());}
return Ok(Token::Number(p));
} else { panic!(); } } else { panic!(); }
} else { panic!(); } } else { panic!(); }
}, },
Operator::Factorial => { todo!() }, Operator::Factorial => {
if args.len() != 1 {panic!()};
let args = args[0].as_number();
if let Token::Number(v) = args {
if v.fract() != 0f64 { return Err(()); }
if v >= 100f64 { return Err(()); }
let mut prod = 1f64;
let mut u = v;
while u > 0f64 {
prod *= u;
u -= 1f64;
} }
return Ok(Token::Number(prod));
} else { panic!(); }
},
};
} }
} }