aboutsummaryrefslogtreecommitdiff
path: root/src/sexp/subst.rs
blob: d09732fe27449a59426ffc631823ad356646f3fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

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 {
        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::<Vec<String>>();
		    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 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)));
			}
		    }
		    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,
        }
    }
}