-
Notifications
You must be signed in to change notification settings - Fork 14
/
ExpressionInterp.js
129 lines (112 loc) · 3.21 KB
/
ExpressionInterp.js
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
/*
* https://github.com/estree/estree/blob/master/spec.md#expressions
*/
import {
lookupEnv,
} from '../Environment';
import {
makeClosure,
makeRecClosure,
applyClosure,
} from '../Closure';
import { interp as statementInterp } from './StatementInterp';
const interp = (exp, env) => {
switch (exp.type) {
case 'NullLiteral': {
return null;
}
case 'NumericLiteral':
case 'BooleanLiteral': {
return exp.value;
}
case 'BlockStatement': {
return statementInterp(exp, env);
}
case 'Identifier': {
const { name } = exp;
return lookupEnv(name, env);
}
case 'ArrowFunctionExpression': {
const { body, params } = exp;
const names = params.map((obj) => obj.name);
if (exp.extra && exp.extra.isLambda) {
const { name: selfId } = exp.extra;
return makeRecClosure(selfId, names, body, env);
}
return makeClosure(names, body, env);
}
case 'CallExpression': {
const { callee, arguments: rawArgs } = exp;
// here we recur on both sides
const closure = interp(callee, env);
const vals = rawArgs.map((obj) => interp(obj, env));
return applyClosure(interp, closure, vals, env);
}
case 'UnaryExpression': {
const { argument, operator } = exp;
// @TODO what's the `prefix` property here?
switch (operator) {
case '!': {
return !interp(argument, env);
}
default: {
throw new Error(`unsupported UnaryExpression operator ${operator}`);
}
}
}
case 'BinaryExpression': {
const { left, operator, right } = exp;
switch (operator) {
case '+': {
return interp(left, env) + interp(right, env);
}
case '-': {
return interp(left, env) - interp(right, env);
}
case '*': {
return interp(left, env) * interp(right, env);
}
case '/': {
return interp(left, env) / interp(right, env);
}
case '==': {
return interp(left, env) == interp(right, env); // eslint-disable-line eqeqeq
}
case '===': {
return interp(left, env) === interp(right, env);
}
case '!=': {
return interp(left, env) != interp(right, env); // eslint-disable-line eqeqeq
}
case '!==': {
return interp(left, env) !== interp(right, env);
}
case '<': {
return interp(left, env) < interp(right, env); // eslint-disable-line eqeqeq
}
case '<=': {
return interp(left, env) <= interp(right, env);
}
case '>': {
return interp(left, env) > interp(right, env); // eslint-disable-line eqeqeq
}
case '>=': {
return interp(left, env) >= interp(right, env);
}
default: {
throw new Error(`unsupported BinaryExpression operator ${operator}`);
}
}
}
case 'ConditionalExpression': {
const { alternate, consequent, test } = exp;
return interp(test, env) ? interp(consequent, env) : interp(alternate, env);
}
default: {
throw new Error(`unsupported expression type ${exp.type}`);
}
}
};
export {
interp,
};