summaryrefslogtreecommitdiff
path: root/src/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'src/interpreter')
-rw-r--r--src/interpreter/builtins.ts120
-rw-r--r--src/interpreter/denotable.ts1
-rw-r--r--src/interpreter/interpreter.ts44
3 files changed, 150 insertions, 15 deletions
diff --git a/src/interpreter/builtins.ts b/src/interpreter/builtins.ts
index 200131f..bc666e9 100644
--- a/src/interpreter/builtins.ts
+++ b/src/interpreter/builtins.ts
@@ -28,6 +28,117 @@ const addUnaryIntegerOperationsTo = (env: Environment) => {
return env;
};
+const addNumberComparisonOperationsTo = (env: Environment) => {
+ const comparisonOperationsSignatures: DenotableFunctionSignature[] = [
+ {
+ arguments: [
+ ['real', 'int'],
+ ['real', 'int'],
+ ],
+ return: 'bool',
+ },
+ ];
+
+ for (const { name, fn } of [
+ { name: '<=', fn: (a: number, b: number) => (a <= b ? 1 : 0) },
+ { name: '<', fn: (a: number, b: number) => (a < b ? 1 : 0) },
+ { name: '>', fn: (a: number, b: number) => (a > b ? 1 : 0) },
+ { name: '>=', fn: (a: number, b: number) => (a >= b ? 1 : 0) },
+ ]) {
+ env.set(name, {
+ type: 'function',
+ value: {
+ signatures: comparisonOperationsSignatures,
+ body: ({ value: a }: Denotable, { value: b }: Denotable) =>
+ fn(a as number, b as number),
+ },
+ });
+ }
+
+ return env;
+};
+
+const addEqualityOperationsTo = (env: Environment) => {
+ const equalityOperationSignatures: DenotableFunctionSignature[] = [
+ {
+ arguments: ['int', 'int'],
+ return: 'bool',
+ },
+ {
+ arguments: ['real', 'real'],
+ return: 'bool',
+ },
+ {
+ arguments: ['bool', 'bool'],
+ return: 'bool',
+ },
+ {
+ arguments: ['string', 'string'],
+ return: 'bool',
+ },
+ ];
+
+ for (const { name, fn } of [
+ {
+ name: '==',
+ fn: (a: number | string, b: number | string) => (a === b ? 1 : 0),
+ },
+ {
+ name: '!=',
+ fn: (a: number | string, b: number | string) => (a !== b ? 1 : 0),
+ },
+ ]) {
+ env.set(name, {
+ type: 'function',
+ value: {
+ signatures: equalityOperationSignatures,
+ body: ({ value: a }: Denotable, { value: b }: Denotable) =>
+ fn(a as number | string, b as number | string),
+ },
+ });
+ }
+
+ return env;
+};
+
+const addBooleanAlgebraOperationsTo = (env: Environment) => {
+ const binaryBooleanOps: DenotableFunctionSignature[] = [
+ {
+ arguments: ['bool', 'bool'],
+ return: 'bool',
+ },
+ ];
+
+ for (const { name, fn } of [
+ { name: '||', fn: (a: number, b: number) => (a === 1 || b === 1 ? 1 : 0) },
+ { name: '&&', fn: (a: number, b: number) => (a === 1 && b === 1 ? 1 : 0) },
+ ]) {
+ env.set(name, {
+ type: 'function',
+ value: {
+ signatures: binaryBooleanOps,
+ body: ({ value: a }: Denotable, { value: b }: Denotable) =>
+ fn(a as number, b as number),
+ },
+ });
+ }
+
+ env.set('!', {
+ type: 'function',
+ value: {
+ signatures: [
+ {
+ arguments: ['bool'],
+ return: 'bool',
+ },
+ ],
+ body: ({ value }: Denotable) => (value === 1 ? 0 : 1),
+ },
+ });
+
+ return env;
+};
+
const addBinaryIntegerOperationsTo = (env: Environment) => {
const binaryIntegerOperationSignatures: DenotableFunctionSignature[] = [
{
@@ -42,12 +153,6 @@ const addBinaryIntegerOperationsTo = (env: Environment) => {
{ name: '<<', fn: (a: number, b: number) => a << b },
{ name: '|', fn: (a: number, b: number) => a | b },
{ name: '^', fn: (a: number, b: number) => a ^ b },
- { name: '&&', fn: (a: number, b: number) => (a && b ? 1 : 0) },
- { name: '<=', fn: (a: number, b: number) => (a <= b ? 1 : 0) },
- { name: '<', fn: (a: number, b: number) => (a < b ? 1 : 0) },
- { name: '>', fn: (a: number, b: number) => (a > b ? 1 : 0) },
- { name: '>=', fn: (a: number, b: number) => (a >= b ? 1 : 0) },
- { name: '||', fn: (a: number, b: number) => (a || b ? 1 : 0) },
]) {
env.set(name, {
type: 'function',
@@ -102,5 +207,8 @@ export const putBuiltinsOnEnvironemtn = (env: Environment) => {
addBinaryArithmeticOperationsTo,
addBinaryIntegerOperationsTo,
addUnaryIntegerOperationsTo,
+ addNumberComparisonOperationsTo,
+ addBooleanAlgebraOperationsTo,
+ addEqualityOperationsTo,
].reduce((acc, builtinsAdder) => builtinsAdder(acc), env);
};
diff --git a/src/interpreter/denotable.ts b/src/interpreter/denotable.ts
index 65aee86..bb520f8 100644
--- a/src/interpreter/denotable.ts
+++ b/src/interpreter/denotable.ts
@@ -21,6 +21,7 @@ export type DenotableType =
| 'null'
| 'int'
| 'real'
+ | 'bool'
| 'string'
| 'bytearray'
| 'function'
diff --git a/src/interpreter/interpreter.ts b/src/interpreter/interpreter.ts
index ebd605c..94e263c 100644
--- a/src/interpreter/interpreter.ts
+++ b/src/interpreter/interpreter.ts
@@ -29,7 +29,6 @@ const evaluateValue = (
return { type: 'int', value: value.int };
}
if ('name' in value) {
- logger.debug(`Evaluating variable: ${value.name}`);
return env.get(value.name);
}
@@ -42,10 +41,6 @@ const evaluatePrimitiveOperation = (
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')),
);
@@ -56,15 +51,46 @@ const evaluatePrimitiveOperation = (
continuationEnvironment.set(name, result);
}
- // return the result of the last continuation
- return continuations.reduce((_, continuation, i) => {
- const childLogger = logger.createChild(`continuation[${i}]`);
+ if (result.type === 'bool') {
+ if (continuations.length > 2) {
+ throw new BadArgumentError(
+ `Expected <= 2 continuations for boolean result, got ${continuations.length}`,
+ );
+ }
+ if (continuations.length !== 2) {
+ logger.warn(
+ `Expected 2 continuations for boolean result, got ContinuationLength=(${continuations.length})`,
+ );
+ }
+
+ const [trueContinuation, falseContinuation] = continuations;
+ const childLogger = logger.createChild('continuation[true]');
+ const continuation = result.value ? trueContinuation : falseContinuation;
return evaluteContinuationExpression(
continuation,
continuationEnvironment,
childLogger,
);
- }, result);
+ }
+
+ if (continuations.length > 1) {
+ throw new BadArgumentError(
+ `Expected <= 1 continuations for non-boolean result, got ${continuations.length}`,
+ );
+ } else if (continuations.length === 0) {
+ logger.warn(
+ `!! Expected 1 continuation in continuation list... implicitly returning result but PLEASE NOTE this is technically undefined behavior !!`,
+ );
+ return result;
+ }
+
+ const [continuation] = continuations;
+ const childLogger = logger.createChild('continuation');
+ return evaluteContinuationExpression(
+ continuation,
+ continuationEnvironment,
+ childLogger,
+ );
};
const evaluteContinuationExpression = (