diff options
| author | Nathan Perry <avaglir@gmail.com> | 2019-03-29 15:38:14 -0400 |
|---|---|---|
| committer | Nathan Perry <avaglir@gmail.com> | 2019-03-29 15:38:14 -0400 |
| commit | d066d8892fcb04a4a2854f6d5455851620eb8d62 (patch) | |
| tree | e1a01b56ba99557d773aeed87aeeea4701bc7207 | |
| parent | 5f63ea4a1991159348c2e7d7f519c3ac6cd46454 (diff) | |
use errors for calc rather than unwrapping everywhere
| -rw-r--r-- | src/commands/roll.rs | 87 |
1 files changed, 56 insertions, 31 deletions
diff --git a/src/commands/roll.rs b/src/commands/roll.rs index b447692..b7b98d6 100644 --- a/src/commands/roll.rs +++ b/src/commands/roll.rs @@ -1,3 +1,5 @@ +use std::result::Result as StdResult; + use rand::prelude::*; use serenity::{ framework::standard::Args, @@ -15,8 +17,20 @@ use crate::{ #[grammar = "commands/calc.pest"] struct Calc; +#[derive(Copy, Clone, Fail, Debug, PartialEq, Eq, Hash)] +pub(crate) enum CalcError { + #[fail(display = "pest was unable to parse the input")] + Pest, + + #[fail(display = "invalid number format")] + NumberFormat, + + #[fail(display = "bad argument count")] + ArgCount, +} + impl Calc { - fn eval<S: AsRef<str>>(s: S) -> Result<f64> { + fn eval<S: AsRef<str>>(s: S) -> StdResult<f64, CalcError> { use pest::{ Parser, prec_climber::PrecClimber, @@ -41,10 +55,10 @@ impl Calc { }; } - let result = Calc::parse(calc, s.as_ref())?; + let result = Calc::parse(calc, s.as_ref()).map_err(|_| CalcError::Pest)?; - fn eval_single_pair(pair: Pair<self::Rule>) -> f64 { - match pair.as_rule() { + fn eval_single_pair(pair: Pair<self::Rule>) -> StdResult<f64, CalcError> { + let result = match pair.as_rule() { oct | hex | binary => { let base = match pair.as_rule() { hex => 16, @@ -53,15 +67,15 @@ impl Calc { _ => unreachable!(), }; - u64::from_str_radix(&pair.as_str()[2..], base).unwrap() as f64 + u64::from_str_radix(&pair.as_str()[2..], base).map_err(|_| CalcError::NumberFormat)? as f64 }, - float => pair.as_str().parse::<f64>().unwrap(), - expr | num => eval_expr(pair.into_inner()), + float => pair.as_str().parse::<f64>().map_err(|_| CalcError::NumberFormat)?, + expr | num => eval_expr(pair.into_inner())?, unary_expr => { let mut p = pair.into_inner(); - let op = p.next().unwrap(); - let arg = eval_expr(p); + let op = p.next().ok_or(CalcError::ArgCount)?; + let arg = eval_expr(p)?; match op.as_rule() { log => arg.ln(), @@ -93,10 +107,10 @@ impl Calc { binary_expr => { let mut p = pair.into_inner(); - let op = p.next().unwrap(); + let op = p.next().ok_or(CalcError::ArgCount)?; - let arg1 = eval_single_pair(p.next().unwrap()); - let arg2 = eval_single_pair(p.next().unwrap()); + let arg1 = eval_single_pair(p.next().ok_or(CalcError::ArgCount)?)?; + let arg2 = eval_single_pair(p.next().ok_or(CalcError::ArgCount)?)?; assert!(p.next().is_none()); @@ -110,8 +124,8 @@ impl Calc { suffix_expr => { let mut p = pair.into_inner(); - let arg = eval_expr(p.next().unwrap().into_inner()); - let op = p.next().unwrap(); + let arg = eval_expr(p.next().ok_or(CalcError::ArgCount)?.into_inner())?; + let op = p.next().ok_or(CalcError::ArgCount)?; assert!(p.next().is_none()); @@ -121,32 +135,43 @@ impl Calc { } }, _ => unreachable!(), - } + }; + + Ok(result) } - fn eval_expr(p: Pairs<self::Rule>) -> f64 { + fn eval_expr(p: Pairs<self::Rule>) -> StdResult<f64, CalcError> { CLIMBER.climb( p, - eval_single_pair, - |lhs: f64, op, rhs: f64| match op.as_rule() { - add => lhs + rhs, - sub => lhs - rhs, - mul => lhs * rhs, - div => lhs / rhs, - pow => lhs.powf(rhs), - dice => { - let dice_count = lhs as usize; - let dice_faces = rhs as usize; + |pair| { + eval_single_pair(pair) + }, + |lhs, op, rhs| { + let lhs = lhs?; + let rhs = rhs?; + + let result = match op.as_rule() { + add => lhs + rhs, + sub => lhs - rhs, + mul => lhs * rhs, + div => lhs / rhs, + pow => lhs.powf(rhs), + dice => { + let dice_count = lhs as usize; + let dice_faces = rhs as usize; + + let mut rng = thread_rng(); + (0..dice_count).map(|_| rng.gen_range(1, dice_faces + 1)).sum::<usize>() as f64 + }, + _ => unreachable!(), + }; - let mut rng = thread_rng(); - (0..dice_count).map(|_| rng.gen_range(1, dice_faces + 1)).sum::<usize>() as f64 - }, - _ => unreachable!(), + Ok(result) } ) } - Ok(eval_expr(result)) + eval_expr(result) } } |
