forked from defunkt/ReefVM
183 lines
3.7 KiB
TypeScript
183 lines
3.7 KiB
TypeScript
import { test, expect } from "bun:test"
|
|
import { toBytecode } from "#bytecode"
|
|
import { VM } from "#vm"
|
|
|
|
test("MAKE_FUNCTION - creates function with captured scope", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION () #999
|
|
`)
|
|
|
|
const result = await new VM(bytecode).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 () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION () #3
|
|
CALL #0
|
|
HALT
|
|
PUSH 42
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
expect(result).toEqual({ type: 'number', value: 42 })
|
|
})
|
|
|
|
test("CALL and RETURN - function with one parameter", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (x) #4
|
|
PUSH 100
|
|
CALL #1
|
|
HALT
|
|
LOAD x
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
expect(result).toEqual({ type: 'number', value: 100 })
|
|
})
|
|
|
|
test("CALL and RETURN - function with two parameters", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (a b) #5
|
|
PUSH 10
|
|
PUSH 20
|
|
CALL #2
|
|
HALT
|
|
LOAD a
|
|
LOAD b
|
|
ADD
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
expect(result).toEqual({ type: 'number', value: 30 })
|
|
})
|
|
|
|
test("CALL - variadic function with no fixed params", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (...args) #6
|
|
PUSH 1
|
|
PUSH 2
|
|
PUSH 3
|
|
CALL #3
|
|
HALT
|
|
LOAD args
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
expect(result).toEqual({
|
|
type: 'array',
|
|
value: [
|
|
{ type: 'number', value: 1 },
|
|
{ type: 'number', value: 2 },
|
|
{ type: 'number', value: 3 }
|
|
]
|
|
})
|
|
})
|
|
|
|
test("CALL - variadic function with one fixed param", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (x ...rest) #6
|
|
PUSH 10
|
|
PUSH 20
|
|
PUSH 30
|
|
CALL #3
|
|
HALT
|
|
LOAD rest
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
// x should be 10, rest should be [20, 30]
|
|
expect(result).toEqual({
|
|
type: 'array',
|
|
value: [
|
|
{ type: 'number', value: 20 },
|
|
{ type: 'number', value: 30 }
|
|
]
|
|
})
|
|
})
|
|
|
|
test("CALL - variadic function with two fixed params", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (a b ...rest) #7
|
|
PUSH 1
|
|
PUSH 2
|
|
PUSH 3
|
|
PUSH 4
|
|
CALL #4
|
|
HALT
|
|
LOAD rest
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
// a=1, b=2, rest=[3, 4]
|
|
expect(result).toEqual({
|
|
type: 'array',
|
|
value: [
|
|
{ type: 'number', value: 3 },
|
|
{ type: 'number', value: 4 }
|
|
]
|
|
})
|
|
})
|
|
|
|
test("CALL - variadic function with no extra args", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (x ...rest) #4
|
|
PUSH 10
|
|
CALL #1
|
|
HALT
|
|
LOAD rest
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
// rest should be empty array
|
|
expect(result).toEqual({ type: 'array', value: [] })
|
|
})
|
|
|
|
test("CALL - variadic function with defaults on fixed params", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (x=5 ...rest) #3
|
|
CALL #0
|
|
HALT
|
|
LOAD x
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
// x should use default value 5
|
|
expect(result).toEqual({ type: 'number', value: 5 })
|
|
})
|
|
|
|
test("TAIL_CALL - variadic function", async () => {
|
|
const bytecode = toBytecode(`
|
|
MAKE_FUNCTION (x ...rest) #6
|
|
PUSH 1
|
|
PUSH 2
|
|
PUSH 3
|
|
CALL #3
|
|
HALT
|
|
LOAD rest
|
|
RETURN
|
|
`)
|
|
|
|
const result = await new VM(bytecode).run()
|
|
// Should return the rest array [2, 3]
|
|
expect(result).toEqual({
|
|
type: 'array',
|
|
value: [
|
|
{ type: 'number', value: 2 },
|
|
{ type: 'number', value: 3 }
|
|
]
|
|
})
|
|
})
|