import type { AST } from './ast'; import type { Env } from './env'; import type { Value } from './types'; export function evaluate(ast: AST, env: Env): Value { switch (ast.kind) { case 'literal': return ast.value; case 'variable': const val = env.get(ast.name); if (val === undefined) throw new Error(`Unknown variable: ${ast.name}`); return val; case 'binaryop': const left = evaluate(ast.left, env); const right = evaluate(ast.right, env); return evaluateBinaryOp(ast.operator, left, right); case 'let': const val2 = evaluate(ast.value, env); const newEnv = new Map(env).set(ast.name, val2); return evaluate(ast.body, newEnv); case 'if': const { kind, value } = evaluate(ast.condition, env); if (kind !== 'bool') throw new Error('Condition must be bool'); if (value) { return evaluate(ast.then, env); } else { return evaluate(ast.else, env); } } } function evaluateBinaryOp(op: string, left: Value, right: Value): Value { const { value: leftValue, kind: leftKind } = left; const { value: rightValue, kind: rightKind } = right; const bothNumbers = ((leftKind === 'int' || leftKind === 'float')) && ((rightKind === 'int' || rightKind === 'float')); if (!bothNumbers) throw new Error(`Not numbers: ${left}, ${right}`); switch (op) { case '+': return { value: leftValue + rightValue, kind: 'int' }; case '-': return { value: leftValue - rightValue, kind: 'int' }; case '*': return { value: leftValue * rightValue, kind: 'int' } case '/': return { value: leftValue / rightValue, kind: 'int' } default: throw new Error(`Unknown operation: ${op}`); } }