From b875aa1058339a17640817136037fb40451ca263 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 24 Aug 2024 19:00:01 -0600 Subject: [PATCH] rpn(1): more improvements --- src/rpn.rs | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/rpn.rs b/src/rpn.rs index d4056b6..42b30a1 100644 --- a/src/rpn.rs +++ b/src/rpn.rs @@ -120,14 +120,20 @@ impl Display for CalcType { #[derive(Debug, Clone)] struct EvaluationError { message: String, - code: ExitCode, + code: u8, +} + +impl StrError for EvaluationError { + fn strerror(&self) -> String { + self.message.clone() + } } /* 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; -fn err(argv0: &String, e: std::io::Error, code: Option) -> ExitCode { +fn err(argv0: &String, e: &T, code: Option) -> ExitCode { eprintln!("{}: {}", argv0, e.strerror()); ExitCode::from(code.unwrap_or(1 /* unknown error */)) } @@ -150,6 +156,7 @@ fn eval( .rev() .map(|t| CalcType::from(t)) .collect(); + let mut ops: VecDeque = VecDeque::new(); while let Some(n) = toks.pop_back() { @@ -157,18 +164,15 @@ fn eval( Val(v) => stack.push_back(v), Invalid(i) => { return Err(EvaluationError { - message: format!("{}: Invalid token", i), - code: ExitCode::from(EX_DATAERR), + message: format!("{}: invalid token", i), + code: EX_DATAERR, }) }, op => { ops.push_back(op.clone()); oper = true; /* this is an operation */ - let vals = ( - stack.pop_back(), - stack.pop_back(), - ); + let vals = (stack.pop_back(), stack.pop_back()); if let (Some(x), Some(y)) = vals { match op { @@ -183,8 +187,8 @@ fn eval( }; } else { return Err(EvaluationError { - message: format!("{}: Unexpected operation", op), - code: ExitCode::from(EX_DATAERR), + message: format!("{}: unexpected operation", op), + code: EX_DATAERR, }) } }, @@ -204,6 +208,7 @@ fn round_precise(value: &f64) -> f64 { (value * multiplier).round() / multiplier } +/* print the stack and let the caller know if evaluation should continue */ fn unstack(stack: VecDeque, op: bool) -> Result { if let Some(val) = stack.iter().last() { if !op { return Ok(true); } @@ -222,7 +227,7 @@ fn main() -> ExitCode { #[cfg(target_os="openbsd")] { let promises = Promises::new("stdio"); if let Err(e) = pledge(Some(promises), None) { - return err(&argv[0], e, Some(EX_OSERR)); + return err(&argv[0], &e, Some(EX_OSERR)); } } @@ -240,14 +245,16 @@ fn main() -> ExitCode { match eval(&input, stack) { Ok(s) => { + /* we can ignore the return value of unstack() because we are + * not continually evaluating from stdin */ if let Err(e) = unstack(s.0.clone(), s.1.clone()) { - return err(&argv[0], e, Some(EX_IOERR)); + return err(&argv[0], &e, Some(EX_IOERR)); } + return ExitCode::SUCCESS; - } + }, Err(e) => { - eprintln!("{}: {}", argv[0], e.message); - return e.code; + return err(&argv[0], &e, Some(e.code)); }, }; } @@ -255,23 +262,24 @@ fn main() -> ExitCode { /* else, read from stdin */ loop { /* take input until EOF */ if let Err(e) = stdin().read_line(&mut buf) { - return err(&argv[0], e, Some(EX_IOERR)); + return err(&argv[0], &e, Some(EX_IOERR)); } match eval(&buf.trim(), stack) { Ok(s) => { buf.clear(); - stack = s.0.clone(); + stack = s.0.clone(); /* out with the old, in with the new */ match unstack(s.0, s.1) { Ok(b) if b => continue, Ok(_) => break, - Err(e) => return err(&argv[0], e, Some(EX_IOERR)), + Err(e) => { + return err(&argv[0], &e, Some(EX_IOERR)) + }, }; }, Err(e) => { - eprintln!("{}: {}", argv[0], e.message); - return e.code; + return err(&argv[0], &e, Some(e.code)); }, }; }