even more debug info

This commit is contained in:
Chris Wanstrath 2025-11-05 15:16:41 -08:00
parent 11b119a322
commit e7201e691c
2 changed files with 19 additions and 4 deletions

View File

@ -68,10 +68,18 @@ export function toValue(v: any, vm?: VM): Value /* throws */ {
if (!vm) { if (!vm) {
const fnName = v.name || '<anonymous>' const fnName = v.name || '<anonymous>'
const fnStr = v.toString().slice(0, 100) const fnStr = v.toString().slice(0, 100)
const stack = new Error().stack || ''
const stackLines = stack.split('\n')
.slice(1)
.filter(line => !line.includes('toValue'))
.slice(0, 3)
.map(line => ' ' + line.trim())
.join('\n')
throw new Error( throw new Error(
`can't toValue() function without a vm\n` + `can't toValue() function without a vm\n` +
` Function: ${fnName}\n` + ` Function: ${fnName}\n` +
` Source: ${fnStr}${v.toString().length > 100 ? '...' : ''}\n` ` Source: ${fnStr}${v.toString().length > 100 ? '...' : ''}\n` +
` Called from:\n${stackLines}`
) )
} }
return { type: 'native', fn: wrapNative(vm, v), value: '<function>' } return { type: 'native', fn: wrapNative(vm, v), value: '<function>' }
@ -189,11 +197,18 @@ export function fromValue(v: Value, vm?: VM): any {
return v.value return v.value
case 'function': case 'function':
if (!vm || !(vm instanceof VM)) { if (!vm || !(vm instanceof VM)) {
const stack = new Error().stack || ''
const stackLines = stack.split('\n')
.slice(1)
.filter(line => !line.includes('fromValue'))
.slice(0, 3)
.map(line => ' ' + line.trim())
.join('\n')
throw new Error( throw new Error(
`VM is required for function conversion\n` + `VM is required for function conversion\n` +
` Function params: [${v.params.join(', ')}]\n` + ` Function params: [${v.params.join(', ')}]\n` +
` Function body at instruction: ${v.body}\n` + ` Function body at instruction: ${v.body}\n` +
` Tip: Pass a VM instance as the second argument to fromValue()` ` Called from:\n${stackLines}`
) )
} }
return fnFromValue(v, vm) return fnFromValue(v, vm)

View File

@ -190,7 +190,7 @@ test("toValue - throws helpful error when converting function without VM", () =>
expect(() => toValue(myFunction)).toThrow(/can't toValue\(\) function without a vm/) expect(() => toValue(myFunction)).toThrow(/can't toValue\(\) function without a vm/)
expect(() => toValue(myFunction)).toThrow(/Function: myFunction/) expect(() => toValue(myFunction)).toThrow(/Function: myFunction/)
expect(() => toValue(myFunction)).toThrow(/Source:/) expect(() => toValue(myFunction)).toThrow(/Source:/)
expect(() => toValue(myFunction)).toThrow(/Tip: Pass a VM instance/) expect(() => toValue(myFunction)).toThrow(/Called from:/)
}) })
test("toValue - error message shows function name from binding", () => { test("toValue - error message shows function name from binding", () => {
@ -233,5 +233,5 @@ test("fromValue - throws helpful error when converting function without VM", asy
expect(() => fromValue(reefFunction)).toThrow(/VM is required for function conversion/) expect(() => fromValue(reefFunction)).toThrow(/VM is required for function conversion/)
expect(() => fromValue(reefFunction)).toThrow(/Function params: \[x, y\]/) expect(() => fromValue(reefFunction)).toThrow(/Function params: \[x, y\]/)
expect(() => fromValue(reefFunction)).toThrow(/Function body at instruction: 10/) expect(() => fromValue(reefFunction)).toThrow(/Function body at instruction: 10/)
expect(() => fromValue(reefFunction)).toThrow(/Tip: Pass a VM instance/) expect(() => fromValue(reefFunction)).toThrow(/Called from:/)
}) })