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
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use std::collections::HashMap;
use types::*;
use types::RispType::*;
use environment::*;
use core::create_core_environment;


pub fn eval(ast: RispType, env: &mut Environment) -> RispResult {
    match ast {
        List(list) => {
            let first_element = list.first().ok_or_else(|| error("Empty List"))?;
            match *first_element {
                Symbol(ref symbol) => {
                    match symbol.as_ref() {
                        "def" => {
                            let var = list.get(1).ok_or_else(|| error("Missing variable in def"))?;
                            match *var {
                                Symbol(ref sym_var) => {
                                    let value_ast = list.get(2).ok_or_else(|| error("Missing value in def"))?;
                                    let value = eval(value_ast.clone(), env)?;
                                    env.set(sym_var, value.clone());
                                    Ok(value)
                                }
                                _ => error_result(format!("Expected symbol in def but got {:?}", var))
                            }
                        },
                        "do" => {
                            if let Some((last, elements)) =  (&list[1..]).split_last() {
                                for child_ast in elements.iter() {
                                    eval(child_ast.clone(), env)?;
                                }
                                eval(last.clone(), env)
                            } else {
                                error_result("Empty do block")
                            }
                        }
                        _ => {
                            let evaluated_tail = list[1..].iter()
                                .map(|el| eval(el.clone(), env))
                                .collect::<Result<Vec<_>, _>>()?;
                            let env_value = env.get(symbol).ok_or_else(|| error(format!("Undefined symbol{:?}", symbol)))?;
                            match env_value {
                                Function(function) => function(evaluated_tail.to_vec()),
                                _ => error_result(format!("Expected function but got {:?}", env_value))
                            }
                        }
                    }
                }
                _ => error_result(format!("Expected symbol but got {:?}", first_element))
            }
        }
        Vector(vector) => {
            let evaluated_vector = vector.iter()
                .map(|el| eval(el.clone(), env))
                .collect::<Result<Vec<_>, _>>()?;
            Ok(Vector(evaluated_vector))
        }

        Map(map_value) => {
            let evaluated_map = map_value.iter()
                .map(|(key, val)|
                    eval(val.clone(), env).map(|evaluated_value|
                        (key.to_string(), evaluated_value)))
                .collect::<Result<HashMap<String, RispType>, _>>()?;
            Ok(Map(evaluated_map))
        }

        Symbol(symbol) => {
            env.get(&symbol).ok_or_else(|| error(format!("symbol '{:?}' is undefined", symbol)))
        }
        other => Ok(other)
    }
}


/* ------------------------------ Tests ----------------------------------------------- */

#[allow(dead_code)]
fn eval_test(ast: RispType) -> RispResult {
    eval(ast, &mut create_core_environment())
}

#[test]
fn test_eval_number() {
    assert_eq!(eval_test(Int(23)), Ok(Int(23)));
}

#[test]
fn test_eval_math() {
    assert_eq!(eval_test(List(vec![Symbol("+".to_string()), Int(1), Int(2)])), Ok(Int(3)));
}

#[test]
fn test_nested_math() {
    assert_eq!(eval_test(List(vec![
        Symbol("+".to_string()), Int(1),
        List(vec![Symbol("+".to_string()), Int(10), Int(100)])
    ])), Ok(Int(111)));
}

#[test]
fn test_mul() {
    assert_eq!(eval_test(List(vec![
        Symbol("+".to_string()), Int(1),
        List(vec![Symbol("*".to_string()), Int(10), Int(23)])
    ])), Ok(Int(231)));
}


#[test]
fn test_def() {
    let variable = "variable";
    let variable_value = Int(23);
    let mut env = create_core_environment();

    assert_eq!(eval(List(vec![
        symbol("def"),
        symbol(variable),
        variable_value.clone()
    ]), &mut env), Ok(variable_value.clone()));

    assert_eq!(env.get(variable), Some(variable_value));
}

#[test]
fn test_def_evaluated() {
    let variable = "variable";
    let mut env = create_core_environment();

    assert_eq!(eval(List(vec![
        symbol("def"),
        symbol(variable),
        List(vec![symbol("+"), Int(1), Int(2)])
    ]), &mut env), Ok(Int(3)));

    assert_eq!(env.get(variable), Some(Int(3)));
}

#[test]
fn test_eval_simple_vector() {
    let simple_vector = Vector(vec![Int(1), Int(2)]);
    assert_eq!(eval_test(simple_vector.clone()), Ok(simple_vector));
}

#[test]
fn test_eval_nested_vector() {
    let simple_vector = Vector(vec![Int(1), List(vec![symbol("+"), Int(1), Int(2)])]);
    assert_eq!(eval_test(simple_vector.clone()), Ok(Vector(vec![Int(1), Int(3)])));
}


#[test]
fn test_eval_simple_map() {
    let simple_map = map(vec![
        ("key1", Int(1)),
        ("key2", Int(2))
    ]);
    assert_eq!(eval_test(simple_map.clone()), Ok(simple_map));
}

#[test]
fn test_eval_nested_map() {
    let input_map = map(vec![
        ("key", List(vec![symbol("+"), Int(1), Int(2)]))
    ]);
    let expected_output_map = map(vec![
        ("key", Int(3))
    ]);
    assert_eq!(eval_test(input_map.clone()), Ok(expected_output_map));
}