rpn(1): better error handling

This commit is contained in:
Emma Tebibyte 2024-02-02 14:16:49 -07:00
parent 885f167afc
commit 4cb5e8e2b0
Signed by untrusted user: emma
GPG Key ID: 06FA419A1698C270

View File

@ -45,7 +45,7 @@
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
env::args, env::args,
fmt, fmt::{ self, Display, Formatter },
io::stdin, io::stdin,
process::ExitCode, process::ExitCode,
}; };
@ -70,19 +70,6 @@ enum CalcType {
Empty, 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)
}
}
// Im 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 { impl From<&str> for CalcType {
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
match value { 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)
}
}
// Im 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( fn eval(
input: &str, input: &str,
initial_stack: VecDeque<f64>, initial_stack: VecDeque<f64>,
) -> Result<VecDeque<f64>, EvaluationError> { ) -> Result<(VecDeque<f64>, bool), EvaluationError> {
let mut stack = initial_stack; let mut stack = initial_stack;
let mut oper = false;
if input.is_empty() { if input.is_empty() {
stack.clear(); stack.clear();
return Ok(stack); return Ok((stack, oper));
} }
// Split the input into tokens. // Split the input into tokens.
@ -122,7 +142,7 @@ fn eval(
let x: CalcType = match CalcType::from(tok) { let x: CalcType = match CalcType::from(tok) {
Empty => { Empty => {
return Err(EvaluationError { return Err(EvaluationError {
message: format!("Invalid token: {}", tok), message: format!("{}: Invalid token", tok),
}) })
}, },
x => x, x => x,
@ -136,13 +156,28 @@ fn eval(
for op in &ops { for op in &ops {
match op { match op {
Val(v) => { Val(_) => {
return Err(EvaluationError { message: format!( return Err(EvaluationError { message: format!(
"{}: Unexpected value in the operator stack.", "{}: 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) = ( let (x, y) = (
stack.pop_back().unwrap(), stack.pop_back().unwrap(),
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 // Round a float to the given precision level
@ -183,15 +218,17 @@ fn main() -> ExitCode {
while let Ok(_) = stdin().read_line(&mut buf) { while let Ok(_) = stdin().read_line(&mut buf) {
match eval(&buf.trim(), stack) { match eval(&buf.trim(), stack) {
Ok(s) => { Ok(s) => {
stack = s.clone(); buf.clear();
stack = s.0.clone();
let val = match stack.iter().last() { let val = match stack.iter().last() {
Some(v) => v, Some(v) => v,
None => break, None => break,
}; };
if s.1 == false { continue; }
println!("{}", round_precise(val, precision).to_string()); println!("{}", round_precise(val, precision).to_string());
buf.clear();
}, },
Err(err) => { Err(err) => {
eprintln!("{}: {}", argv[0], err.message); eprintln!("{}: {}", argv[0], err.message);
@ -209,7 +246,7 @@ fn main() -> ExitCode {
match eval(&input, stack) { match eval(&input, stack) {
Ok(s) => { Ok(s) => {
stack = s.clone(); stack = s.0.clone();
let val = match stack.iter().last() { let val = match stack.iter().last() {
Some(v) => v, Some(v) => v,