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::{
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)
}
}
// 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 {
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)
}
}
// 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(
input: &str,
initial_stack: VecDeque<f64>,
) -> Result<VecDeque<f64>, EvaluationError> {
) -> Result<(VecDeque<f64>, 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,