forked from defunkt/ReefVM
more native named arg tests
This commit is contained in:
parent
797eb281cb
commit
f79fea33c5
|
|
@ -1011,7 +1011,7 @@ test("Native function calls multiple Reef functions", async () => {
|
|||
const doubled = await this.call('double', n)
|
||||
const tripled = await this.call('triple', n)
|
||||
|
||||
return doubled + tripled // 10 + 15 = 25
|
||||
return doubled + tripled
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
|
|
@ -1327,4 +1327,306 @@ test("Native function calls Reef function with named arguments", async () => {
|
|||
|
||||
const result = await vm.run()
|
||||
expect(result).toEqual({ type: 'string', value: "Hi Alice!" })
|
||||
})
|
||||
})
|
||||
test("vm.call() with only named arguments", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
; Reef function with default parameters
|
||||
MAKE_FUNCTION (name greeting='Hello') .greet_body
|
||||
STORE greet
|
||||
JUMP .skip_greet
|
||||
.greet_body:
|
||||
LOAD greeting
|
||||
PUSH " "
|
||||
LOAD name
|
||||
PUSH "!"
|
||||
STR_CONCAT #4
|
||||
RETURN
|
||||
.skip_greet:
|
||||
|
||||
LOAD call_greet
|
||||
PUSH 0
|
||||
PUSH 0
|
||||
CALL
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode, {
|
||||
call_greet: async function () {
|
||||
// Call with ONLY named arguments (no positional)
|
||||
return await this.call('greet', { name: "Bob", greeting: "Hey" })
|
||||
}
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
expect(result).toEqual({ type: 'string', value: "Hey Bob!" })
|
||||
})
|
||||
|
||||
test("Native function receives Reef closure with default params - calls with named args", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
; Reef function with default parameters
|
||||
MAKE_FUNCTION (x multiplier=2) .transform_body
|
||||
STORE transform
|
||||
JUMP .skip_transform
|
||||
.transform_body:
|
||||
LOAD x
|
||||
LOAD multiplier
|
||||
MUL
|
||||
RETURN
|
||||
.skip_transform:
|
||||
|
||||
; Pass to native map function
|
||||
LOAD map
|
||||
PUSH 1
|
||||
PUSH 2
|
||||
PUSH 3
|
||||
MAKE_ARRAY #3
|
||||
LOAD transform
|
||||
PUSH 2
|
||||
PUSH 0
|
||||
CALL
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode)
|
||||
|
||||
// Native function that calls the Reef closure with named arguments
|
||||
vm.registerFunction('map', async (array: any[], callback: Function) => {
|
||||
const results = []
|
||||
for (const item of array) {
|
||||
// Call with named argument to override the default
|
||||
results.push(await callback(item, { multiplier: 10 }))
|
||||
}
|
||||
return results
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
expect(result.type).toBe('array')
|
||||
if (result.type === 'array') {
|
||||
expect(result.value).toEqual([
|
||||
toValue(10), // 1 * 10
|
||||
toValue(20), // 2 * 10
|
||||
toValue(30) // 3 * 10
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
test("Native function receives Reef closure with variadic parameters", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
; Reef function with variadic params
|
||||
MAKE_FUNCTION (...nums) .sum_body
|
||||
STORE sum_all
|
||||
JUMP .skip_sum
|
||||
.sum_body:
|
||||
PUSH 0
|
||||
STORE total
|
||||
LOAD nums
|
||||
STORE items
|
||||
PUSH 0
|
||||
STORE idx
|
||||
|
||||
.loop:
|
||||
LOAD idx
|
||||
LOAD items
|
||||
ARRAY_LEN
|
||||
LT
|
||||
JUMP_IF_FALSE .done
|
||||
|
||||
LOAD total
|
||||
LOAD items
|
||||
LOAD idx
|
||||
ARRAY_GET
|
||||
ADD
|
||||
STORE total
|
||||
|
||||
LOAD idx
|
||||
PUSH 1
|
||||
ADD
|
||||
STORE idx
|
||||
JUMP .loop
|
||||
|
||||
.done:
|
||||
LOAD total
|
||||
RETURN
|
||||
.skip_sum:
|
||||
|
||||
; Pass to native function
|
||||
LOAD process
|
||||
LOAD sum_all
|
||||
PUSH 1
|
||||
PUSH 0
|
||||
CALL
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode)
|
||||
|
||||
// Native function that calls the variadic Reef closure with multiple args
|
||||
vm.registerFunction('process', async (callback: Function) => {
|
||||
// Call with varying number of arguments
|
||||
const result1 = await callback(1, 2, 3)
|
||||
const result2 = await callback(10, 20)
|
||||
return result1 + result2
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
expect(result).toEqual({ type: 'number', value: 36 }) // (1+2+3) + (10+20) = 6 + 30
|
||||
})
|
||||
|
||||
test("Native function receives Reef closure with @named parameter", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
; Reef function with @named parameter
|
||||
MAKE_FUNCTION (message @options) .format_body
|
||||
STORE format_message
|
||||
JUMP .skip_format
|
||||
.format_body:
|
||||
; Get uppercase option (default false)
|
||||
LOAD options
|
||||
PUSH "uppercase"
|
||||
DICT_GET
|
||||
STORE use_upper
|
||||
|
||||
; Get prefix option (default empty)
|
||||
LOAD options
|
||||
PUSH "prefix"
|
||||
DICT_GET
|
||||
STORE prefix_val
|
||||
|
||||
; Build result
|
||||
LOAD prefix_val
|
||||
LOAD message
|
||||
STR_CONCAT #2
|
||||
RETURN
|
||||
.skip_format:
|
||||
|
||||
; Pass to native function
|
||||
LOAD format_messages
|
||||
PUSH "hello"
|
||||
PUSH "world"
|
||||
MAKE_ARRAY #2
|
||||
LOAD format_message
|
||||
PUSH 2
|
||||
PUSH 0
|
||||
CALL
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode)
|
||||
|
||||
// Native function that calls Reef closure with named arguments
|
||||
vm.registerFunction('format_messages', async (messages: any[], formatter: Function) => {
|
||||
const results = []
|
||||
for (const msg of messages) {
|
||||
// Call with named arguments
|
||||
results.push(await formatter(msg, { prefix: "[LOG] ", uppercase: true }))
|
||||
}
|
||||
return results
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
expect(result.type).toBe('array')
|
||||
if (result.type === 'array') {
|
||||
expect(result.value).toEqual([
|
||||
toValue('[LOG] hello'),
|
||||
toValue('[LOG] world')
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
test("Native function receives Reef closure - calls with only named arguments", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
; Reef function expecting named arguments
|
||||
MAKE_FUNCTION (x=0 y=0 z=0) .add_body
|
||||
STORE add_coords
|
||||
JUMP .skip_add
|
||||
.add_body:
|
||||
LOAD x
|
||||
LOAD y
|
||||
ADD
|
||||
LOAD z
|
||||
ADD
|
||||
RETURN
|
||||
.skip_add:
|
||||
|
||||
; Pass to native function
|
||||
LOAD compute
|
||||
LOAD add_coords
|
||||
PUSH 1
|
||||
PUSH 0
|
||||
CALL
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode)
|
||||
|
||||
// Native function that calls Reef closure with ONLY named arguments
|
||||
vm.registerFunction('compute', async (callback: Function) => {
|
||||
// First call with all named args
|
||||
const result1 = await callback({ x: 10, y: 20, z: 30 })
|
||||
|
||||
// Second call with partial named args (rest use defaults)
|
||||
const result2 = await callback({ x: 5, z: 15 })
|
||||
|
||||
return result1 + result2
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
expect(result).toEqual({ type: 'number', value: 80 }) // (10+20+30) + (5+0+15) = 60 + 20
|
||||
})
|
||||
|
||||
test("Native function receives Reef closure with mixed positional and variadic", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
; Reef function with fixed param and variadic
|
||||
MAKE_FUNCTION (multiplier ...nums) .scale_body
|
||||
STORE scale_numbers
|
||||
JUMP .skip_scale
|
||||
.scale_body:
|
||||
PUSH 0
|
||||
STORE total
|
||||
LOAD nums
|
||||
STORE items
|
||||
PUSH 0
|
||||
STORE idx
|
||||
|
||||
.loop:
|
||||
LOAD idx
|
||||
LOAD items
|
||||
ARRAY_LEN
|
||||
LT
|
||||
JUMP_IF_FALSE .done
|
||||
|
||||
LOAD total
|
||||
LOAD items
|
||||
LOAD idx
|
||||
ARRAY_GET
|
||||
LOAD multiplier
|
||||
MUL
|
||||
ADD
|
||||
STORE total
|
||||
|
||||
LOAD idx
|
||||
PUSH 1
|
||||
ADD
|
||||
STORE idx
|
||||
JUMP .loop
|
||||
|
||||
.done:
|
||||
LOAD total
|
||||
RETURN
|
||||
.skip_scale:
|
||||
|
||||
; Pass to native function
|
||||
LOAD process_numbers
|
||||
LOAD scale_numbers
|
||||
PUSH 1
|
||||
PUSH 0
|
||||
CALL
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode)
|
||||
|
||||
// Native function that calls Reef closure with mixed args
|
||||
vm.registerFunction('process_numbers', async (calculator: Function) => {
|
||||
// Call with fixed multiplier and variadic numbers
|
||||
const result1 = await calculator(10, 1, 2, 3) // 10 * (1+2+3) = 60
|
||||
const result2 = await calculator(5, 4, 6) // 5 * (4+6) = 50
|
||||
return result1 + result2
|
||||
})
|
||||
|
||||
const result = await vm.run()
|
||||
expect(result).toEqual({ type: 'number', value: 110 }) // 60 + 50
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user