From 24a7cb3c8eb0517b69c145170765c891a82ccc76 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Tue, 5 Mar 2019 14:56:46 -0500 Subject: add debug_expr command --- src/commands/mod.rs | 5 +++++ src/commands/roll.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 5dd98d8..4619a5a 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -60,6 +60,11 @@ pub fn register_commands(f: StandardFramework) -> StandardFramework { .desc("simulate rolling dice") .guild_only(true) .exec(roll::roll)) + .command("debug_expr", |c| c + .desc("debug calculator expression") + .owners_only(true) + .exec(roll::debug_expr) + ) .unrecognised_command(|ctx, msg, unrec| { let url = match msg.content.split_whitespace().skip(1).next() { Some(x) if x.starts_with("http") => x, diff --git a/src/commands/roll.rs b/src/commands/roll.rs index 733fc76..bdb729e 100644 --- a/src/commands/roll.rs +++ b/src/commands/roll.rs @@ -1,4 +1,5 @@ use failure::Error; +use itertools::Itertools; use nom::{ self, double, @@ -26,8 +27,9 @@ enum CalcExpr { #[derive(Clone, Debug, PartialEq, Fail)] enum CalcParseError { - #[fail(display = "couldn't consume entire expression. remaining: '{}'.", remaining)] + #[fail(display = "couldn't consume entire expression. parsed: {:?}, remaining: '{}'.", parsed, remaining)] NotReadToEnd { + parsed: Box, remaining: String, }, #[fail(display = "nom error: {}", _0)] @@ -41,6 +43,7 @@ impl CalcExpr { .and_then(|(s, res)| { if s.len() != 0 { Err(CalcParseError::NotReadToEnd { + parsed: res, remaining: s.as_ref().to_owned(), }) } else { @@ -50,13 +53,43 @@ impl CalcExpr { .map_err(Error::from) } - pub fn compute(self: Box) -> f64 { + pub fn pretty(&self) -> String { + format!("```\n{}\n```", self.pretty_helper(0)) + } + + fn pretty_helper(&self, depth: usize) -> String { + match self { + CalcExpr::Binary(op, e1, e2) => { + let lines = vec! { + format!("{}{:?} ({}) {{", "\t".repeat(depth), op, self.compute()), + e1.pretty_helper(depth + 1), + e2.pretty_helper(depth + 1), + "\t".repeat(depth) + "}", + }; + + lines.into_iter().join("\n") + }, + CalcExpr::Unary(op, e) => { + let lines = vec! { + format!("{}{:?} ({}) {{", "\t".repeat(depth), op, self.compute()), + e.pretty_helper(depth + 1), + "\t".repeat(depth) + "}", + }; + + lines.into_iter().join("\n") + }, + CalcExpr::Term(val) => { + format!("{}{}", "\t".repeat(depth), val) + } + } + } + + pub fn compute(&self) -> f64 { use self::CalcExpr::*; use self::BinOp::*; use self::UnaryOp::*; - let s = *self; - match s { + match self { Binary(bop, e1, e2) => { let r1 = e1.compute(); let r2 = e2.compute(); @@ -97,7 +130,7 @@ impl CalcExpr { Round => r.round(), } }, - Term(v) => v, + Term(v) => *v, } } } @@ -293,7 +326,7 @@ pub fn roll(_ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { Ok(expr) => send(msg.channel_id, &format!("{}", expr.compute()), msg.tts), Err(e) => { let parse_err = e.downcast::().unwrap(); - if let CalcParseError::NotReadToEnd { remaining } = parse_err { + if let CalcParseError::NotReadToEnd { remaining, .. } = parse_err { error!("parsing '{}': failed to consume '{}'", args.rest(), remaining); send(msg.channel_id, "I COULDN'T READ THAT YOU FUCK", msg.tts) } else { @@ -302,3 +335,17 @@ pub fn roll(_ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { }, } } + +pub fn debug_expr(_ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { + match CalcExpr::parse(args.rest()) { + Ok(expr) => send(msg.channel_id, &expr.pretty(), false), + Err(e) => { + let parse_err = e.downcast::().unwrap(); + if let CalcParseError::NotReadToEnd { remaining, parsed } = parse_err { + send(msg.channel_id, &format!("parsed this expr: {}\nwith remaining text: '{}'", parsed.pretty(), remaining), false) + } else { + Err(parse_err.into()) + } + } + } +} -- cgit v1.3.1