diff options
| author | Nathan Perry <avaglir@gmail.com> | 2019-03-04 11:21:23 -0500 |
|---|---|---|
| committer | Nathan Perry <avaglir@gmail.com> | 2019-03-04 11:21:23 -0500 |
| commit | 12ae9736b384d58d65e9c67186321241e2488489 (patch) | |
| tree | 8a6e23695a43a8670f80c147010b1b3617270a5a /src/commands | |
| parent | 553e5b976ceef5430599ab9511f7fb48516375dd (diff) | |
improve assoc of roll
Diffstat (limited to 'src/commands')
| -rw-r--r-- | src/commands/mod.rs | 1 | ||||
| -rw-r--r-- | src/commands/roll.rs | 115 |
2 files changed, 78 insertions, 38 deletions
diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 2f18e9f..5dd98d8 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -56,6 +56,7 @@ pub fn register_commands(f: StandardFramework) -> StandardFramework { .guild_only(true) .exec(volume)) .command("roll", |c| c + .known_as("calc") .desc("simulate rolling dice") .guild_only(true) .exec(roll::roll)) diff --git a/src/commands/roll.rs b/src/commands/roll.rs index 9d130e6..ae6c4c2 100644 --- a/src/commands/roll.rs +++ b/src/commands/roll.rs @@ -114,47 +114,33 @@ enum UnaryOp { } fn parse_expr(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { - ws!(input, alt_complete!( - parse_infix | - parse_dice | - parse_binary_prefix | - parse_suffix | - parse_prefix | - parse_term_or_paren - )) -} - -fn parse_term_or_paren(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { - ws!(input, alt_complete!( - delimited!(char!('('), parse_expr, char!(')')) | - do_parse!( - dat: double >> - (Box::new(CalcExpr::Term(dat))) - ) - )) + ws!(input, up_to_add_sub_mod) } -fn parse_dice(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { +fn parse_add_sub_mod(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { ws!(input, do_parse!( - tpl: separated_pair!(parse_term_or_paren, ws!(char!('d')), parse_term_or_paren) >> + tpl: tuple!(up_to_div_mul, ws!(one_of!("+-%")), up_to_div_mul) >> ({ - let (expr1, expr2) = tpl; - Box::new(CalcExpr::Binary(BinOp::DiceRoll, expr1, expr2)) + let (expr1, op, expr2) = tpl; + let op = match op { + '+' => BinOp::Add, + '-' => BinOp::Sub, + '%' => BinOp::Mod, + _ => unreachable!(), + }; + Box::new(CalcExpr::Binary(op, expr1, expr2)) }) )) } -fn parse_infix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { +fn parse_div_mul(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { ws!(input, do_parse!( - tpl: tuple!(parse_term_or_paren, ws!(one_of!("+-*/%^")), parse_term_or_paren) >> + tpl: tuple!(up_to_binary_prefix, ws!(one_of!("/*")), up_to_binary_prefix) >> ({ let (expr1, op, expr2) = tpl; let op = match op { - '+' => BinOp::Add, - '-' => BinOp::Sub, '*' => BinOp::Mul, '/' => BinOp::Div, - '%' => BinOp::Mod, '^' => BinOp::Pow, _ => unreachable!(), }; @@ -163,7 +149,19 @@ fn parse_infix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { )) } -fn parse_prefix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { +fn parse_binary_prefix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { + ws!(input, do_parse!( + op: ws!(alt_complete!( + tag!("min") => { |_| BinOp::Min } | + tag!("max") => { |_| BinOp::Max } + )) >> + expr1: up_to_unary_prefix >> + expr2: up_to_unary_prefix >> + (Box::new(CalcExpr::Binary(op, expr1, expr2))) + )) +} + +fn parse_unary_prefix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { ws!(input, do_parse!( op: ws!(alt_complete!( tag!("log") => { |_| UnaryOp::Log } @@ -177,22 +175,36 @@ fn parse_prefix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> | tag!("floor") => { |_| UnaryOp::Floor } | tag!("abs") => { |_| UnaryOp::Abs } | tag!("round") => { |_| UnaryOp::Round } - | char!('-') => { |_| UnaryOp::Neg } )) >> - expr: parse_term_or_paren >> + expr: up_to_dice >> (Box::new(CalcExpr::Unary(op, expr))) )) } -fn parse_binary_prefix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { +fn parse_dice(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { ws!(input, do_parse!( - op: ws!(alt_complete!( - tag!("min") => { |_| BinOp::Min } | - tag!("max") => { |_| BinOp::Max } - )) >> - expr1: parse_term_or_paren >> - expr2: parse_term_or_paren >> - (Box::new(CalcExpr::Binary(op, expr1, expr2))) + tpl: separated_pair!(up_to_pow, ws!(char!('d')), up_to_pow) >> + ({ + let (expr1, expr2) = tpl; + Box::new(CalcExpr::Binary(BinOp::DiceRoll, expr1, expr2)) + }) + )) +} + +fn parse_pow(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { + ws!(input, do_parse!( + tpl: separated_pair!(up_to_neg, ws!(char!('^')), up_to_neg) >> + ({ + let (expr1, expr2) = tpl; + Box::new(CalcExpr::Binary(BinOp::Pow, expr1, expr2)) + }) + )) +} + +fn parse_neg(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { + ws!(input, do_parse!( + expr: ws!(preceded!(char!('-'), up_to_suffix)) >> + (Box::new(CalcExpr::Unary(UnaryOp::Neg, expr))) )) } @@ -203,6 +215,33 @@ fn parse_suffix(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> )) } +fn parse_term_or_paren(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { + ws!(input, alt_complete!( + delimited!(char!('('), parse_expr, char!(')')) | + do_parse!( + dat: double >> + (Box::new(CalcExpr::Term(dat))) + ) + )) +} + +macro_rules! up_to { + ($up_to_name:ident, $fn_name:ident, $prev:ident) => ( + fn $up_to_name(input: CompleteStr) -> nom::IResult<CompleteStr, Box<CalcExpr>> { + alt_complete!(input, $fn_name | $prev) + } + ) +} + +up_to! { up_to_add_sub_mod, parse_add_sub_mod, up_to_div_mul } +up_to! { up_to_div_mul, parse_div_mul, up_to_binary_prefix } +up_to! { up_to_binary_prefix, parse_binary_prefix, up_to_unary_prefix } +up_to! { up_to_unary_prefix, parse_unary_prefix, up_to_dice } +up_to! { up_to_dice, parse_dice, up_to_pow } +up_to! { up_to_pow, parse_pow, up_to_neg } +up_to! { up_to_neg, parse_neg, up_to_suffix } +up_to! { up_to_suffix, parse_suffix, parse_term_or_paren } + #[cfg(test)] mod test { use super::*; |
