125 lines
3.1 KiB
TypeScript
125 lines
3.1 KiB
TypeScript
import { test, expect } from "bun:test"
|
|
import { VM } from "#vm"
|
|
import { OpCode } from "#opcode"
|
|
|
|
test("MAKE_FUNCTION - creates function with captured scope", async () => {
|
|
const vm = new VM({
|
|
instructions: [
|
|
{ op: OpCode.MAKE_FUNCTION, operand: 0 }
|
|
],
|
|
constants: [
|
|
{
|
|
type: 'function_def',
|
|
params: [],
|
|
defaults: {},
|
|
body: 999,
|
|
variadic: false,
|
|
kwargs: false
|
|
}
|
|
]
|
|
})
|
|
|
|
const result = await vm.run()
|
|
expect(result.type).toBe('function')
|
|
if (result.type === 'function') {
|
|
expect(result.body).toBe(999)
|
|
expect(result.params).toEqual([])
|
|
}
|
|
})
|
|
|
|
test("CALL and RETURN - basic function call", async () => {
|
|
// Function that returns 42
|
|
const vm = new VM({
|
|
instructions: [
|
|
// 0: Create and call the function
|
|
{ op: OpCode.MAKE_FUNCTION, operand: 0 },
|
|
{ op: OpCode.CALL, operand: 0 }, // call with 0 args
|
|
{ op: OpCode.HALT },
|
|
|
|
// 3: Function body (starts here, address = 3)
|
|
{ op: OpCode.PUSH, operand: 1 }, // push 42
|
|
{ op: OpCode.RETURN }
|
|
],
|
|
constants: [
|
|
{
|
|
type: 'function_def',
|
|
params: [],
|
|
defaults: {},
|
|
body: 3, // function body starts at instruction 3
|
|
variadic: false,
|
|
kwargs: false
|
|
},
|
|
{ type: 'number', value: 42 }
|
|
]
|
|
})
|
|
|
|
const result = await vm.run()
|
|
expect(result).toEqual({ type: 'number', value: 42 })
|
|
})
|
|
|
|
test("CALL and RETURN - function with one parameter", async () => {
|
|
// Function that returns its parameter
|
|
const vm = new VM({
|
|
instructions: [
|
|
// 0: Push argument and call function
|
|
{ op: OpCode.MAKE_FUNCTION, operand: 0 },
|
|
{ op: OpCode.PUSH, operand: 1 }, // argument: 100
|
|
{ op: OpCode.CALL, operand: 1 }, // call with 1 arg
|
|
{ op: OpCode.HALT },
|
|
|
|
// 4: Function body
|
|
{ op: OpCode.LOAD, operand: 'x' }, // load parameter x
|
|
{ op: OpCode.RETURN }
|
|
],
|
|
constants: [
|
|
{
|
|
type: 'function_def',
|
|
params: ['x'],
|
|
defaults: {},
|
|
body: 4,
|
|
variadic: false,
|
|
kwargs: false
|
|
},
|
|
{ type: 'number', value: 100 }
|
|
]
|
|
})
|
|
|
|
const result = await vm.run()
|
|
expect(result).toEqual({ type: 'number', value: 100 })
|
|
})
|
|
|
|
test("CALL and RETURN - function with two parameters", async () => {
|
|
// Function that adds two parameters
|
|
const vm = new VM({
|
|
instructions: [
|
|
// 0: Push arguments and call function
|
|
{ op: OpCode.MAKE_FUNCTION, operand: 0 },
|
|
{ op: OpCode.PUSH, operand: 1 }, // arg1: 10
|
|
{ op: OpCode.PUSH, operand: 2 }, // arg2: 20
|
|
{ op: OpCode.CALL, operand: 2 }, // call with 2 args
|
|
{ op: OpCode.HALT },
|
|
|
|
// 5: Function body
|
|
{ op: OpCode.LOAD, operand: 'a' },
|
|
{ op: OpCode.LOAD, operand: 'b' },
|
|
{ op: OpCode.ADD },
|
|
{ op: OpCode.RETURN }
|
|
],
|
|
constants: [
|
|
{
|
|
type: 'function_def',
|
|
params: ['a', 'b'],
|
|
defaults: {},
|
|
body: 5,
|
|
variadic: false,
|
|
kwargs: false
|
|
},
|
|
{ type: 'number', value: 10 },
|
|
{ type: 'number', value: 20 }
|
|
]
|
|
})
|
|
|
|
const result = await vm.run()
|
|
expect(result).toEqual({ type: 'number', value: 30 })
|
|
})
|