aboutsummaryrefslogtreecommitdiff
path: root/src/sexp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sexp')
-rw-r--r--src/sexp/mod.rs4
-rw-r--r--src/sexp/step.rs60
-rw-r--r--src/sexp/util.rs2
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())
}