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 => { 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); };