import { test, expect } from "bun:test" import { toBytecode } from "#bytecode" import { OpCode } from "#opcode" import { VM } from "#vm" test("string compilation", () => { const str = ` PUSH 1 PUSH 5 ADD ` expect(toBytecode(str)).toEqual({ instructions: [ { op: OpCode.PUSH, operand: 0 }, { op: OpCode.PUSH, operand: 1 }, { op: OpCode.ADD }, ], constants: [ { type: 'number', value: 1 }, { type: 'number', value: 5 } ] }) }) test("MAKE_FUNCTION - basic function", async () => { const bytecode = toBytecode(` MAKE_FUNCTION () #5 PUSH 0 PUSH 0 CALL HALT PUSH 42 RETURN `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 42 }) }) test("MAKE_FUNCTION - function with parameters", async () => { const bytecode = toBytecode(` MAKE_FUNCTION (x y) #7 PUSH 10 PUSH 20 PUSH 2 PUSH 0 CALL HALT LOAD x LOAD y ADD RETURN `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 30 }) }) test("MAKE_FUNCTION - function with default parameters", async () => { const bytecode = toBytecode(` MAKE_FUNCTION (x y=100) #6 PUSH 10 PUSH 1 PUSH 0 CALL HALT LOAD x LOAD y ADD RETURN `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 110 }) }) test("MAKE_FUNCTION - tail recursive countdown", async () => { const bytecode = toBytecode(` MAKE_FUNCTION (n) #8 STORE countdown LOAD countdown PUSH 5 PUSH 1 PUSH 0 CALL HALT LOAD n PUSH 0 EQ JUMP_IF_FALSE #2 PUSH "done" RETURN LOAD countdown LOAD n PUSH 1 SUB PUSH 1 PUSH 0 TAIL_CALL `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'string', value: 'done' }) }) test("MAKE_FUNCTION - multiple default values", async () => { const bytecode = toBytecode(` MAKE_FUNCTION (a=1 b=2 c=3) #5 PUSH 0 PUSH 0 CALL HALT LOAD a LOAD b LOAD c ADD ADD RETURN `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 6 }) }) test("MAKE_FUNCTION - default with string", async () => { const bytecode = toBytecode(` MAKE_FUNCTION (name="World") #5 PUSH 0 PUSH 0 CALL HALT LOAD name RETURN `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'string', value: 'World' }) })