noctisroll 0.1.6

Text-based TRPG dice rolling system
Documentation
use std::str::FromStr;

use crate::{Dice, Filter};

grammar;

pub Expr: (i32, String) = {
    <l:Expr> "+" <r:Factor> => (l.0 + r.0, format!("{} + {}", l.1, r.1)),
    <l:Expr> "-" <r:Factor> => (l.0 - r.0, format!("{} - {}", l.1, r.1)),
    Factor,
};

Factor: (i32, String) = {
    <l:Factor> "*" <r:Term> => (l.0 * r.0, format!("{} * {}", l.1, r.1)),
    <l:Factor> "/" <r:Term> => (l.0 / r.0, format!("{} / {}", l.1, r.1)),
    <l:Factor> "//" <r:Term> => (l.0 / r.0, format!("{} // {}", l.1, r.1)),
    <l:Factor> "^" <r:Term> => (l.0.pow(r.0 as u32), format!("{} ^ {}", l.1, r.1)),
    <l:Factor> "**" <r:Term> => (l.0.pow(r.0 as u32), format!("{} ** {}", l.1, r.1)),
    <l:Factor> "%" <r:Term> => (l.0 % r.0, format!("{} % {}", l.1, r.1)),
    "+" <t:Term> => (t.0, format!("+{}", t.1)),
    "-" <t:Term> => (-t.0, format!("-{}", t.1)),
    Term,
};

Term: (i32, String) = {
    <d:Dice> => {
        let dice = d.roll();
        (dice.result as i32, dice.roll_str())
    },
    <n:Num> => (n as i32, n.to_string()),
    "(" <Expr> ")",
    "abs(" <e:Expr> ")" => {
        (e.0.abs(), format!("abs({})", e.1))
    },
    "cos(" <e:Expr> ")" => {
        let x = e.0 as f64;
        let result = x.cos();
        (result as i32, format!("cos({})", e.1))
    },
    "exp(" <e:Expr> ")" => {
        let x = e.0 as f64;
        let result = x.exp();
        (result as i32, format!("exp({})", e.1))
    },
    "floor(" <e:Expr> ")" => {
        let x = e.0 as f64;
        let result = x.floor();
        (result as i32, format!("floor({})", e.1))
    },
    "max(" <l:Expr> "," <r:Expr> ")" => {
        (l.0.max(r.0), format!("max({}, {})", l.1, r.1))
    },
    "min(" <l:Expr> "," <r:Expr> ")" => {
        (l.0.min(r.0), format!("min({}, {})", l.1, r.1))
    },
    "sin(" <e:Expr> ")" => {
        let x = e.0 as f64;
        let result = x.sin();
        (result as i32, format!("sin({})", e.1))
    },
    "sqrt(" <e:Expr> ")" => {
        let x = e.0 as f64;
        let result = x.sqrt();
        (result as i32, format!("sqrt({})", e.1))
    },
    "tan(" <e:Expr> ")" => {
        let x = e.0 as f64;
        let result = x.tan();
        (result as i32, format!("tan({})", e.1))
    },
};

Dice: Dice = {
    <dice:Dice> "k" <k:Num> => dice.filter(Filter::MaxN(k)),
    <dice:Dice> "q" <q:Num> => dice.filter(Filter::MinN(q)),
    FacedDice,
};

FacedDice: Dice = {
    <l:Num> "d" <r:Num> => Dice::new(l, r),
    "d" <r:Num> => Dice::new(1, r),
    "d" => Dice::new(1, 100),
};

Num: u32 = {
    r"[0-9]+" => u32::from_str(<>).unwrap(),
};