diff options
Diffstat (limited to 'src/sexp/util.rs')
-rw-r--r-- | src/sexp/util.rs | 29 |
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()), + } + } +} |