rpn(1): better error handling
This commit is contained in:
parent
885f167afc
commit
4cb5e8e2b0
83
src/rpn.rs
83
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<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,
|
||||
|
Loading…
Reference in New Issue
Block a user