From 4cb5e8e2b0e1cbfd44638953b494727f1cb473e6 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 2 Feb 2024 14:16:49 -0700 Subject: [PATCH] rpn(1): better error handling --- src/rpn.rs | 83 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/src/rpn.rs b/src/rpn.rs index 10c4e20..0f39187 100644 --- a/src/rpn.rs +++ b/src/rpn.rs @@ -45,7 +45,7 @@ use std::{ collections::VecDeque, env::args, - fmt, + fmt::{ self, Display, Formatter }, io::stdin, process::ExitCode, }; @@ -70,19 +70,6 @@ enum CalcType { Empty, } -#[derive(Debug, Clone)] -struct EvaluationError { pub message: String } - -impl fmt::Display for EvaluationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.message) - } -} - -// I’m no math nerd but I want the highest possible approximation of 0.9 -// repeating and it seems this can give it to me -const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0; - impl From<&str> for CalcType { fn from(value: &str) -> Self { match value { @@ -103,15 +90,48 @@ impl From<&str> for CalcType { } } +impl Display for CalcType { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let y: String; + write!(f, "{}", match self { + Add => "addition", + Subtract => "subtraction", + Multiply => "multiplication", + Divide => "division", + Power => "exponentiation", + Floor => "floor divion", + Modulo => "modulus", + Val(x) => { + y = x.to_string(); &y + }, + Empty => "", + }) + } +} + +#[derive(Debug, Clone)] +struct EvaluationError { pub message: String } + +impl Display for EvaluationError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +// I’m no math nerd but I want the highest possible approximation of 0.9 +// repeating and it seems this can give it to me +const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0; + fn eval( input: &str, initial_stack: VecDeque, -) -> Result, EvaluationError> { +) -> Result<(VecDeque, bool), EvaluationError> { let mut stack = initial_stack; + let mut oper = false; if input.is_empty() { stack.clear(); - return Ok(stack); + return Ok((stack, oper)); } // Split the input into tokens. @@ -122,7 +142,7 @@ fn eval( let x: CalcType = match CalcType::from(tok) { Empty => { return Err(EvaluationError { - message: format!("Invalid token: {}", tok), + message: format!("{}: Invalid token", tok), }) }, x => x, @@ -136,13 +156,28 @@ fn eval( for op in &ops { match op { - Val(v) => { + Val(_) => { return Err(EvaluationError { message: format!( "{}: Unexpected value in the operator stack.", - v + op, )}); }, _ => { + + if stack.len() < 2 { + return Err(EvaluationError { + message: format!("{}: Unexpected operation.", op) + }) + } + + if stack.len() > ops.len() + 1 { + return Err( + EvaluationError { message: format!("Syntax error.")} + ); + } + + oper = true; + let (x, y) = ( stack.pop_back().unwrap(), stack.pop_back().unwrap(), @@ -162,7 +197,7 @@ fn eval( }; } - Ok(stack) + Ok((stack, oper)) } // Round a float to the given precision level @@ -183,15 +218,17 @@ fn main() -> ExitCode { while let Ok(_) = stdin().read_line(&mut buf) { match eval(&buf.trim(), stack) { Ok(s) => { - stack = s.clone(); + buf.clear(); + stack = s.0.clone(); let val = match stack.iter().last() { Some(v) => v, None => break, }; + if s.1 == false { continue; } + println!("{}", round_precise(val, precision).to_string()); - buf.clear(); }, Err(err) => { eprintln!("{}: {}", argv[0], err.message); @@ -209,7 +246,7 @@ fn main() -> ExitCode { match eval(&input, stack) { Ok(s) => { - stack = s.clone(); + stack = s.0.clone(); let val = match stack.iter().last() { Some(v) => v,