From cd68a2880db1400ae09ce0df64994b2bae33a3c1 Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Wed, 30 Jul 2025 17:27:15 +0300 Subject: 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 --- src/sexp/util.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/sexp/util.rs') 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. + /// + /// 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, String> { + match self { + SCons(a, b) => match (*a, *b) { + (Atom(a), Atom(Nil)) => Ok(iter::once(a).collect::>()), + (Atom(a), b) => Ok(iter::once(a).chain(b.into_vec()?).collect::>()), + (a, b) => Err(format!("invalid list structure: {:?}", scons(a, b))) + }, + _ => Err("expected list, found atom".to_string()), + } + } +} -- cgit v1.2.3