-
Notifications
You must be signed in to change notification settings - Fork 14
/
StatementInterp.js
85 lines (67 loc) · 2.42 KB
/
StatementInterp.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
/*
* https://github.com/estree/estree/blob/master/spec.md#statements
*/
import invariant from 'fbjs/lib/invariant';
import { interp as expInterp } from './ExpressionInterp';
import { extendEnv } from '../Environment';
const interp = (exp, env) => {
switch (exp.type) {
case 'BlockStatement': {
let currentEnv = env;
for (let i = 0; i < exp.body.length; i++) {
const currentExp = exp.body[i];
switch (currentExp.type) {
case 'ExpressionStatement': {
expInterp(currentExp.expression, currentEnv); // stuff like `log(something)`
continue;
}
case 'ReturnStatement': {
const { argument } = currentExp;
return expInterp(argument, currentEnv); // early return!
}
case 'VariableDeclaration': {
const { kind, declarations } = currentExp;
invariant(
kind === 'const',
`unsupported VariableDeclaration kind ${kind}`,
);
invariant(
declarations.length === 1,
`unsupported multiple (${declarations.length}) VariableDeclarations`,
);
const { id, init } = declarations[0];
const { name } = id;
if (init.type === 'ArrowFunctionExpression') {
/*
* TL;DR: it could be a `letrec`!
*
* A better way is to do a static analysis and to see whether the RHS
* actually contains recursive definitions.
* However, for the sake of simplicity,
* we treat all RHS lambdas as potential self-referencing definitions,
* a.k.a., `letrec`s.
*
* For more information, check the comments and definitions in `Closure.js`
* and http:https://www.cs.indiana.edu/~dyb/papers/fixing-letrec.pdf
*/
init.extra = { isLambda: true, name };
}
const val = expInterp(init, currentEnv);
currentEnv = extendEnv(name, val, currentEnv);
continue;
}
default: {
throw new Error(`unsupported BlockStatement type ${currentExp.type}`);
}
}
}
return undefined; // `return` hasn't been called so we return `undefined`
}
default: {
throw new Error(`unsupported statement type ${exp.type}`);
}
}
};
export {
interp,
};