forked from defunkt/ReefVM
give more info on toValue() error
This commit is contained in:
parent
33ea94a247
commit
11b119a322
19
src/value.ts
19
src/value.ts
|
|
@ -65,7 +65,15 @@ export function toValue(v: any, vm?: VM): Value /* throws */ {
|
|||
case 'function':
|
||||
if ((v as any)[REEF_FUNCTION])
|
||||
return (v as any)[REEF_FUNCTION]
|
||||
if (!vm) throw new Error("can't toValue() function without a vm")
|
||||
if (!vm) {
|
||||
const fnName = v.name || '<anonymous>'
|
||||
const fnStr = v.toString().slice(0, 100)
|
||||
throw new Error(
|
||||
`can't toValue() function without a vm\n` +
|
||||
` Function: ${fnName}\n` +
|
||||
` Source: ${fnStr}${v.toString().length > 100 ? '...' : ''}\n`
|
||||
)
|
||||
}
|
||||
return { type: 'native', fn: wrapNative(vm, v), value: '<function>' }
|
||||
case 'object':
|
||||
const dict: Dict = new Map()
|
||||
|
|
@ -180,7 +188,14 @@ export function fromValue(v: Value, vm?: VM): any {
|
|||
case 'regex':
|
||||
return v.value
|
||||
case 'function':
|
||||
if (!vm || !(vm instanceof VM)) throw new Error('VM is required for function conversion')
|
||||
if (!vm || !(vm instanceof VM)) {
|
||||
throw new Error(
|
||||
`VM is required for function conversion\n` +
|
||||
` Function params: [${v.params.join(', ')}]\n` +
|
||||
` Function body at instruction: ${v.body}\n` +
|
||||
` Tip: Pass a VM instance as the second argument to fromValue()`
|
||||
)
|
||||
}
|
||||
return fnFromValue(v, vm)
|
||||
case 'native':
|
||||
return getOriginalFunction(v.fn)
|
||||
|
|
|
|||
|
|
@ -168,19 +168,70 @@ test("fromValue - async native function roundtrip", async () => {
|
|||
const bytecode = toBytecode([["HALT"]])
|
||||
const vm = new VM(bytecode)
|
||||
|
||||
// Create an async native function
|
||||
const asyncFn = async (x: number, y: number) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 1))
|
||||
return x + y
|
||||
}
|
||||
|
||||
// Roundtrip through Value
|
||||
const nativeValue = toValue(asyncFn, vm)
|
||||
expect(nativeValue.type).toBe("native")
|
||||
|
||||
const roundtrippedFn = fromValue(nativeValue, vm)
|
||||
|
||||
// Verify it works
|
||||
const result = await roundtrippedFn(5, 7)
|
||||
expect(result).toBe(12)
|
||||
})
|
||||
|
||||
test("toValue - throws helpful error when converting function without VM", () => {
|
||||
function myFunction(x: number) {
|
||||
return x * 2
|
||||
}
|
||||
|
||||
expect(() => toValue(myFunction)).toThrow(/can't toValue\(\) function without a vm/)
|
||||
expect(() => toValue(myFunction)).toThrow(/Function: myFunction/)
|
||||
expect(() => toValue(myFunction)).toThrow(/Source:/)
|
||||
expect(() => toValue(myFunction)).toThrow(/Tip: Pass a VM instance/)
|
||||
})
|
||||
|
||||
test("toValue - error message shows function name from binding", () => {
|
||||
const anonymousFn = (x: number) => x * 2
|
||||
|
||||
expect(() => toValue(anonymousFn)).toThrow(/Function: anonymousFn/)
|
||||
expect(() => toValue(anonymousFn)).toThrow(/Source:/)
|
||||
})
|
||||
|
||||
test("toValue - error when function is nested in object without VM", () => {
|
||||
const obj = {
|
||||
name: "test",
|
||||
handler: (x: number) => x * 2
|
||||
}
|
||||
|
||||
expect(() => toValue(obj)).toThrow(/can't toValue\(\) function without a vm/)
|
||||
expect(() => toValue(obj)).toThrow(/Function: handler/)
|
||||
})
|
||||
|
||||
test("toValue - error when function is nested in array without VM", () => {
|
||||
const arr = [1, 2, (x: number) => x * 2]
|
||||
|
||||
expect(() => toValue(arr)).toThrow(/can't toValue\(\) function without a vm/)
|
||||
})
|
||||
|
||||
test("fromValue - throws helpful error when converting function without VM", async () => {
|
||||
const { Scope, fromValue } = await import("#reef")
|
||||
|
||||
const reefFunction = {
|
||||
type: 'function' as const,
|
||||
params: ['x', 'y'],
|
||||
defaults: {},
|
||||
body: 10,
|
||||
parentScope: new Scope(),
|
||||
variadic: false,
|
||||
named: false,
|
||||
value: '<function>' as const
|
||||
}
|
||||
|
||||
expect(() => fromValue(reefFunction)).toThrow(/VM is required for function conversion/)
|
||||
expect(() => fromValue(reefFunction)).toThrow(/Function params: \[x, y\]/)
|
||||
expect(() => fromValue(reefFunction)).toThrow(/Function body at instruction: 10/)
|
||||
expect(() => fromValue(reefFunction)).toThrow(/Tip: Pass a VM instance/)
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user