This commit is contained in:
Dmitry Vasilev
2022-12-22 22:14:36 +08:00
parent 23429845d2
commit 4dbc7c26e2
6 changed files with 102 additions and 46 deletions

View File

@@ -276,6 +276,11 @@ export const eval_modules = (
const codestring = const codestring =
` `
let children, prev_children let children, prev_children
// TODO refactor, move patch_promise here
globalThis.get_children = () => children
globalThis.set_children = (_children) => children = _children
// TODO use native array for stack for perf? // TODO use native array for stack for perf?
const stack = new Array() const stack = new Array()

View File

@@ -5,11 +5,36 @@ export const patch_promise = window => {
return return
} }
class PromiseRecordChildren extends Promise {
then(on_resolve, on_reject) {
let children = window.get_children()
if(children == null) {
children = []
window.set_children(children)
}
return super.then(
on_resolve == null
? null
: value => {
window.set_children(children)
return on_resolve(value)
},
on_reject == null
? null
: error => {
window.set_children(children)
return on_reject(error)
}
)
}
}
class PromiseWithStatus extends window.Promise { class PromiseWithStatus extends window.Promise {
constructor(fn) { constructor(fn) {
let status let status
let is_constructor_finished = false let is_constructor_finished = false
const p = new window.Promise.Original( const p = new PromiseRecordChildren(
(resolve, reject) => { (resolve, reject) => {
fn( fn(
(value) => { (value) => {

View File

@@ -3,7 +3,9 @@
export const reserved = [ export const reserved = [
'break', 'break',
'case', 'case',
'catch', // TODO: fix parser to allow catch be an Object key, as other reserved words.
// Currently we make exception for promise.catch
// 'catch',
'class', 'class',
'const', 'const',
'continue', 'continue',
@@ -14,7 +16,9 @@ export const reserved = [
'else', 'else',
'export', 'export',
'extends', 'extends',
'finally', // TODO: fix parser to allow finally be an Object key, as other reserved words.
// Currently we make exception for promise.finally
// 'finally',
'for', 'for',
'function', 'function',
'if', 'if',

View File

@@ -67,10 +67,8 @@ const dir = load_dir('.')
console.time('run') console.time('run')
const i = test_initial_state( const i = test_initial_state(
` {}, // files
import './test/run.js' {project_dir: dir, entrypoint: 'test/run.js'}
`,
{project_dir: dir}
) )
assert_equal(i.loading_external_imports_state != null, true) assert_equal(i.loading_external_imports_state != null, true)
@@ -81,6 +79,8 @@ assert_equal(loaded.eval_modules_state != null, true)
const s = loaded.eval_modules_state const s = loaded.eval_modules_state
const result = await s.promise const result = await s.promise
const state = COMMANDS.eval_modules_finished(loaded , result, s.node, s.toplevel) const state = COMMANDS.eval_modules_finished(loaded , result, s.node, s.toplevel)
const root = root_calltree_node(state)
const run = root.children[0]
assert_equal(root_calltree_node(state).ok, true) assert_equal(root_calltree_node(state).ok, true)

View File

@@ -2779,18 +2779,38 @@ const y = x()`
) )
}), }),
// TODO
/*
test('async/await Promise.then creates subcall', async () => { test('async/await Promise.then creates subcall', async () => {
const i = await test_initial_state_async(` const i = await test_initial_state_async(`
await Promise.resolve(1).then(x => { const x = () => 1
}) await Promise.resolve(1).then(x)
`) `)
console.log('i', root_calltree_node(i)) const root = root_calltree_node(i)
assert_equal(root.children.at(-1).children[0].fn.name, 'x')
}), }),
test('async/await bug', async () => { test('async/await Promise.catch creates subcall', async () => {
const i = await test_initial_state_async(`
const x = () => 1
await Promise.reject(1).catch(x)
`)
const root = root_calltree_node(i)
assert_equal(root.children.at(-1).children[0].fn.name, 'x')
}),
test_only('async/await native Promise.then creates subcall', async () => {
const i = await test_initial_state_async(`
const x = () => 1
const async_fn = async () => 1
await async_fn().then(x)
`)
const root = root_calltree_node(i)
assert_equal(root.children.at(-1).children[0].fn.name, 'x')
}),
/*
// TODO
test('async/await move_cursor', async () => {
const code = ` const code = `
const f = async () => { const f = async () => {
console.log('f') console.log('f')

View File

@@ -151,13 +151,12 @@ export const test_only = (message, t) => test(message, t, true)
// TODO in calltree view, hide fn which has special flag set (see // TODO in calltree view, hide fn which has special flag set (see
// filter_calltree) // filter_calltree)
const AsyncFunction = new Function(`return (async () => {}).constructor`)() export const run = Object.defineProperty(new Function('tests', `
// Runs test, return failure or null if not failed
export const run = Object.defineProperty(new AsyncFunction('tests', ` const run_test = t => {
const run_test = async t => { return Promise.resolve(t.test())
try { .then(() => null)
await t.test() .catch(e => {
} catch(e) {
if(globalThis.process != null) { if(globalThis.process != null) {
// In node.js runner, fail fast // In node.js runner, fail fast
console.error('Failed: ' + t.message) console.error('Failed: ' + t.message)
@@ -165,7 +164,7 @@ export const run = Object.defineProperty(new AsyncFunction('tests', `
} else { } else {
return e return e
} }
} })
} }
// If not run in node, then dont apply filter // If not run in node, then dont apply filter
@@ -178,14 +177,14 @@ export const run = Object.defineProperty(new AsyncFunction('tests', `
// Exec each test. After all tests are done, we rethrow first error if // Exec each test. After all tests are done, we rethrow first error if
// any. So we will mark root calltree node if one of tests failed // any. So we will mark root calltree node if one of tests failed
const failure = await tests_to_run.reduce( return tests_to_run.reduce(
async (failureP, t) => { (failureP, t) =>
const failure = await failureP Promise.resolve(failureP).then(failure =>
const next_failure = await run_test(t) run_test(t).then(next_failure => failure ?? next_failure)
return failure ?? next_failure
},
null
) )
,
null
).then(failure => {
if(failure != null) { if(failure != null) {
throw failure throw failure
@@ -195,15 +194,18 @@ export const run = Object.defineProperty(new AsyncFunction('tests', `
} }
} }
})
} else { } else {
const test = tests.find(t => t.message.includes(filter)) const test = tests.find(t => t.message.includes(filter))
if(test == null) { if(test == null) {
throw new Error('test not found') throw new Error('test not found')
} else { } else {
await run_test(test) return run_test(test).then(() => {
if(globalThis.process != null) { if(globalThis.process != null) {
console.log('Ok') console.log('Ok')
} }
})
} }
} }
`), 'name', {value: 'run'}) `), 'name', {value: 'run'})