use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; impl SExp { /// Performs substitution on the s-expression. /// /// Replaces all free occurrences of variables /// named `name` with the given `value` /// in this s-expression. /// ```rust /// use myslip::sexp::{SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( /// scons(Add, scons(var("a"), var("b"))).subst("b", &scons(Sub, scons(2, 1))), /// scons(Add, scons(var("a"), scons(Sub, scons(2, 1)))) /// ); /// ``` pub fn subst(self, name: &str, value: &SExp) -> SExp { let ret = match self { SCons(a, b) => { if let Some((varname, _)) = a.clone().check_let() { if &varname == name { return SCons(a, b); } } if scons(a.clone(), b.clone()).is_fun() { let arglist = b.clone().parts()[0].clone(); let arglist = arglist.parts().into_iter().map(|exp| match exp { Atom(Var(s)) => s, _ => todo!(), }).collect::>(); if arglist.contains(&name.to_string()) { return SCons(a, b); } } if let Some((scrut, pavec)) = scons(a.clone(), b.clone()) .get_case_scrut_pats_and_arms() { let scrut = scrut.subst(name, value); let (structkind, scrut) = match scrut { SCons(q, v) if *q == Atom(Quote) || *q == Atom(Vector) => (Some(*q), *v), t => (None, t) }; let mut res = vec![]; for (pat, arm) in pavec { if pat .get_vars_bound_by_pattern() .contains(&name.to_string()) { res.push(scons(pat, arm)); } else { res.push(scons(pat, arm.subst(name, value))); } } let scrut = match structkind { Some(kind) => scons(kind, scrut), None => scrut, }; return SExp::back_to_case(scrut, res); } scons((*a).subst(name, value), (*b).subst(name, value)) }, Atom(Var(x)) if x == name => value.clone(), t => t, }; ret } }