more repl support

This commit is contained in:
Chris Wanstrath 2025-10-25 09:48:17 -07:00
parent 1fb5effb0a
commit 17d846b999
2 changed files with 46 additions and 2 deletions

View File

@ -83,8 +83,16 @@ export class VM {
// Helper for REPL mode: append new bytecode with proper constant index remapping // Helper for REPL mode: append new bytecode with proper constant index remapping
appendBytecode(bytecode: Bytecode): void { appendBytecode(bytecode: Bytecode): void {
const constantOffset = this.constants.length 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) { for (const instruction of bytecode.instructions) {
if (instruction.operand !== undefined && typeof instruction.operand === 'number') { if (instruction.operand !== undefined && typeof instruction.operand === 'number') {
@ -103,7 +111,6 @@ export class VM {
} }
if (bytecode.labels) { if (bytecode.labels) {
const instructionOffset = this.instructions.length - bytecode.instructions.length
for (const [addr, label] of bytecode.labels.entries()) { for (const [addr, label] of bytecode.labels.entries()) {
this.labels.set(addr + instructionOffset, label) this.labels.set(addr + instructionOffset, label)
} }

View File

@ -110,3 +110,40 @@ test("REPL mode - continue() executes only new bytecode", async () => {
expect(line2Count).toBe(1) // Ran once as expected expect(line2Count).toBe(1) // Ran once as expected
expect(result).toEqual({ type: "number", value: 15 }) // 5 + 10 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 })
})