This repository has been archived by the owner on Jan 16, 2021. It is now read-only.
/
007eval.boot.cc
127 lines (100 loc) · 4.01 KB
/
007eval.boot.cc
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
//// eval: lookup symbols, respect quotes, rewrite lambda calls
bool isQuoted(Cell* Cell) {
return isCons(Cell) && car(Cell) == newSym(L"'");
}
Cell* unQuote(Cell* Cell) {
if (isQuoted(Cell))
return cdr(Cell);
return Cell;
}
void bindArgs(Cell* params, Cell* args, bool quoted) {
if (params == nil) return;
if (isQuoted(params)) {
bindArgs(cdr(params), args, true);
return;
}
if (isSym(params) || isQuoted(params))
addLexicalBinding(unQuote(params), args);
else
bindArgs(car(params), car(args), quoted);
bindArgs(cdr(params), cdr(args), quoted);
}
void bindArgs(Cell* params, Cell* args) {
bindArgs(params, args, false);
}
Cell* sig(Cell* lambda) {
return car(cdr(lambda));
}
Cell* body(Cell* lambda) {
return cdr(cdr(lambda));
}
Cell* callee_body(Cell* callee) {
return car(cdr(cdr(callee)));
}
Cell* callee_env(Cell* callee) {
return cdr(cdr(cdr(callee)));
}
Cell* call_args(Cell* call) {
return cdr(call);
}
extern Cell* eval(Cell*);
Cell* eval_args(Cell* params, Cell* args) {
if (args == nil) return nil;
if (isQuoted(params)) return args;
setCdr(args, eval_args(cdr(params), cdr(args)));
if (!isCons(params) || !isQuoted(car(params))) {
Cell* result = eval(car(args));
setCar(args, result);
rmref(result);
}
return args;
}
Cell* eval(Cell* expr) {
if (!expr)
cerr << "eval: cell should never be NULL" << endl << DIE;
if (expr == nil)
return nil;
// Every path through eval must mkref the return value exactly once.
// This implies rmref'ing the result of nested evals.
if (isSym(expr))
return mkref(lookup(expr));
if (isAtom(expr))
return mkref(expr);
if (isQuoted(expr))
return mkref(cdr(expr));
if (car(expr) == newSym(L"lambda")) {
// attach current lexical scope
Cell* ans = newCell();
setCar(ans, car(expr));
setCdr(ans, newCell());
setCar(cdr(ans), sig(expr));
setCdr(cdr(ans), newCell());
setCar(cdr(cdr(ans)), body(expr));
setCdr(cdr(cdr(ans)), currLexicalScopes.top());
return mkref(ans);
}
// expr is a function call
Cell* lambda = eval(car(expr));
// eval all its args in the current lexical scope
Cell* evald_args = eval_args(sig(lambda), call_args(expr));
// swap in the function's lexical environment
newDynamicScope(L"currLexicalScope", callee_env(lambda));
// now bind its params to args in the new environment
newLexicalScope();
bindArgs(sig(lambda), evald_args);
// eval all forms in body; save result of final form
Cell* result = nil;
if (isPrimFunc(car(lambda))) {
result = mkref(toPrimFunc(car(lambda))());
}
else {
for (Cell* form = callee_body(lambda); form != nil; form = cdr(form)) {
rmref(result);
result = eval(car(form));
}
}
endLexicalScope();
endDynamicScope(newSym(L"currLexicalScope"));
rmref(lambda);
return result; // already mkref'd
}