use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; impl SExp { /// Evaluates the s-expression one step. /// /// **Integer operations** /// /// Addition, subtraction, multiplication and division /// are supported. /// ```rust /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( /// scons(Add, scons(1, 1)).step().unwrap(), /// Atom(Int(2)) /// ); /// /// assert_eq!( /// scons(Sub, scons(1, 2)).step().unwrap(), /// Atom(Int(-1)) /// ); /// /// assert_eq!( /// scons(Mul, scons(2, 3)).step().unwrap(), /// Atom(Int(6)) /// ); /// /// assert_eq!( /// scons(Div, scons(6, 2)).step().unwrap(), /// Atom(Int(3)) /// ); /// ``` /// /// Division truncates the decimals. /// ```rust /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( /// scons(Div, scons(5, 2)).step().unwrap(), /// Atom(Int(2)) /// ); /// /// ``` /// /// Here's an example of a bit more complicated expression: /// ```rust /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// fn main() { /// let exp = scons(Mul, scons( /// 2, /// scons(Add, scons( /// scons(Div, scons(5, 2)), /// 4 /// )) /// )); /// /// let exp = exp.step().unwrap(); /// assert_eq!(exp, scons(Mul, scons(2, scons(Add, scons(2, 4))))); /// /// let exp = exp.step().unwrap(); /// assert_eq!(exp, scons(Mul, scons(2, 6))); /// /// let exp = exp.step().unwrap(); /// assert_eq!(exp, Atom(Int(12))); /// } /// /// ``` pub fn step(self) -> Result { match self { SCons(op, e1) if *op == Atom(Add) || *op == Atom(Sub) || *op == Atom(Mul) || *op == Atom(Div) => match *e1 { SCons(e1, e2) => match (*e1, *e2) { (Atom(Int(a)), Atom(Int(b))) => match *op { Atom(Add) => Ok(Atom(Int(a + b))), Atom(Sub) => Ok(Atom(Int(a - b))), Atom(Mul) => Ok(Atom(Int(a * b))), Atom(Div) => Ok(Atom(Int(a / b))), _ => panic!("unreachable as per match arm"), } (Atom(Int(a)), e2) => Ok(scons(op, scons(a, e2.step()?))), (e1, e2) => Ok(scons(op, scons(e1.step()?, e2))), }, _ => Err(format!("{:?} should be given two arguments, only one was given: {:?}", op, e1)), }, t => Err(format!("unimplemented: {:?}.step()", t)), } } }