From 17d846b99910a46fc1c7ab98aa41ca8afbc14097 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sat, 25 Oct 2025 09:48:17 -0700 Subject: [PATCH] more repl support --- src/vm.ts | 11 +++++++++-- tests/repl.test.ts | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/vm.ts b/src/vm.ts index 604cb38..aa3c948 100644 --- a/src/vm.ts +++ b/src/vm.ts @@ -83,8 +83,16 @@ export class VM { // Helper for REPL mode: append new bytecode with proper constant index remapping appendBytecode(bytecode: Bytecode): void { const constantOffset = this.constants.length + const instructionOffset = this.instructions.length - this.constants.push(...bytecode.constants) + // Remap function body addresses in constants before adding them + for (const constant of bytecode.constants) { + if (constant.type === 'function_def') { + this.constants.push({ ...constant, body: constant.body + instructionOffset }) + } else { + this.constants.push(constant) + } + } for (const instruction of bytecode.instructions) { if (instruction.operand !== undefined && typeof instruction.operand === 'number') { @@ -103,7 +111,6 @@ export class VM { } if (bytecode.labels) { - const instructionOffset = this.instructions.length - bytecode.instructions.length for (const [addr, label] of bytecode.labels.entries()) { this.labels.set(addr + instructionOffset, label) } diff --git a/tests/repl.test.ts b/tests/repl.test.ts index 8c65b28..35bb314 100644 --- a/tests/repl.test.ts +++ b/tests/repl.test.ts @@ -110,3 +110,40 @@ test("REPL mode - continue() executes only new bytecode", async () => { expect(line2Count).toBe(1) // Ran once as expected expect(result).toEqual({ type: "number", value: 15 }) // 5 + 10 }) + +test("REPL mode - function calls work across chunks", async () => { + const vm = new VM(toBytecode([])) + await vm.run() + + // Line 1: Define a function + const line1 = toBytecode([ + ["MAKE_FUNCTION", ["x"], ".body"], + ["STORE", "add1"], + ["JUMP", ".end"], + [".body:"], + ["LOAD", "x"], + ["PUSH", 1], + ["ADD"], + ["RETURN"], + [".end:"] + ]) + + vm.appendBytecode(line1) + await vm.continue() + + expect(vm.scope.get("add1")?.type).toBe("function") + + // Line 2: Call the function + const line2 = toBytecode([ + ["LOAD", "add1"], + ["PUSH", 10], + ["PUSH", 1], + ["PUSH", 0], + ["CALL"] + ]) + + vm.appendBytecode(line2) + const result = await vm.continue() + + expect(result).toEqual({ type: "number", value: 11 }) +})