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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
mod env;
mod eval;
mod lexer;
mod object;
mod parser;

use object::Object;
use std::cell::RefCell;
use std::rc::Rc;

pub fn lisp_rs_eval(input: &str) -> String {
    let mut env = Rc::new(RefCell::new(env::Env::new()));
    let val = eval::eval(input, &mut env);
    match val {
        Ok(Object::Void) => "".to_string().into(),
        Ok(Object::Integer(n)) => n.to_string().into(),
        Ok(Object::Bool(b)) => b.to_string().into(),
        Ok(Object::Symbol(s)) => s.to_string().into(),
        Ok(Object::Lambda(params, body, _)) => {
            let mut res = "Lambda(".to_string();
            for param in params {
                res.push_str(&format!("{} ", param));
            }
            res.push_str(")");
            for expr in (*body).iter() {
                res.push_str(&format!(" {}", expr));
            }
            res
        }
        Ok(Object::List(list)) => {
            let mut res = "(".to_string();
            for (i, obj) in (*list).iter().enumerate() {
                if i > 0 {
                    res.push_str(" ");
                }
                res.push_str(&format!("{}", obj));
            }
            res.push_str(")");
            res
        }
        Ok(Object::ListData(list)) => {
            let mut res = "(".to_string();
            for (i, obj) in list.iter().enumerate() {
                if i > 0 {
                    res.push_str(" ");
                }
                res.push_str(&format!("{}", obj));
            }
            res.push_str(")");
            res.to_string().into()
        }
        Ok(Object::String(s)) => s.to_string().into(),
        Ok(Object::Keyword(s)) => s.to_string().into(),
        Ok(Object::BinaryOp(s)) => s.to_string().into(),
        Ok(Object::Float(n)) => n.to_string().into(),
        Ok(Object::If) => "If".to_string().into(),
        Err(e) => e.to_string().into(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_map() {
        let program = "
            (map (lambda (x) (* x x)) (list 1 2 3 4 5))
        ";
        let result = lisp_rs_eval(program);
        assert_eq!(result, "(1 4 9 16 25)");
    }

    #[test]
    fn test_filter() {
        let program = "
            (filter (lambda (x) (= 0 (% x 2))) (list 1 2 3 4 5))
        ";
        let result = lisp_rs_eval(program);
        assert_eq!(result, "(2 4)");
    }

    #[test]
    fn test_reduce() {
        let program = "
            (reduce (lambda (x y) (+ x y)) (list 1 2 3 4 5))
        ";
        let result = lisp_rs_eval(program);
        assert_eq!(result, "15");
    }
}