diff options
Diffstat (limited to 'src/interpreter')
-rw-r--r-- | src/interpreter/builtins.ts | 120 | ||||
-rw-r--r-- | src/interpreter/denotable.ts | 1 | ||||
-rw-r--r-- | src/interpreter/interpreter.ts | 44 |
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 = ( |