forked from klmr/lisp.cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheval.cpp
62 lines (48 loc) · 1.74 KB
/
eval.cpp
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
#include "eval.hpp"
#include "error.hpp"
namespace klmr { namespace lisp {
struct eval_call_visitor : boost::static_visitor<value> {
environment& env;
list::const_range args;
eval_call_visitor(environment& env, list::const_range args) :
env{env}, args{args} {}
auto operator ()(call const& call) const -> value {
auto evaluated_args = std::vector<value>(std::distance(begin(args), end(args)));
std::transform(begin(args), end(args), begin(evaluated_args),
[this](value const& v) { return eval(v, env); });
return call(env, begin(evaluated_args), end(evaluated_args));
}
auto operator ()(macro const& macro) const -> value {
return macro(env, begin(args), end(args));
}
template <typename T>
auto operator ()(T const& val) const -> value {
throw invalid_node{val, "call"};
}
};
struct eval_visitor : boost::static_visitor<value> {
environment& env;
eval_visitor(environment& env) : env{env} {}
auto operator ()(symbol const& sym) const -> value {
return env[sym];
}
template <typename T>
auto operator ()(literal<T> const& lit) const -> value {
return lit;
}
auto operator ()(list const& cons) const -> value {
if (empty(cons))
throw invalid_node{cons, "non-empty list"};
auto&& call = eval(head(cons), env);
return boost::apply_visitor(eval_call_visitor{env, tail(cons)}, call);
}
template <typename T>
auto operator ()(T const& val) const -> value {
// Everything else is invalid.
throw invalid_node{val};
}
};
auto eval(value expr, environment& env) -> value {
return boost::apply_visitor(eval_visitor{env}, expr);
}
} } // namespace klmr::lisp