extern crate honeycomb; use honeycomb::{ atoms::{eof, rec, seq, space, sym}, language::number, transform::to_number, Parser, }; #[test] fn calculator_test() { assert_eq!(eval(math().parse("1 + 3 + 4").unwrap()), 8.0); assert_eq!(eval(math().parse("4 + (1 + 3)").unwrap()), 8.0); assert_eq!(eval(math().parse("(4 + 1 + 3)").unwrap()), 8.0); assert_eq!(eval(math().parse("(4 + (1 + 3))").unwrap()), 8.0); assert_eq!(eval(math().parse("(4 + (1 * 3))").unwrap()), 7.0); assert_eq!(eval(math().parse("(4 + (1 / 2))").unwrap()), 4.5); assert_eq!(eval(math().parse("(4 + (1 - 2))").unwrap()), 3.0); assert_eq!(eval(math().parse("(7.0)").unwrap()), 7.0); assert_eq!(eval(math().parse("5").unwrap()), 5.0); } use std::sync::Arc; #[derive(Clone, Debug)] enum Math { Add(Arc, Arc), Multiply(Arc, Arc), Divide(Arc, Arc), Subtract(Arc, Arc), Number(f64), Exit, Clear, EOF, } fn token(symbol: &'static str) -> Parser { space() >> seq(symbol) << space() } fn operation(symbol: char, map_fn: fn((Math, Math)) -> Math) -> Parser { (number() - to_number - Math::Number | rec(math)) .suffix(space() & sym(symbol) & space()) .and(rec(math)) - map_fn } fn add() -> Parser { operation('+', |m| Math::Add(Arc::new(m.0), Arc::new(m.1))) } fn multiply() -> Parser { operation('*', |m| Math::Multiply(Arc::new(m.0), Arc::new(m.1))) } fn divide() -> Parser { operation('/', |m| Math::Divide(Arc::new(m.0), Arc::new(m.1))) } fn subtract() -> Parser { operation('-', |m| Math::Subtract(Arc::new(m.0), Arc::new(m.1))) } fn exit() -> Parser { (seq("exit") | seq("quit")) - |_| Math::Exit } fn clear() -> Parser { seq("clear") - |_| Math::Clear } fn math() -> Parser { exit() | eof() - (|_| Math::EOF) | clear() | token("(") >> rec(math) << token(")") | (number().is() >> (multiply() | divide() | add() | subtract() | (number() - to_number - Math::Number))) } fn eval(math: Math) -> f64 { match math { Math::Number(n) => n, Math::Add(a, b) => eval((*a).clone()) + eval((*b).clone()), Math::Subtract(a, b) => eval((*a).clone()) - eval((*b).clone()), Math::Divide(a, b) => eval((*a).clone()) / eval((*b).clone()), Math::Multiply(a, b) => eval((*a).clone()) * eval((*b).clone()), Math::Exit => std::process::exit(0), Math::Clear => { println!("{}", "\n".repeat(1000)); 0.0 } _ => 0.0, } }