mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 13:04:30 -08:00
fix await bug
This commit is contained in:
15
src/eval.js
15
src/eval.js
@@ -80,6 +80,11 @@ const codegen_function_expr = (node, node_cxt) => {
|
|||||||
// TODO gensym __obj, __fn, __call_id, __let_vars, __literals
|
// TODO gensym __obj, __fn, __call_id, __let_vars, __literals
|
||||||
const prolog =
|
const prolog =
|
||||||
'{const __call_id = __cxt.call_counter;'
|
'{const __call_id = __cxt.call_counter;'
|
||||||
|
+ (
|
||||||
|
node.is_async
|
||||||
|
? 'let __await_state;'
|
||||||
|
: ''
|
||||||
|
)
|
||||||
+ (
|
+ (
|
||||||
node.has_versioned_let_vars
|
node.has_versioned_let_vars
|
||||||
? 'const __let_vars = __cxt.let_vars;'
|
? 'const __let_vars = __cxt.let_vars;'
|
||||||
@@ -346,7 +351,9 @@ const codegen = (node, node_cxt) => {
|
|||||||
+ ']'
|
+ ']'
|
||||||
} else if(node.type == 'unary') {
|
} else if(node.type == 'unary') {
|
||||||
if(node.operator == 'await') {
|
if(node.operator == 'await') {
|
||||||
return `(await __do_await(__cxt, ${do_codegen(node.expr)}))`
|
return `(__await_state = __await_start(__cxt, ${do_codegen(node.expr)}),` +
|
||||||
|
`await __await_state.promise,` +
|
||||||
|
`__await_finish(__cxt, __await_state))`
|
||||||
} else {
|
} else {
|
||||||
return '(' + node.operator + ' ' + do_codegen(node.expr) + ')'
|
return '(' + node.operator + ' ' + do_codegen(node.expr) + ')'
|
||||||
}
|
}
|
||||||
@@ -416,7 +423,7 @@ export const eval_modules = (
|
|||||||
io_trace,
|
io_trace,
|
||||||
) => {
|
) => {
|
||||||
// TODO gensym __cxt, __trace, __trace_call, __calltree_node_by_loc,
|
// TODO gensym __cxt, __trace, __trace_call, __calltree_node_by_loc,
|
||||||
// __do_await, __Multiversion, __create_array, __create_object
|
// __await_start, __await_finish, __Multiversion, __create_array, __create_object
|
||||||
|
|
||||||
// TODO bug if module imported twice, once as external and as regular
|
// TODO bug if module imported twice, once as external and as regular
|
||||||
|
|
||||||
@@ -446,7 +453,8 @@ export const eval_modules = (
|
|||||||
'__calltree_node_by_loc',
|
'__calltree_node_by_loc',
|
||||||
'__trace',
|
'__trace',
|
||||||
'__trace_call',
|
'__trace_call',
|
||||||
'__do_await',
|
'__await_start',
|
||||||
|
'__await_finish',
|
||||||
'__save_ct_node_for_path',
|
'__save_ct_node_for_path',
|
||||||
'__Multiversion',
|
'__Multiversion',
|
||||||
'__create_array',
|
'__create_array',
|
||||||
@@ -457,6 +465,7 @@ export const eval_modules = (
|
|||||||
* because we dont want to codegen differently for if statements in
|
* because we dont want to codegen differently for if statements in
|
||||||
* toplevel and if statements within functions*/
|
* toplevel and if statements within functions*/
|
||||||
'const __call_id = __cxt.call_counter;' +
|
'const __call_id = __cxt.call_counter;' +
|
||||||
|
'let __await_state;' +
|
||||||
code
|
code
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ const do_run = function*(module_fns, cxt, io_trace){
|
|||||||
calltree_node_by_loc.get(module),
|
calltree_node_by_loc.get(module),
|
||||||
__trace,
|
__trace,
|
||||||
__trace_call,
|
__trace_call,
|
||||||
__do_await,
|
__await_start,
|
||||||
|
__await_finish,
|
||||||
__save_ct_node_for_path,
|
__save_ct_node_for_path,
|
||||||
LetMultiversion,
|
LetMultiversion,
|
||||||
create_array,
|
create_array,
|
||||||
@@ -250,9 +251,7 @@ export const do_eval_expand_calltree_node = (cxt, node) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const __await_start = (cxt, promise) => {
|
||||||
|
|
||||||
const __do_await = async (cxt, value) => {
|
|
||||||
// children is an array of child calls for current function call. But it
|
// children is an array of child calls for current function call. But it
|
||||||
// can be null to save one empty array allocation in case it has no child
|
// can be null to save one empty array allocation in case it has no child
|
||||||
// calls. Allocate array now, so we can have a reference to this array
|
// calls. Allocate array now, so we can have a reference to this array
|
||||||
@@ -261,20 +260,33 @@ const __do_await = async (cxt, value) => {
|
|||||||
cxt.children = []
|
cxt.children = []
|
||||||
}
|
}
|
||||||
const children_copy = cxt.children
|
const children_copy = cxt.children
|
||||||
if(value instanceof cxt.window.Promise) {
|
const result = {children_copy, promise}
|
||||||
value.__original_then(
|
|
||||||
v => {
|
if(promise instanceof cxt.window.Promise) {
|
||||||
value.status = {ok: true, value: v}
|
result.promise = promise.then(
|
||||||
|
(value) => {
|
||||||
|
result.status = {ok: true, value}
|
||||||
|
// We do not return value on purpose - it will be return in
|
||||||
|
// __await_finish
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
result.status = {ok: false, error}
|
||||||
|
// We do not throw error on purpose
|
||||||
},
|
},
|
||||||
e => {
|
|
||||||
value.status = {ok: false, error: e}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
result.status = {ok: true, value: promise}
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
return await value
|
return result
|
||||||
} finally {
|
}
|
||||||
cxt.children = children_copy
|
|
||||||
|
const __await_finish = (__cxt, await_state) => {
|
||||||
|
__cxt.children = await_state.children_copy
|
||||||
|
if(await_state.status.ok) {
|
||||||
|
return await_state.status.value
|
||||||
|
} else {
|
||||||
|
throw await_state.status.error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
test/test.js
25
test/test.js
@@ -3695,6 +3695,18 @@ const y = x()`
|
|||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
test('async/await await rejected Promise fn call', async () => {
|
||||||
|
await assert_code_error_async(
|
||||||
|
`
|
||||||
|
async function test() {
|
||||||
|
await Promise.reject('boom')
|
||||||
|
}
|
||||||
|
await test()
|
||||||
|
`,
|
||||||
|
'boom'
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
test('async/await promise rejected with null', async () => {
|
test('async/await promise rejected with null', async () => {
|
||||||
await assert_code_error_async(
|
await assert_code_error_async(
|
||||||
`await Promise.reject()`,
|
`await Promise.reject()`,
|
||||||
@@ -3872,6 +3884,19 @@ const y = x()`
|
|||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
test('async/await await bug', async () => {
|
||||||
|
const code = `
|
||||||
|
const x = () => {}
|
||||||
|
const test = async () => {
|
||||||
|
await 1
|
||||||
|
x()
|
||||||
|
}
|
||||||
|
await Promise.all([test(), test()])
|
||||||
|
`
|
||||||
|
const i = await test_initial_state_async(code, code.indexOf('await 1'))
|
||||||
|
assert_value_explorer(i ,1)
|
||||||
|
}),
|
||||||
|
|
||||||
test('async/await edit', async () => {
|
test('async/await edit', async () => {
|
||||||
const code = `
|
const code = `
|
||||||
const f = async () => {
|
const f = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user