import { test, expect } from "bun:test" import { VM } from "#vm" import { OpCode } from "#opcode" import { toValue, toNumber } from "#value" test("CALL_TYPESCRIPT - basic function call", async () => { const vm = new VM({ instructions: [ { op: OpCode.PUSH, operand: 0 }, // push 5 { op: OpCode.PUSH, operand: 1 }, // push 10 { op: OpCode.CALL_TYPESCRIPT, operand: 'add' }, // call TypeScript 'add' { op: OpCode.HALT } ], constants: [ toValue(5), toValue(10) ] }) // Register a TypeScript function vm.registerFunction('add', (a, b) => { return toValue(toNumber(a) + toNumber(b)) }) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 15 }) }) test("CALL_TYPESCRIPT - function with string manipulation", async () => { const vm = new VM({ instructions: [ { op: OpCode.PUSH, operand: 0 }, // push "hello" { op: OpCode.PUSH, operand: 1 }, // push "world" { op: OpCode.CALL_TYPESCRIPT, operand: 'concat' }, // call TypeScript 'concat' { op: OpCode.HALT } ], constants: [ toValue("hello"), toValue("world") ] }) vm.registerFunction('concat', (a, b) => { const aStr = a.type === 'string' ? a.value : String(a.value) const bStr = b.type === 'string' ? b.value : String(b.value) return toValue(aStr + ' ' + bStr) }) const result = await vm.run() expect(result).toEqual({ type: 'string', value: 'hello world' }) }) test("CALL_TYPESCRIPT - async function", async () => { const vm = new VM({ instructions: [ { op: OpCode.PUSH, operand: 0 }, // push 42 { op: OpCode.CALL_TYPESCRIPT, operand: 'asyncDouble' }, // call async TypeScript function { op: OpCode.HALT } ], constants: [ toValue(42) ] }) vm.registerFunction('asyncDouble', async (a) => { // Simulate async operation await new Promise(resolve => setTimeout(resolve, 1)) return toValue(toNumber(a) * 2) }) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 84 }) }) test("CALL_TYPESCRIPT - function with no arguments", async () => { const vm = new VM({ instructions: [ { op: OpCode.CALL_TYPESCRIPT, operand: 'getAnswer' }, // call with empty stack { op: OpCode.HALT } ], constants: [] }) vm.registerFunction('getAnswer', () => { return toValue(42) }) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 42 }) }) test("CALL_TYPESCRIPT - function with multiple arguments", async () => { const vm = new VM({ instructions: [ { op: OpCode.PUSH, operand: 0 }, // push 2 { op: OpCode.PUSH, operand: 1 }, // push 3 { op: OpCode.PUSH, operand: 2 }, // push 4 { op: OpCode.CALL_TYPESCRIPT, operand: 'sum' }, // call TypeScript 'sum' { op: OpCode.HALT } ], constants: [ toValue(2), toValue(3), toValue(4) ] }) vm.registerFunction('sum', (...args) => { const total = args.reduce((acc, val) => acc + toNumber(val), 0) return toValue(total) }) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 9 }) }) test("CALL_TYPESCRIPT - function returns array", async () => { const vm = new VM({ instructions: [ { op: OpCode.PUSH, operand: 0 }, // push 3 { op: OpCode.CALL_TYPESCRIPT, operand: 'makeRange' }, // call TypeScript 'makeRange' { op: OpCode.HALT } ], constants: [ toValue(3) ] }) vm.registerFunction('makeRange', (n) => { const count = toNumber(n) const arr = [] for (let i = 0; i < count; i++) { arr.push(toValue(i)) } return { type: 'array', value: arr } }) const result = await vm.run() expect(result.type).toBe('array') if (result.type === 'array') { expect(result.value.length).toBe(3) expect(result.value).toEqual([ toValue(0), toValue(1), toValue(2) ]) } }) test("CALL_TYPESCRIPT - function not found", async () => { const vm = new VM({ instructions: [ { op: OpCode.CALL_TYPESCRIPT, operand: 'nonexistent' } ], constants: [] }) await expect(vm.run()).rejects.toThrow('CALL_TYPESCRIPT: function not found: nonexistent') }) test("CALL_TYPESCRIPT - using result in subsequent operations", async () => { const vm = new VM({ instructions: [ { op: OpCode.PUSH, operand: 0 }, // push 5 { op: OpCode.CALL_TYPESCRIPT, operand: 'triple' }, // call TypeScript 'triple' -> 15 { op: OpCode.PUSH, operand: 1 }, // push 10 { op: OpCode.ADD }, // 15 + 10 = 25 { op: OpCode.HALT } ], constants: [ toValue(5), toValue(10) ] }) vm.registerFunction('triple', (n) => { return toValue(toNumber(n) * 3) }) const result = await vm.run() expect(result).toEqual({ type: 'number', value: 25 }) })