Compare commits
No commits in common. "4898a6bb5a3843f529e652303491d075af12515c" and "df9af925d33b08a32e69961c212db166e9d97146" have entirely different histories.
4898a6bb5a
...
df9af925d3
|
|
@ -401,8 +401,9 @@ export class VM {
|
|||
const key = this.stack.pop()!
|
||||
namedPairs.unshift({ key: toString(key), value })
|
||||
}
|
||||
for (const pair of namedPairs)
|
||||
for (const pair of namedPairs) {
|
||||
namedArgs.set(pair.key, pair.value)
|
||||
}
|
||||
|
||||
// Pop positional arguments from stack
|
||||
const positionalArgs: Value[] = []
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { test, expect } from "bun:test"
|
||||
import { toBytecode } from "#bytecode"
|
||||
import { toValue, run } from "#reef"
|
||||
import { VM } from "#vm"
|
||||
|
||||
test("MAKE_FUNCTION - creates function with captured scope", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
MAKE_FUNCTION () #999
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('function')
|
||||
if (result.type === 'function') {
|
||||
expect(result.body).toBe(999)
|
||||
|
|
@ -26,7 +26,7 @@ test("CALL and RETURN - basic function call", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'number', value: 42 })
|
||||
})
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ test("CALL and RETURN - function with one parameter", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'number', value: 100 })
|
||||
})
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ test("CALL and RETURN - function with two parameters", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'number', value: 30 })
|
||||
})
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ test("CALL - variadic function with no fixed params", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({
|
||||
type: 'array',
|
||||
value: [
|
||||
|
|
@ -104,7 +104,7 @@ test("CALL - variadic function with one fixed param", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// x should be 10, rest should be [20, 30]
|
||||
expect(result).toEqual({
|
||||
type: 'array',
|
||||
|
|
@ -130,7 +130,7 @@ test("CALL - variadic function with two fixed params", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// a=1, b=2, rest=[3, 4]
|
||||
expect(result).toEqual({
|
||||
type: 'array',
|
||||
|
|
@ -153,7 +153,7 @@ test("CALL - variadic function with no extra args", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// rest should be empty array
|
||||
expect(result).toEqual({ type: 'array', value: [] })
|
||||
})
|
||||
|
|
@ -169,7 +169,7 @@ test("CALL - variadic function with defaults on fixed params", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// x should use default value 5
|
||||
expect(result).toEqual({ type: 'number', value: 5 })
|
||||
})
|
||||
|
|
@ -188,7 +188,7 @@ test("TAIL_CALL - variadic function", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// Should return the rest array [2, 3]
|
||||
expect(result).toEqual({
|
||||
type: 'array',
|
||||
|
|
@ -214,7 +214,7 @@ test("CALL - named args function with no fixed params", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('dict')
|
||||
if (result.type === 'dict') {
|
||||
expect(result.value.get('name')).toEqual({ type: 'string', value: 'Bob' })
|
||||
|
|
@ -236,7 +236,7 @@ test("CALL - named args function with one fixed param", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('dict')
|
||||
if (result.type === 'dict') {
|
||||
expect(result.value.get('name')).toEqual({ type: 'string', value: 'Alice' })
|
||||
|
|
@ -258,7 +258,7 @@ test("CALL - named args with matching param name should bind to param not named"
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// name should be bound as regular param, not collected in named
|
||||
expect(result).toEqual({ type: 'string', value: 'Bob' })
|
||||
})
|
||||
|
|
@ -278,7 +278,7 @@ test("CALL - named args that match param names should not be in named", async ()
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('dict')
|
||||
if (result.type === 'dict') {
|
||||
// Only city should be in named, name should be bound to param
|
||||
|
|
@ -304,7 +304,7 @@ test("CALL - mixed variadic and named args", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// rest should have [2, 3]
|
||||
expect(result).toEqual({
|
||||
type: 'array',
|
||||
|
|
@ -331,7 +331,7 @@ test("CALL - mixed variadic and named args, check named", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('dict')
|
||||
if (result.type === 'dict') {
|
||||
expect(result.value.get('name')).toEqual({ type: 'string', value: 'Bob' })
|
||||
|
|
@ -350,7 +350,7 @@ test("CALL - named args with no extra named args", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// named should be empty dict
|
||||
expect(result.type).toBe('dict')
|
||||
if (result.type === 'dict') {
|
||||
|
|
@ -371,34 +371,11 @@ test("CALL - named args with defaults on fixed params", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// x should use default value 5
|
||||
expect(result).toEqual({ type: 'number', value: 5 })
|
||||
})
|
||||
|
||||
test("CALL - fixed params can be named", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
MAKE_FUNCTION (a b) .func_0
|
||||
STORE minus
|
||||
TRY_LOAD minus
|
||||
PUSH 200
|
||||
PUSH 'a'
|
||||
PUSH 900
|
||||
PUSH 1
|
||||
PUSH 1
|
||||
CALL
|
||||
HALT
|
||||
.func_0:
|
||||
TRY_LOAD a
|
||||
TRY_LOAD b
|
||||
SUB
|
||||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
expect(result).toEqual(toValue(700))
|
||||
})
|
||||
|
||||
test("TRY_CALL - calls function if found", async () => {
|
||||
const bytecode = toBytecode([
|
||||
["MAKE_FUNCTION", [], ".body"],
|
||||
|
|
@ -410,7 +387,7 @@ test("TRY_CALL - calls function if found", async () => {
|
|||
["RETURN"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'number', value: 42 })
|
||||
})
|
||||
|
||||
|
|
@ -422,7 +399,7 @@ test("TRY_CALL - pushes value if variable exists but is not a function", async (
|
|||
["HALT"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'number', value: 99 })
|
||||
})
|
||||
|
||||
|
|
@ -432,7 +409,7 @@ test("TRY_CALL - pushes string if variable not found", async () => {
|
|||
["HALT"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'string', value: 'unknownVar' })
|
||||
})
|
||||
|
||||
|
|
@ -446,7 +423,7 @@ test("TRY_CALL - handles arrays", async () => {
|
|||
["HALT"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('array')
|
||||
if (result.type === 'array') {
|
||||
expect(result.value).toEqual([
|
||||
|
|
@ -466,7 +443,7 @@ test("TRY_CALL - handles dicts", async () => {
|
|||
["HALT"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result.type).toBe('dict')
|
||||
if (result.type === 'dict') {
|
||||
expect(result.value.get('key')).toEqual({ type: 'string', value: 'value' })
|
||||
|
|
@ -481,7 +458,7 @@ test("TRY_CALL - handles null values", async () => {
|
|||
["HALT"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'null', value: null })
|
||||
})
|
||||
|
||||
|
|
@ -500,7 +477,7 @@ test("TRY_CALL - function can access its parameters", async () => {
|
|||
["RETURN"]
|
||||
])
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
// Function is called with 0 args, so x inside function should be null
|
||||
// Then we add 5 to null (which coerces to 0)
|
||||
expect(result).toEqual({ type: 'number', value: 5 })
|
||||
|
|
@ -516,6 +493,6 @@ test("TRY_CALL - with string format", async () => {
|
|||
RETURN
|
||||
`)
|
||||
|
||||
const result = await run(bytecode)
|
||||
const result = await new VM(bytecode).run()
|
||||
expect(result).toEqual({ type: 'number', value: 100 })
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user