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, scons(1, Nil))).step(), /// Ok(Atom(Int(2))) /// ); /// /// assert_eq!( /// scons(Sub, scons(1, scons(2, Nil))).step(), /// Ok(Atom(Int(-1))) /// ); /// /// assert_eq!( /// scons(Mul, scons(2, scons(3, Nil))).step(), /// Ok(Atom(Int(6))) /// ); /// /// assert_eq!( /// scons(Div, scons(6, scons(2, Nil))).step(), /// Ok(Atom(Int(3))) /// ); /// ``` /// /// Division truncates the decimals. /// ```rust /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( /// scons(Div, scons(5, scons(2, Nil))).step(), /// Ok(Atom(Int(2))) /// ); /// ``` /// /// Also, addition and multiplication can take more than two arguments: /// ```rust /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( /// scons(Add, scons(1, scons(2, scons(3, Nil)))).step(), /// Ok(Atom(Int(6))) /// ); /// /// assert_eq!( /// scons(Mul, scons(1, scons(2, scons(3, Nil)))).step(), /// Ok(Atom(Int(6))) /// ); /// ``` /// /// Here's an example of a bit more complicated expression /// from wikipedias article on s-expressions. /// ```rust /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// fn main() { /// let exp = scons( /// Mul, /// scons( /// 2, /// scons( /// scons(Add, scons(3, scons(4, Nil))), /// Nil /// ) /// ) /// ); /// /// let exp = exp.step().unwrap(); /// assert_eq!(exp, scons(Mul, scons(2, scons(7, Nil)))); /// /// let exp = exp.step().unwrap(); /// assert_eq!(exp, Atom(Int(14))); /// } /// /// ``` 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)), } } }