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 doubled = await this.call('double', n)
|
||||||
const tripled = await this.call('triple', n)
|
const tripled = await this.call('triple', n)
|
||||||
|
|
||||||
return doubled + tripled // 10 + 15 = 25
|
return doubled + tripled
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await vm.run()
|
const result = await vm.run()
|
||||||
|
|
@ -1328,3 +1328,305 @@ test("Native function calls Reef function with named arguments", async () => {
|
||||||
const result = await vm.run()
|
const result = await vm.run()
|
||||||
expect(result).toEqual({ type: 'string', value: "Hi Alice!" })
|
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