bebop_lang/lisp/
eval.rs

1use crate::lisp::{Lenv, Lerr, LerrType, Llambda, Lval};
2
3pub fn eval(env: &mut Lenv, expr: Lval) -> Result<Lval, Lerr> {
4    match expr {
5        Lval::Sym(s) => eval_symbol(env, s),
6        Lval::Sexpr(vec) => eval_sexpression(env, vec),
7        _ => Ok(expr),
8    }
9}
10
11fn eval_symbol(env: &mut Lenv, s: String) -> Result<Lval, Lerr> {
12    match env.get(&s) {
13        Some(lval) => Ok(lval.clone()),
14        None => Err(Lerr::new(
15            LerrType::UnboundSymbol,
16            format!("{:?} has not been defined", s),
17        )),
18    }
19}
20
21fn eval_sexpression(env: &mut Lenv, sexpr: Vec<Lval>) -> Result<Lval, Lerr> {
22    // evaluate each element
23    let results = sexpr
24        .into_iter()
25        .map(|expr| eval(env, expr))
26        .collect::<Result<Vec<Lval>, Lerr>>()?;
27
28    if results.len() == 0 {
29        // if empty return empty
30        return Ok(Lval::Sexpr(results));
31    } else if results.len() == 1 {
32        // if singular value return singular value
33        let op = results[0].clone();
34        match op {
35            Lval::Fun(fun) => fun(env, vec![]),
36            Lval::Lambda(lambda) => call(env, lambda, vec![]),
37            _ => Ok(op),
38        }
39    } else {
40        let operands = (&results[1..]).to_vec();
41        // recognize a builtin function or a lambda
42        match results[0].clone() {
43            Lval::Fun(fun) => fun(env, operands),
44            Lval::Lambda(lambda) => call(env, lambda, operands),
45            _ => Err(Lerr::new(
46                LerrType::BadOp,
47                format!("{:?} is not a valid operator", results[0]),
48            )),
49        }
50    }
51}
52
53pub fn call(env: &mut Lenv, mut func: Llambda, mut args: Vec<Lval>) -> Result<Lval, Lerr> {
54    let given = args.len();
55    let total = func.args.len();
56
57    // load up all of the args
58    while args.len() != 0 {
59        // if too many args
60        if func.args.len() == 0 {
61            return Err(Lerr::new(
62                LerrType::IncorrectParamCount,
63                format!("Function needed {} arg(s) but was given {}", total, given),
64            ));
65        }
66        // pop the first element
67        let sym = func.args[0].clone();
68        // preserve the rest
69        func.args = func.args[1..].to_vec();
70
71        if sym == ":" {
72            if func.args.len() != 1 {
73                return Err(Lerr::new(
74                    LerrType::IncorrectParamCount,
75                    format!(": operator needs to be followed by arg"),
76                ));
77            }
78
79            let sym = func.args[0].clone();
80            func.args = func.args[1..].to_vec();
81            func.env.insert(&sym, Lval::Qexpr(args));
82            // sinning but we know that it will need to break here
83            break;
84        } else {
85            let val = args[0].clone();
86            args = args[1..].to_vec();
87            func.env.insert(&sym, val);
88        }
89    }
90
91    if func.args.len() == 0 {
92        env.push(func.env.peek().unwrap().clone());
93        let res = eval(env, Lval::Sexpr(func.body));
94        env.pop();
95        res
96    } else {
97        Ok(Lval::Lambda(func))
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104    use crate::lisp::{env::init_env, to_lambda};
105
106    fn empty_fun(_env: &mut Lenv, _operands: Vec<Lval>) -> Result<Lval, Lerr> {
107        Ok(Lval::Sexpr(vec![]))
108    }
109
110    #[test]
111    fn it_handles_singular_numbers() {
112        let env = &mut init_env();
113        assert_eq!(eval(env, Lval::Num(1_f64)).unwrap(), Lval::Num(1_f64));
114        assert_eq!(
115            eval(env, Lval::Sexpr(vec![Lval::Num(1_f64)])).unwrap(),
116            Lval::Num(1_f64)
117        );
118    }
119
120    #[test]
121    fn it_handles_singular_symbols() {
122        let env = &mut init_env();
123        assert_eq!(
124            eval(env, Lval::Sym(String::from("+"))).unwrap(),
125            Lval::Fun(empty_fun)
126        );
127        assert_eq!(
128            eval(env, Lval::Sexpr(vec![Lval::Sym(String::from("*"))])).unwrap(),
129            Lval::Fun(empty_fun)
130        );
131    }
132
133    #[test]
134    fn it_handles_empty_expressions() {
135        let env = &mut init_env();
136        assert_eq!(eval(env, Lval::Sexpr(vec![])).unwrap(), Lval::Sexpr(vec![]));
137        assert_eq!(
138            eval(
139                env,
140                Lval::Sexpr(vec![Lval::Sexpr(vec![Lval::Sexpr(vec![])])])
141            )
142            .unwrap(),
143            Lval::Sexpr(vec![])
144        );
145    }
146
147    #[test]
148    fn it_uses_operators_properly() {
149        let env = &mut init_env();
150        assert_eq!(
151            eval(
152                env,
153                Lval::Sexpr(vec![
154                    Lval::Sym(String::from("+")),
155                    Lval::Num(1_f64),
156                    Lval::Num(1_f64),
157                ])
158            )
159            .unwrap(),
160            Lval::Num(2_f64)
161        );
162        let _ = eval(
163            env,
164            Lval::Sexpr(vec![
165                Lval::Sym(String::from("+")),
166                Lval::Sym(String::from("+")),
167                Lval::Num(1_f64),
168            ]),
169        )
170        .map_err(|err| assert_eq!(err.etype, LerrType::BadNum));
171        let _ = eval(
172            env,
173            Lval::Sexpr(vec![Lval::Num(1_f64), Lval::Num(1_f64), Lval::Num(1_f64)]),
174        )
175        .map_err(|err| assert_eq!(err.etype, LerrType::BadOp));
176    }
177
178    #[test]
179    fn it_handles_nested_sexpressions() {
180        let env = &mut init_env();
181        assert_eq!(
182            eval(
183                env,
184                Lval::Sexpr(vec![
185                    Lval::Sym(String::from("+")),
186                    Lval::Num(1_f64),
187                    Lval::Sexpr(vec![
188                        Lval::Sym(String::from("+")),
189                        Lval::Num(1_f64),
190                        Lval::Num(1_f64),
191                    ]),
192                ])
193            )
194            .unwrap(),
195            Lval::Num(3_f64)
196        );
197    }
198
199    #[test]
200    fn it_handles_symbols() {
201        let mut env = init_env();
202
203        assert_eq!(
204            eval(
205                &mut env,
206                Lval::Sexpr(vec![
207                    Lval::Sym(String::from("def")),
208                    Lval::Qexpr(vec![Lval::Sym(String::from("a"))]),
209                    Lval::Num(1_f64),
210                ]),
211            )
212            .unwrap(),
213            Lval::Sexpr(vec![])
214        );
215        assert_eq!(
216            eval_symbol(&mut env, String::from("a")).unwrap(),
217            Lval::Num(1_f64)
218        );
219
220        env.push(crate::lisp::Lookup::new());
221        assert_eq!(
222            eval(
223                &mut env,
224                Lval::Sexpr(vec![
225                    Lval::Sym(String::from("def")),
226                    Lval::Qexpr(vec![Lval::Sym(String::from("b"))]),
227                    Lval::Num(2_f64),
228                ]),
229            )
230            .unwrap(),
231            Lval::Sexpr(vec![])
232        );
233        assert_eq!(
234            eval_symbol(&mut env, String::from("a")).unwrap(),
235            Lval::Num(1_f64)
236        );
237        assert_eq!(
238            eval_symbol(&mut env, String::from("b")).unwrap(),
239            Lval::Num(2_f64)
240        );
241
242        assert_eq!(
243            eval(
244                &mut env,
245                Lval::Sexpr(vec![
246                    Lval::Sym(String::from("def")),
247                    Lval::Qexpr(vec![Lval::Sym(String::from("c"))]),
248                    Lval::Num(3_f64),
249                ]),
250            )
251            .unwrap(),
252            Lval::Sexpr(vec![])
253        );
254        assert_eq!(
255            eval_symbol(&mut env, String::from("a")).unwrap(),
256            Lval::Num(1_f64)
257        );
258        assert_eq!(
259            eval_symbol(&mut env, String::from("b")).unwrap(),
260            Lval::Num(2_f64)
261        );
262        assert_eq!(
263            eval_symbol(&mut env, String::from("c")).unwrap(),
264            Lval::Num(3_f64)
265        );
266    }
267
268    #[test]
269    fn it_handles_lambdas() {
270        let env = &mut init_env();
271
272        let immediately_invoked =
273            Llambda::new(vec![], vec![Lval::Num(71_f64)], env.peek().unwrap().clone());
274        assert_eq!(
275            eval(env, Lval::Sexpr(vec![Lval::Lambda(immediately_invoked)])).unwrap(),
276            Lval::Num(71_f64)
277        );
278
279        // normal usage
280        let lambda = Llambda::new(
281            vec![String::from("a")],
282            vec![
283                Lval::Sym(String::from("+")),
284                Lval::Sym(String::from("a")),
285                Lval::Sym(String::from("a")),
286            ],
287            env.peek().unwrap().clone(),
288        );
289        assert_eq!(
290            call(env, lambda, vec![Lval::Num(5_f64)]).unwrap(),
291            Lval::Num(10_f64)
292        );
293
294        // partial application
295        let lambda = Llambda::new(
296            vec![String::from("c"), String::from("d")],
297            vec![
298                Lval::Sym(String::from("*")),
299                Lval::Sym(String::from("c")),
300                Lval::Sym(String::from("d")),
301            ],
302            env.peek().unwrap().clone(),
303        );
304        let new_lambda = call(env, lambda, vec![Lval::Num(15_f64)]).unwrap();
305        assert_eq!(
306            call(env, to_lambda(&new_lambda).unwrap(), vec![Lval::Num(5_f64)]).unwrap(),
307            Lval::Num(75_f64)
308        );
309    }
310
311    #[test]
312    fn it_handles_nested_lambdas() {
313        let env = &mut init_env();
314
315        let f = Lval::Sexpr(vec![
316            Lval::Sexpr(vec![
317                Lval::Sym(String::from("\\")),
318                Lval::Qexpr(vec![Lval::Sym(String::from("e"))]),
319                Lval::Qexpr(vec![
320                    Lval::Sym(String::from("\\")),
321                    Lval::Qexpr(vec![Lval::Sym(String::from("f"))]),
322                    Lval::Qexpr(vec![Lval::Sym(String::from("e"))]),
323                ]),
324            ]),
325            Lval::Num(5_f64),
326        ]);
327
328        // defining e
329        let partial = eval(env, f).unwrap();
330        let partial_lambda = to_lambda(&partial).unwrap();
331        assert_eq!(partial_lambda.args.len(), 1);
332        assert!(partial_lambda.env.get("+").is_some()); // we want the std lib
333        assert!(partial_lambda.env.get("e").is_some()); // we want e to get defined
334
335        assert_eq!(
336            call(env, partial_lambda, vec![Lval::Num(25_f64)]).unwrap(),
337            Lval::Num(5_f64)
338        );
339    }
340}
341//
342// ((\ {e} {(\ {f} {* e f})} ) 5) 30
343//
344// ((\ {e} {(\ {e f} {* e f}) e}) 5) 30