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(),
};