aboutsummaryrefslogtreecommitdiff
path: root/src/sexp/util.rs
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2025-07-30 17:27:15 +0300
committerJoel Kronqvist <joel.kronqvist@iki.fi>2025-07-30 17:27:15 +0300
commitcd68a2880db1400ae09ce0df64994b2bae33a3c1 (patch)
tree04893ee79ed16b920e7129b4eab1298a62814d65 /src/sexp/util.rs
parent8e2ca4bbc356d87ff5a37f20bea4f5b3cc561041 (diff)
downloadmyslip-cd68a2880db1400ae09ce0df64994b2bae33a3c1.tar.gz
myslip-cd68a2880db1400ae09ce0df64994b2bae33a3c1.zip
Implemented evaluation according to tests. Quite a bit of changes were required, see rest of commit message.
SExp::Quote was added to let the interpreter know whether a list should be evaluated or treated as a literal list. It still needs code to be added for parsing it successfully. Some utility functions were needed: * SExp::is_value * SExp::consists_of_values * SExp::into_vec
Diffstat (limited to 'src/sexp/util.rs')
-rw-r--r--src/sexp/util.rs29
1 files changed, 29 insertions, 0 deletions
diff --git a/src/sexp/util.rs b/src/sexp/util.rs
index ce6de5d..70ac152 100644
--- a/src/sexp/util.rs
+++ b/src/sexp/util.rs
@@ -1,4 +1,6 @@
+use std::iter;
+
use crate::sexp::SExp;
use crate::sexp::SLeaf;
use crate::sexp::SExp::*;
@@ -30,3 +32,30 @@ pub fn var(name: &str) -> SExp {
Atom(Var(name.to_string()))
}
+impl SExp {
+ /// Transforms this SExp into a Vec<SLeaf>.
+ ///
+ /// Errors if the left-hand side of SCons has an SCons,
+ /// or if the passed SExp is an Atom, or if the
+ /// lists aren't Nil-terminated.
+ ///
+ /// ```rust
+ /// use melisp::sexp::{SExp::*, SLeaf::*, util::*};
+ /// assert_eq!(
+ /// scons(1, scons(2, scons(3, Nil))).into_vec(),
+ /// Ok(vec![Int(1), Int(2), Int(3)])
+ /// );
+ /// assert!(scons(scons(1, Nil), Nil).into_vec().is_err());
+ /// assert!(scons(1, 2).into_vec().is_err());
+ /// ```
+ pub fn into_vec(self) -> Result<Vec<SLeaf>, String> {
+ match self {
+ SCons(a, b) => match (*a, *b) {
+ (Atom(a), Atom(Nil)) => Ok(iter::once(a).collect::<Vec<SLeaf>>()),
+ (Atom(a), b) => Ok(iter::once(a).chain(b.into_vec()?).collect::<Vec<SLeaf>>()),
+ (a, b) => Err(format!("invalid list structure: {:?}", scons(a, b)))
+ },
+ _ => Err("expected list, found atom".to_string()),
+ }
+ }
+}