ReefVM/tests/functions.test.ts

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 })
})