import { type DenotableFunctionSignature, Environment, type Denotable, } from '.'; const addUnaryIntegerOperationsTo = (env: Environment) => { const unaryIntegerOperationSignatures: DenotableFunctionSignature[] = [ { arguments: ['int'], return: 'int', }, ]; for (const { name, fn } of [{ name: '~', fn: (a: number) => ~a }]) { env.set(name, { type: 'function', value: { signatures: unaryIntegerOperationSignatures, body: ({ value }: Denotable) => fn(value as number), }, }); } 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[] = [ { arguments: ['int', 'int'], return: 'int', }, ]; for (const { name, fn } of [ { 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 }, { name: '^', fn: (a: number, b: number) => a ^ b }, ]) { env.set(name, { type: 'function', value: { signatures: binaryIntegerOperationSignatures, body: ({ value: a }: Denotable, { value: b }: Denotable) => fn(a as number, b as number), }, }); } return env; }; const addBinaryArithmeticOperationsTo = (env: Environment) => { const binaryArithmeticSignatures: DenotableFunctionSignature[] = [ { arguments: ['int', 'int'], return: 'int', }, { arguments: [ ['int', 'real'], ['int', 'real'], ], return: 'real', }, ]; for (const { name, fn } of [ { 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 }, { name: '**', fn: (a: number, b: number) => a ** b }, ]) { env.set(name, { type: 'function', value: { signatures: binaryArithmeticSignatures, body: ({ value: a }: Denotable, { value: b }: Denotable) => fn(a as number, b as number), }, }); } return env; }; const addIdentityFunctionTo = (env: Environment) => { env.set('id', { type: 'function', value: { signatures: [ { arguments: ['null'], return: 'null', }, { arguments: ['int'], return: 'int', }, { arguments: ['real'], return: 'real', }, { arguments: ['bool'], return: 'bool', }, { arguments: ['string'], return: 'string', }, { arguments: ['bytearray'], return: 'bytearray', }, { arguments: ['function'], return: 'function', }, { arguments: ['reference'], return: 'reference', }, ], body: ({ value }: Denotable) => value, }, }); return env; }; export const putBuiltinsOnEnvironemtn = (env: Environment) => { return [ addBinaryArithmeticOperationsTo, addBinaryIntegerOperationsTo, addUnaryIntegerOperationsTo, addNumberComparisonOperationsTo, addBooleanAlgebraOperationsTo, addEqualityOperationsTo, addIdentityFunctionTo, ].reduce((acc, builtinsAdder) => builtinsAdder(acc), env); };