From 074c7a10e410b6f88061f7ffee88802111ab06f0 Mon Sep 17 00:00:00 2001 From: Lilith Schier Date: Tue, 18 Aug 2026 20:28:25 +0200 Subject: [PATCH 1/3] added decimals --- src/dice.rs | 2 +- src/parsing.rs | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/dice.rs b/src/dice.rs index 522f3f6..12f51bf 100644 --- a/src/dice.rs +++ b/src/dice.rs @@ -480,7 +480,7 @@ impl<'a> WitnessSet for DiscordMdWitnessSet<'a> { type Error = DiscordMdWitnessError; fn witness_roll(&mut self, dice: DiceRoll) -> Result { - if self.parent.dice_written >= 100 { + if self.parent.dice_written >= 50 { if !self.dice_elided { write!(self.parent.buffer, "…")?; self.dice_elided = true; diff --git a/src/parsing.rs b/src/parsing.rs index 1a74101..329ce5b 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -1,5 +1,10 @@ -use crate::dice::{CompareFragment, DiceFormula, Expression::{self, Const}}; +use crate::dice::{ + CompareFragment, DiceFormula, + Expression::{self, Const}, +}; use Assoc::Left; +use nom::character::complete::digit0; +use nom::combinator::recognize; use nom::{ Parser, branch::alt, @@ -115,9 +120,12 @@ fn expr<'c, 'i>( } fn number(i: &str) -> IResult<&str, Expression> { - map_res(digit1(), |s: &str| s.parse::()) - .map(Const) - .parse_complete(i) + map_res( + alt((recognize((digit0, tag("."), digit1())), digit1())), + |s: &str| s.parse::(), + ) + .map(Const) + .parse_complete(i) } fn basic_operand<'c, 'i>( @@ -128,7 +136,7 @@ fn basic_operand<'c, 'i>( fn compare_fragment<'c, 'i>( ctx: &'c Context, -) -> impl Parser<&'i str, Output = CompareFragment, Error = InternalError<&'i str>> + use<'c, 'i> { +) -> impl Parser<&'i str, Output = CompareFragment, Error = InternalError<&'i str>> + use<'c, 'i> { use CompareFragment::*; alt(( preceded(tag("="), basic_operand(ctx)).map(|x| Eq(Box::new(x))), @@ -154,6 +162,18 @@ mod test { assert_matches!(expression, Expression::Dice { .. }); } + #[test] + pub fn parse_decimal() { + let expression = parse("2.5+2.5").unwrap(); + assert_matches!(expression, Expression::Add { .. }); + } + + #[test] + pub fn parse_decimal2() { + let expression = parse(".4*.8").unwrap(); + assert_matches!(expression, Expression::Mul { .. }); + } + #[test] pub fn parse_bare_dice() { let expression = parse("d8").unwrap(); From 9b78cf2786151ded2a5cadbc2fbb134d3fb77bb4 Mon Sep 17 00:00:00 2001 From: Lilith Schier Date: Tue, 18 Aug 2026 20:36:18 +0200 Subject: [PATCH 2/3] added exponentials --- src/dice.rs | 9 +++++++++ src/parsing.rs | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/dice.rs b/src/dice.rs index 12f51bf..11c267d 100644 --- a/src/dice.rs +++ b/src/dice.rs @@ -17,6 +17,7 @@ pub enum Expression { Mul(ExpBox, ExpBox), Div(ExpBox, ExpBox), IntDiv(ExpBox, ExpBox), + Pow(ExpBox, ExpBox), } #[derive(Debug, PartialEq, Clone)] @@ -265,6 +266,12 @@ impl Expression { let rhs = rhs_node.evaluate(rng, w, precedence)?; lhs.div_euclid(rhs) } + Pow(lhs_node, rhs_node) => { + let lhs = lhs_node.evaluate(rng, w, precedence)?; + write!(w, " ^ ")?; + let rhs = rhs_node.evaluate(rng, w, precedence)?; + lhs.powf(rhs) + } }; if needs_parens { write!(w, ")")?; @@ -326,6 +333,7 @@ impl Expression { Expression::Mul(lhs, rhs) => lhs.avg()? * rhs.avg()?, Expression::Div(lhs, rhs) => lhs.avg()? / rhs.avg()?, Expression::IntDiv(lhs, rhs) => lhs.avg()?.div_euclid(rhs.avg()?), + Expression::Pow(lhs, rhs) => lhs.avg()?.powf(rhs.avg()?), }; Ok(result) } @@ -377,6 +385,7 @@ impl Expression { match self { Const(_) => 1, Dice { .. } => 2, + Pow(_, _) => 4, Neg(_) => 5, Mul(_, _) | Div(_, _) | IntDiv(_, _) => 7, Add(_, _) | Sub(_, _) => 8, diff --git a/src/parsing.rs b/src/parsing.rs index 329ce5b..81dc420 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -94,6 +94,7 @@ fn expr<'c, 'i>( complete(unary_op(5, tag("-"))), fail(), complete(alt(( + binary_op(4, Left, spaced_op("^")), binary_op(7, Left, spaced_op("*")), binary_op(7, Left, spaced_op("//")), binary_op(7, Left, spaced_op("/")), @@ -106,6 +107,7 @@ fn expr<'c, 'i>( Ok(match op { Prefix("-", x) => Neg(Box::new(x)), + Binary(lhs, "^", rhs) => Pow(Box::new(lhs), Box::new(rhs)), Binary(lhs, "*", rhs) => Mul(Box::new(lhs), Box::new(rhs)), Binary(lhs, "//", rhs) => IntDiv(Box::new(lhs), Box::new(rhs)), Binary(lhs, "/", rhs) => Div(Box::new(lhs), Box::new(rhs)), @@ -182,7 +184,7 @@ mod test { #[test] pub fn parse_math() { - let expression = parse("8 * 2 + 2 * 5").unwrap(); + let expression = parse("8 * 2 + 2 * 5 ^ 4").unwrap(); assert_matches!(expression, Expression::Add { .. }); } From 9dd6bee0e350a89be3eec67caefc1bb6ff089685 Mon Sep 17 00:00:00 2001 From: Lilith Schier Date: Thu, 20 Aug 2026 01:30:31 +0200 Subject: [PATCH 3/3] fixed exploding dice bug --- src/dice.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/dice.rs b/src/dice.rs index 11c267d..9c1b21e 100644 --- a/src/dice.rs +++ b/src/dice.rs @@ -122,9 +122,6 @@ impl Expression { // Exploding dice are early, they add rolls if let Some(fragments) = x { write!(w, "x")?; - if size < 2 { - bail!("Infinite explosion.") - } let mut comparers = Vec::with_capacity(fragments.len()); for fragment in fragments { comparers.push(fragment.comparer(rng, w)?); @@ -301,7 +298,7 @@ impl Expression { } else { 1 }; - if count > 1_000_000 { + if count > DICE_POOL_LIMIT { bail!("Too many dice.") }; let size = size.avg()? as i64;