use std::iter; use crate::sexp::SExp; use crate::sexp::SLeaf; use crate::sexp::SExp::*; use crate::sexp::SLeaf::*; impl From for Box { fn from(int: i32) -> Self { Box::new(Atom(Int(int))) } } impl From for SExp { fn from(bl: bool) -> Self { Atom( if bl { True } else { False } ) } } impl From for Box { fn from(leaf: SLeaf) -> Self { Box::new(Atom(leaf)) } } impl From for SLeaf { fn from(int: i32) -> Self { Int(int) } } pub fn scons(x: impl Into>, y: impl Into>) -> SExp { SCons(x.into(), y.into()) } 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 myslip::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()), } } pub fn parts(self) -> Vec { let mut res = vec![]; let mut se = self; loop { match se { Atom(Nil) => break, Atom(x) => { res.push(Atom(x)); break; }, SCons(a, b) => { res.push(*a); se = *b; } } } res } pub fn check_let(self) -> Option<(String, SExp)> { match &(self.parts())[..] { [l, n, v] if *l == Atom(Let) => match (n.clone(), v.clone()) { (Atom(Var(name)), val) => Some((name, val)), _ => None }, _ => None } } pub fn get_vars_bound_by_pattern(&self) -> Vec { match self { Atom(Var(s)) => vec![s.clone()], Atom(RestPat(s)) => vec![s.clone()], SCons(a, b) => (*a).get_vars_bound_by_pattern() .into_iter() .chain((*b).get_vars_bound_by_pattern()) .collect(), _ => vec![], } } pub fn get_case_scrut_pats_and_arms(self) -> Option<(SExp, Vec<(SExp, SExp)>)> { let (scrutinee, patarms) = self.check_case()?; let mut res = vec![]; for patarm in patarms { let (pat, arm) = match patarm { SCons(pat, arm) => Some((*pat, *arm)), _ => { println!("warn: invalid structure in case arms,"); println!(" should be unreachable after type checking"); None }, }?; let arm = match arm { SCons(x, n) if *n == Atom(Nil) => *x, t => t, }; res.push((pat, arm)); } Some((scrutinee, res)) } pub fn check_case(self) -> Option<(SExp, Vec)> { match &(self.parts())[..] { [casekw, scrutinee, cases @ ..] if casekw.clone() == Atom(Case) => Some((scrutinee.clone(), cases.to_vec())), _ => None, } } pub fn back_to_case(scrutinee: SExp, arms: Vec) -> SExp { let mut res = Atom(Nil); for arm in arms.into_iter().rev() { res = scons(arm, res); } scons(Case, scons(scrutinee, res)) } }