From 3ea0bedc31f38a68a862c5d793d2b3d7e78e8267 Mon Sep 17 00:00:00 2001 From: Dmitry Vasilev Date: Wed, 7 Dec 2022 05:42:33 +0800 Subject: [PATCH] WIP --- src/calltree.js | 1 + src/effects.js | 14 +++++++++-- src/eval.js | 11 +-------- src/find_definitions.js | 17 ++++++++++--- src/patch_promise.js | 20 ++++++++++++--- test/test.js | 55 +++++++++++++++++++++++++++++------------ test/utils.js | 2 +- 7 files changed, 84 insertions(+), 36 deletions(-) diff --git a/src/calltree.js b/src/calltree.js index 6649973..1ed846f 100644 --- a/src/calltree.js +++ b/src/calltree.js @@ -7,6 +7,7 @@ import {eval_frame} from './eval.js' export const pp_calltree = tree => ({ id: tree.id, ok: tree.ok, + value: tree.value, is_log: tree.is_log, has_more_children: tree.has_more_children, string: tree.code?.string, diff --git a/src/effects.js b/src/effects.js index 5f27114..6fc9db4 100644 --- a/src/effects.js +++ b/src/effects.js @@ -177,7 +177,11 @@ export const render_common_side_effects = async (prev, next, command, ui) => { load_external_imports(next) } - if(prev.eval_modules_state != next.eval_modules_state) { + if( + prev.eval_modules_state != next.eval_modules_state + && + next.eval_modules_state != null + ) { const s = next.eval_modules_state s.promise.then(result => { exec('eval_modules_finished', result, s.node, s.toplevel) @@ -188,7 +192,13 @@ export const render_common_side_effects = async (prev, next, command, ui) => { render_parse_result(ui, next) } - if(!next.parse_result.ok || next.loading_external_imports_state != null) { + if( + !next.parse_result.ok + || + next.loading_external_imports_state != null + || + next.eval_modules_state != null + ) { // TODO if loading external imports, show loading indicator ui.calltree.clear_calltree() diff --git a/src/eval.js b/src/eval.js index 2cfe0b6..e315e9d 100644 --- a/src/eval.js +++ b/src/eval.js @@ -260,16 +260,6 @@ const codegen = (node, cxt, parent) => { } } -/* TODO remove -const sync_promise = value => { - if(value instanceof run_window.Promise.Original) { - return value - } else { - return {is_sync_promise: true, then: fn => sync_promise(fn(value))} - } -} -*/ - export const eval_modules = ( parse_result, external_imports, @@ -955,6 +945,7 @@ const do_eval_frame_expr = (node, scope, callsleft) => { ok = true value = typeof(expr.result.value) } else if(node.operator == '-') { + ok = true value = - expr.result.value } else if(node.operator == 'await') { const run_window = globalThis.run_window ?? globalThis diff --git a/src/find_definitions.js b/src/find_definitions.js index 528f488..89bb2b7 100644 --- a/src/find_definitions.js +++ b/src/find_definitions.js @@ -203,9 +203,20 @@ export const topsort_modules = (modules) => { } export const has_toplevel_await = modules => - Object.values(modules).some(m => - m.children.find(c => c.type == 'unary' && c.operator == 'await' ) != null - ) + Object.values(modules).some(m => node_has_toplevel_await(m)) + +const node_has_toplevel_await = node => { + if(node.type == 'unary' && node.operator == 'await') { + return true + } + if(node.type == 'function_expr') { + return false + } + if(node.children == null) { + return false + } + return node.children.find(c => node_has_toplevel_await(c)) != null +} // TODO not implemented // TODO detect cycles when loading modules diff --git a/src/patch_promise.js b/src/patch_promise.js index b2bd462..d7517c7 100644 --- a/src/patch_promise.js +++ b/src/patch_promise.js @@ -13,11 +13,23 @@ export const patch_promise = window => { (resolve, reject) => { fn( (value) => { - status = {ok: true, value} - if(is_constructor_finished) { - this.status = status + if(value instanceof window.Promise.Original) { + value + .then(v => { + this.status = {ok: true, value: v} + resolve(v) + }) + .catch(e => { + this.status = {ok: false, error: e} + reject(e) + }) + } else { + status = {ok: true, value} + if(is_constructor_finished) { + this.status = status + } + resolve(value) } - resolve(value) }, (error) => { status = {ok: false, error} diff --git a/test/test.js b/test/test.js index ca523e3..6144cc4 100644 --- a/test/test.js +++ b/test/test.js @@ -2600,7 +2600,7 @@ const y = x()` ) }), - test('async/await await Promise', async () => { + test('async/await await resolved Promise', async () => { await assert_code_evals_to_async( ` await Promise.resolve(123) @@ -2609,6 +2609,34 @@ const y = x()` ) }), + test('async/await await Promise resolved with resolved Promise', async () => { + await assert_code_evals_to_async( + ` + await Promise.resolve(Promise.resolve(123)) + `, + 123 + ) + }), + + test('async/await await Promise resolved with async', async () => { + await assert_code_evals_to_async( + ` + const x = async () => 1 + await Promise.resolve(x()) + `, + 1 + ) + }), + + test('async/await await Promise resolved with rejected Promise', async () => { + await assert_code_error_async( + ` + await Promise.resolve(Promise.reject('boom')) + `, + 'boom', + ) + }), + test('async/await await Promise returned from async function', async () => { await assert_code_evals_to_async( ` @@ -2640,15 +2668,6 @@ const y = x()` ) }), - test('async/await await rejected Promise', async () => { - await assert_code_error_async( - ` - await Promise.reject('boom') - `, - 'boom' - ) - }), - test('async/await await rejected Promise returned from async', async () => { await assert_code_error_async( ` @@ -2659,10 +2678,14 @@ const y = x()` ) }), - // TODO - //assert_equal('s', active_frame - //const result = await s.eval_modules_state - //const move = COMMANDS.move_cursor(s, code.indexOf('await x()')).state - //log('m', root_calltree_node(move).children[0].children[0].value) - //log(s.parse_result.modules['']) + test('async/await Promise.all', async () => { + await assert_code_evals_to_async( + ` + const x = async i => i + await Promise.all([x(0), x(1), x(2)]) + `, + [0,1,2] + ) + }), + ] diff --git a/test/utils.js b/test/utils.js index 693cf5b..85e8902 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,6 +1,6 @@ import {parse, print_debug_node, load_modules} from '../src/parse_js.js' import {eval_tree, eval_frame} from '../src/eval.js' -import {active_frame} from '../src/calltree.js' +import {active_frame, pp_calltree} from '../src/calltree.js' import {COMMANDS} from '../src/cmd.js' Object.assign(globalThis, {log: console.log})