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
|
import {
type ContinuationExpression,
type PrimitiveOperationExpression,
type Program,
type Value,
} from '@/parser';
import { Environment, type Denotable } from '.';
import {
BadArgumentError,
InvalidStateError,
NotImplementedError,
type TracingLogger,
} from '@/utils';
import { putBuiltinsOnEnvironemtn } from './builtins';
const evaluateValue = (
value: Value,
env: Environment,
logger: TracingLogger,
): Denotable => {
if (typeof value === 'string') {
return { type: 'string', value };
}
if ('real' in value) {
return { type: 'real', value: value.real };
}
if ('int' in value) {
return { type: 'int', value: value.int };
}
if ('name' in value) {
logger.debug(`Evaluating variable: ${value.name}`);
return env.get(value.name);
}
throw new InvalidStateError(`Invalid value: ${value}`);
};
const evaluatePrimitiveOperation = (
{ primitiveOperation }: PrimitiveOperationExpression,
env: Environment,
logger: TracingLogger,
) => {
const { opr, operands, resultBindings, continuations } = primitiveOperation;
if (operands.length !== 2) {
throw new BadArgumentError('Primitive operations must have 2 operands');
}
const operandValues = operands.map(operand =>
evaluateValue(operand, env, logger.createChild('evaluteValue')),
);
const result = env.apply(opr, operandValues);
const continuationEnvironment = env.createChild();
for (const { name } of resultBindings) {
continuationEnvironment.set(name, result);
}
// return the result of the last continuation
return continuations.reduce((_, continuation, i) => {
const childLogger = logger.createChild(`continuation[${i}]`);
return evaluteContinuationExpression(
continuation,
continuationEnvironment,
childLogger,
);
}, result);
};
const evaluteContinuationExpression = (
expr: ContinuationExpression,
env: Environment,
logger: TracingLogger,
): Denotable => {
if ('primitiveOperation' in expr) {
logger.debug('Evaluating primitive operation');
return evaluatePrimitiveOperation(
expr,
env,
logger.createChild('evaluatePrimitiveOperation'),
);
}
if ('record' in expr) {
throw new NotImplementedError('Continuation records are not supported yet');
}
if ('select' in expr) {
throw new NotImplementedError('Continuation select is not supported yet');
}
if ('offset' in expr) {
throw new NotImplementedError('Continuation offset is not supported yet');
}
if ('application' in expr) {
throw new NotImplementedError(
'Continuation application is not supported yet',
);
}
if ('switch' in expr) {
throw new NotImplementedError('Continuation switch is not supported yet');
}
if ('fix' in expr) {
throw new NotImplementedError('Continuation fix is not supported yet');
}
throw new InvalidStateError(`Invalid continuation expression: ${expr}`);
};
export const evaluate = async (
ast: Program,
logger: TracingLogger,
): Promise<Denotable> => {
const globalEnvironment = putBuiltinsOnEnvironemtn(
new Environment(logger.createChild('RootEnv')),
);
return ast.reduce((_, continuation, i) => {
const exprLogger = logger.createChild(`statement[${i}]`);
return evaluteContinuationExpression(
continuation as ContinuationExpression,
globalEnvironment,
exprLogger,
);
}, null);
};
|