rpn(1): more improvements

This commit is contained in:
Emma Tebibyte 2024-08-24 19:00:01 -06:00
parent cc53dab035
commit b875aa1058
Signed by untrusted user: emma
GPG Key ID: 06FA419A1698C270

View File

@ -120,14 +120,20 @@ impl Display for CalcType {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct EvaluationError { struct EvaluationError {
message: String, message: String,
code: ExitCode, code: u8,
}
impl StrError for EvaluationError {
fn strerror(&self) -> String {
self.message.clone()
}
} }
/* Im no math nerd but I want the highest possible approximation of 0.9 /* Im no math nerd but I want the highest possible approximation of 0.9
* repeating and it seems this can give it to me */ * repeating and it seems this can give it to me */
const PRECISION_MOD: f64 = 0.9 + f64::EPSILON; const PRECISION_MOD: f64 = 0.9 + f64::EPSILON;
fn err(argv0: &String, e: std::io::Error, code: Option<u8>) -> ExitCode { fn err<T: StrError>(argv0: &String, e: &T, code: Option<u8>) -> ExitCode {
eprintln!("{}: {}", argv0, e.strerror()); eprintln!("{}: {}", argv0, e.strerror());
ExitCode::from(code.unwrap_or(1 /* unknown error */)) ExitCode::from(code.unwrap_or(1 /* unknown error */))
} }
@ -150,6 +156,7 @@ fn eval(
.rev() .rev()
.map(|t| CalcType::from(t)) .map(|t| CalcType::from(t))
.collect(); .collect();
let mut ops: VecDeque<CalcType> = VecDeque::new(); let mut ops: VecDeque<CalcType> = VecDeque::new();
while let Some(n) = toks.pop_back() { while let Some(n) = toks.pop_back() {
@ -157,18 +164,15 @@ fn eval(
Val(v) => stack.push_back(v), Val(v) => stack.push_back(v),
Invalid(i) => { Invalid(i) => {
return Err(EvaluationError { return Err(EvaluationError {
message: format!("{}: Invalid token", i), message: format!("{}: invalid token", i),
code: ExitCode::from(EX_DATAERR), code: EX_DATAERR,
}) })
}, },
op => { op => {
ops.push_back(op.clone()); ops.push_back(op.clone());
oper = true; /* this is an operation */ oper = true; /* this is an operation */
let vals = ( let vals = (stack.pop_back(), stack.pop_back());
stack.pop_back(),
stack.pop_back(),
);
if let (Some(x), Some(y)) = vals { if let (Some(x), Some(y)) = vals {
match op { match op {
@ -183,8 +187,8 @@ fn eval(
}; };
} else { } else {
return Err(EvaluationError { return Err(EvaluationError {
message: format!("{}: Unexpected operation", op), message: format!("{}: unexpected operation", op),
code: ExitCode::from(EX_DATAERR), code: EX_DATAERR,
}) })
} }
}, },
@ -204,6 +208,7 @@ fn round_precise(value: &f64) -> f64 {
(value * multiplier).round() / multiplier (value * multiplier).round() / multiplier
} }
/* print the stack and let the caller know if evaluation should continue */
fn unstack(stack: VecDeque<f64>, op: bool) -> Result<bool, Error> { fn unstack(stack: VecDeque<f64>, op: bool) -> Result<bool, Error> {
if let Some(val) = stack.iter().last() { if let Some(val) = stack.iter().last() {
if !op { return Ok(true); } if !op { return Ok(true); }
@ -222,7 +227,7 @@ fn main() -> ExitCode {
#[cfg(target_os="openbsd")] { #[cfg(target_os="openbsd")] {
let promises = Promises::new("stdio"); let promises = Promises::new("stdio");
if let Err(e) = pledge(Some(promises), None) { 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) { match eval(&input, stack) {
Ok(s) => { 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()) { 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; return ExitCode::SUCCESS;
} },
Err(e) => { Err(e) => {
eprintln!("{}: {}", argv[0], e.message); return err(&argv[0], &e, Some(e.code));
return e.code;
}, },
}; };
} }
@ -255,23 +262,24 @@ fn main() -> ExitCode {
/* else, read from stdin */ /* else, read from stdin */
loop { /* take input until EOF */ loop { /* take input until EOF */
if let Err(e) = stdin().read_line(&mut buf) { 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) { match eval(&buf.trim(), stack) {
Ok(s) => { Ok(s) => {
buf.clear(); buf.clear();
stack = s.0.clone(); stack = s.0.clone(); /* out with the old, in with the new */
match unstack(s.0, s.1) { match unstack(s.0, s.1) {
Ok(b) if b => continue, Ok(b) if b => continue,
Ok(_) => break, Ok(_) => break,
Err(e) => return err(&argv[0], e, Some(EX_IOERR)), Err(e) => {
return err(&argv[0], &e, Some(EX_IOERR))
},
}; };
}, },
Err(e) => { Err(e) => {
eprintln!("{}: {}", argv[0], e.message); return err(&argv[0], &e, Some(e.code));
return e.code;
}, },
}; };
} }