use cmdparse::error::ParseError; use cmdparse::parsers::{ParsableTransformation, TransformParser}; use cmdparse::{parse_parser, Parsable}; use rustyline::error::ReadlineError; use rustyline::Editor; #[derive(Debug, Parsable)] enum Expression { #[cmd(transparent)] Value(f64), #[cmd(rename = "+")] Add( #[cmd(parser = "EvaluationParser")] f64, #[cmd(parser = "EvaluationParser")] f64, ), #[cmd(rename = "-")] Subtract( #[cmd(parser = "EvaluationParser")] f64, #[cmd(parser = "EvaluationParser")] f64, ), #[cmd(rename = "*")] Multiply( #[cmd(parser = "EvaluationParser")] f64, #[cmd(parser = "EvaluationParser")] f64, ), #[cmd(rename = "/")] Divide( #[cmd(parser = "EvaluationParser")] f64, #[cmd(parser = "EvaluationParser")] f64, ), Sqrt(#[cmd(parser = "EvaluationParser")] f64), } impl ParsableTransformation for Expression { type Input = Expression; fn transform(input: Self::Input) -> Result> { match input { Expression::Value(value) => Ok(value), Expression::Add(a, b) => Ok(a + b), Expression::Subtract(a, b) => Ok(a - b), Expression::Multiply(a, b) => Ok(a * b), Expression::Divide(_, b) if b == 0.0 => { Err(ParseError::custom("cannot divide by zero")) } Expression::Divide(a, b) => Ok(a / b), Expression::Sqrt(a) if a < 0.0 => Err(ParseError::custom( "cannot take square root of a negative number", )), Expression::Sqrt(a) => Ok(a.sqrt()), } } } type EvaluationParser = TransformParser; fn main() { let mut rl = Editor::<()>::new(); loop { let readline = rl.readline(">> "); match readline { Ok(line) => match parse_parser::<_, EvaluationParser>(&line, ()) { Ok(value) => println!("<< {}", value), Err(err) => println!("Error: {}", err), }, Err(ReadlineError::Interrupted | ReadlineError::Eof) => break, Err(err) => { println!("Error: {}", err); break; } } } }