diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sexp/mod.rs | 4 | ||||
-rw-r--r-- | src/sexp/step.rs | 60 | ||||
-rw-r--r-- | src/sexp/util.rs | 2 |
3 files changed, 57 insertions, 9 deletions
diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs index c920e41..087cb67 100644 --- a/src/sexp/mod.rs +++ b/src/sexp/mod.rs @@ -18,10 +18,12 @@ pub enum SLeaf { } /// An S-Expression; the defining structure of the language. +/// +/// This structure is not intended to correspond with +/// IETF-standardized s-expressions; they are only inspiration. #[derive(Debug)] #[derive(PartialEq)] pub enum SExp { SCons(Box<SExp>, Box<SExp>), Atom(SLeaf), } - diff --git a/src/sexp/step.rs b/src/sexp/step.rs index 86ad9ea..a6ce664 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -1,5 +1,5 @@ -use crate::sexp::SExp; +use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; impl SExp { @@ -13,22 +13,22 @@ impl SExp { /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( - /// sexp(Add, sexp(1, 1)).step().unwrap(), + /// scons(Add, scons(1, 1)).step().unwrap(), /// Atom(Int(2)) /// ); /// /// assert_eq!( - /// sexp(Sub, sexp(1, 2).step().unwrap()), + /// scons(Sub, scons(1, 2)).step().unwrap(), /// Atom(Int(-1)) /// ); /// /// assert_eq!( - /// sexp(Mul, sexp(2, 3).step().unwrap()), + /// scons(Mul, scons(2, 3)).step().unwrap(), /// Atom(Int(6)) /// ); /// /// assert_eq!( - /// sexp(Div, sexp(6, 2).step().unwrap()), + /// scons(Div, scons(6, 2)).step().unwrap(), /// Atom(Int(3)) /// ); /// ``` @@ -38,12 +38,58 @@ impl SExp { /// use melisp::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( - /// sexp(Div, sexp(5, 2).step().unwrap()), + /// 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<Self, String> { - todo!(); + 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)), + } } } diff --git a/src/sexp/util.rs b/src/sexp/util.rs index a4e3ab4..c31358f 100644 --- a/src/sexp/util.rs +++ b/src/sexp/util.rs @@ -22,6 +22,6 @@ impl From<i32> for SLeaf { } } -pub fn sexp(x: impl Into<Box<SExp>>, y: impl Into<Box<SExp>>) -> SExp { +pub fn scons(x: impl Into<Box<SExp>>, y: impl Into<Box<SExp>>) -> SExp { SCons(x.into(), y.into()) } |