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 () #3 CALL #0 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) #5 PUSH 10 PUSH 20 CALL #2 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) #4 PUSH 10 CALL #1 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) #6 STORE countdown LOAD countdown PUSH 5 CALL #1 HALT LOAD n PUSH 0 EQ JUMP_IF_FALSE #2 PUSH "done" RETURN LOAD countdown LOAD n PUSH 1 SUB TAIL_CALL #1 `) 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) #3 CALL #0 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") #3 CALL #0 HALT LOAD name RETURN `) const vm = new VM(bytecode) const result = await vm.run() expect(result).toEqual({ type: 'string', value: 'World' }) })