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 { .. }); }