mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 13:04:30 -08:00
async calls find_call and test async call nav
This commit is contained in:
@@ -606,7 +606,7 @@ export const find_call = (state, index) => {
|
|||||||
|
|
||||||
if(ct_node_id != null) {
|
if(ct_node_id != null) {
|
||||||
const ct_node = find_node(
|
const ct_node = find_node(
|
||||||
root_calltree_node(state),
|
state.calltree,
|
||||||
n => n.id == ct_node_id
|
n => n.id == ct_node_id
|
||||||
)
|
)
|
||||||
if(ct_node == null) {
|
if(ct_node == null) {
|
||||||
@@ -630,7 +630,12 @@ export const find_call = (state, index) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loc = {index: node.index, module: state.current_module}
|
const loc = {index: node.index, module: state.current_module}
|
||||||
const {calltree, call} = state.calltree_actions.find_call(
|
const {
|
||||||
|
calltree,
|
||||||
|
call,
|
||||||
|
is_found_async_call,
|
||||||
|
async_call_index
|
||||||
|
} = state.calltree_actions.find_call(
|
||||||
loc,
|
loc,
|
||||||
get_async_calls(state)
|
get_async_calls(state)
|
||||||
)
|
)
|
||||||
@@ -645,20 +650,41 @@ export const find_call = (state, index) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const merged = make_calltree(
|
let next_calltree, active_calltree_node
|
||||||
merge_calltrees(root_calltree_node(state), calltree),
|
|
||||||
get_async_calls(state),
|
|
||||||
)
|
|
||||||
|
|
||||||
const active_calltree_node = find_same_node(
|
if(is_found_async_call) {
|
||||||
root_calltree_node({calltree: merged}),
|
const async_calls = get_async_calls(state)
|
||||||
calltree,
|
const prev_call = async_calls[async_call_index]
|
||||||
call.id
|
const merged = merge_calltrees(prev_call, calltree)
|
||||||
)
|
const next_async_calls = async_calls.map((c, i) =>
|
||||||
|
i == async_call_index
|
||||||
|
? merged
|
||||||
|
: c
|
||||||
|
)
|
||||||
|
next_calltree = make_calltree(
|
||||||
|
root_calltree_node(state),
|
||||||
|
next_async_calls,
|
||||||
|
)
|
||||||
|
active_calltree_node = find_same_node(
|
||||||
|
merged,
|
||||||
|
calltree,
|
||||||
|
call.id
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
next_calltree = make_calltree(
|
||||||
|
merge_calltrees(root_calltree_node(state), calltree),
|
||||||
|
get_async_calls(state),
|
||||||
|
)
|
||||||
|
active_calltree_node = find_same_node(
|
||||||
|
root_calltree_node({calltree: next_calltree}),
|
||||||
|
calltree,
|
||||||
|
call.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return add_frame(
|
return add_frame(
|
||||||
expand_path(
|
expand_path(
|
||||||
{...state, calltree: merged},
|
{...state, calltree: next_calltree},
|
||||||
active_calltree_node
|
active_calltree_node
|
||||||
),
|
),
|
||||||
active_calltree_node,
|
active_calltree_node,
|
||||||
|
|||||||
38
src/eval.js
38
src/eval.js
@@ -312,19 +312,40 @@ export const eval_modules = (
|
|||||||
|
|
||||||
const find_call = (location, async_calls) => {
|
const find_call = (location, async_calls) => {
|
||||||
searched_location = location
|
searched_location = location
|
||||||
const {modules, calltree} = run()
|
let is_found_async_call = false
|
||||||
|
let i
|
||||||
|
|
||||||
|
let {calltree} = run()
|
||||||
|
|
||||||
|
is_recording_async_calls = false
|
||||||
if(found_call == null && async_calls != null) {
|
if(found_call == null && async_calls != null) {
|
||||||
for(let c of async_calls) {
|
for(i = 0; i < async_calls.length; i++) {
|
||||||
c.fn.apply(c.context, c.args)
|
const c = async_calls[i]
|
||||||
|
try {
|
||||||
|
c.fn.apply(c.context, c.args)
|
||||||
|
} catch(e) {
|
||||||
|
// do nothing. Exception was caught and recorded inside 'trace'
|
||||||
|
}
|
||||||
if(found_call != null) {
|
if(found_call != null) {
|
||||||
|
is_found_async_call = true
|
||||||
|
calltree = children[0]
|
||||||
|
children = null
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_recording_async_calls = true
|
||||||
|
|
||||||
searched_location = null
|
searched_location = null
|
||||||
const call = found_call
|
const call = found_call
|
||||||
found_call = null
|
found_call = null
|
||||||
return {modules, calltree, call}
|
return {
|
||||||
|
is_found_async_call,
|
||||||
|
async_call_index: i,
|
||||||
|
calltree,
|
||||||
|
call
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const trace = (fn, name, argscount, __location, get_closure) => {
|
const trace = (fn, name, argscount, __location, get_closure) => {
|
||||||
@@ -563,8 +584,15 @@ export const eval_modules = (
|
|||||||
return assign_code(parse_result.modules, expanded)
|
return assign_code(parse_result.modules, expanded)
|
||||||
},
|
},
|
||||||
find_call: (loc, async_calls) => {
|
find_call: (loc, async_calls) => {
|
||||||
const {modules, calltree, call} = actions.find_call(loc, async_calls)
|
const {
|
||||||
|
is_found_async_call,
|
||||||
|
async_call_index,
|
||||||
|
calltree,
|
||||||
|
call
|
||||||
|
} = actions.find_call(loc, async_calls)
|
||||||
return {
|
return {
|
||||||
|
is_found_async_call,
|
||||||
|
async_call_index,
|
||||||
calltree: assign_code(parse_result.modules, calltree),
|
calltree: assign_code(parse_result.modules, calltree),
|
||||||
// TODO: `call` does not have `code` property here. Currently it is
|
// TODO: `call` does not have `code` property here. Currently it is
|
||||||
// worked around by callers. Refactor
|
// worked around by callers. Refactor
|
||||||
|
|||||||
152
test/test.js
152
test/test.js
@@ -2313,16 +2313,13 @@ const y = x()`
|
|||||||
|
|
||||||
test('async calls', () => {
|
test('async calls', () => {
|
||||||
const code = `
|
const code = `
|
||||||
const fn = () => {
|
export const fn = () => {
|
||||||
fn2()
|
fn2()
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn2 = () => {
|
const fn2 = () => {
|
||||||
console.log(1)
|
console.log(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Function constructor to exec impure code for testing
|
|
||||||
new Function('fn', 'globalThis.__run_async_call = fn')(fn)
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const {get_async_call, on_async_call} = (new Function(`
|
const {get_async_call, on_async_call} = (new Function(`
|
||||||
@@ -2338,7 +2335,10 @@ const y = x()`
|
|||||||
`))()
|
`))()
|
||||||
|
|
||||||
const i = test_initial_state(code, { on_async_call })
|
const i = test_initial_state(code, { on_async_call })
|
||||||
globalThis.__run_async_call(10)
|
|
||||||
|
// Make async call
|
||||||
|
i.modules[''].fn(10)
|
||||||
|
|
||||||
const call = get_async_call()
|
const call = get_async_call()
|
||||||
assert_equal(call.fn.name, 'fn')
|
assert_equal(call.fn.name, 'fn')
|
||||||
assert_equal(call.code.index, code.indexOf('() => {'))
|
assert_equal(call.code.index, code.indexOf('() => {'))
|
||||||
@@ -2360,20 +2360,15 @@ const y = x()`
|
|||||||
assert_equal(nav2.state.current_calltree_node.fn.name, 'fn2')
|
assert_equal(nav2.state.current_calltree_node.fn.name, 'fn2')
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// TODO
|
|
||||||
/*
|
|
||||||
test('async calls calltree nav', () => {
|
test('async calls calltree nav', () => {
|
||||||
const code = `
|
const code = `
|
||||||
const fn = () => {
|
const normal_call = () => {
|
||||||
fn2()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn2 = () => {
|
normal_call(0)
|
||||||
console.log(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use Function constructor to exec impure code for testing
|
export const async_call = () => {
|
||||||
new Function('fn', 'globalThis.__run_async_call = fn')(fn)
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const {get_async_call, on_async_call} = (new Function(`
|
const {get_async_call, on_async_call} = (new Function(`
|
||||||
@@ -2389,41 +2384,76 @@ const y = x()`
|
|||||||
`))()
|
`))()
|
||||||
|
|
||||||
const i = test_initial_state(code, { on_async_call })
|
const i = test_initial_state(code, { on_async_call })
|
||||||
globalThis.__run_async_call(10)
|
|
||||||
const call = get_async_call()
|
|
||||||
assert_equal(call.fn.name, 'fn')
|
|
||||||
assert_equal(call.code.index, code.indexOf('() => {'))
|
|
||||||
assert_equal(call.args, [10])
|
|
||||||
const state = COMMANDS.on_async_call(i, call)
|
|
||||||
assert_equal(get_async_calls(state), [call])
|
|
||||||
|
|
||||||
assert_equal(state.logs.logs.length, 1)
|
const after_async_calls = [1, 2, 3].reduce(
|
||||||
|
(s, a) => {
|
||||||
|
// Make async calls
|
||||||
|
i.modules[''].async_call(a)
|
||||||
|
const call = get_async_call()
|
||||||
|
return COMMANDS.on_async_call(s, call)
|
||||||
|
},
|
||||||
|
i
|
||||||
|
)
|
||||||
|
|
||||||
// Expand call
|
assert_equal(
|
||||||
const {state: expanded} = COMMANDS.calltree.click(state, call.id)
|
get_async_calls(after_async_calls).map(c => c.args[0]),
|
||||||
assert_equal(get_async_calls(expanded)[0].children[0].fn.name, 'fn2')
|
[1,2,3]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_equal(after_async_calls.current_calltree_node.toplevel, true)
|
||||||
|
|
||||||
|
const down = COMMANDS.calltree.arrow_down(after_async_calls).state
|
||||||
|
|
||||||
|
const first_async_call_selected = COMMANDS.calltree.arrow_down(
|
||||||
|
COMMANDS.calltree.arrow_down(after_async_calls).state
|
||||||
|
).state
|
||||||
|
|
||||||
|
// After we press arrow down, first async call gets selected
|
||||||
|
assert_equal(
|
||||||
|
first_async_call_selected.current_calltree_node.args[0],
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
|
||||||
|
// One more arrow down, second async call gets selected
|
||||||
|
assert_equal(
|
||||||
|
COMMANDS.calltree.arrow_down(first_async_call_selected)
|
||||||
|
.state
|
||||||
|
.current_calltree_node
|
||||||
|
.args[0],
|
||||||
|
2
|
||||||
|
)
|
||||||
|
|
||||||
|
// After we press arrow up when first async call selected, we select last
|
||||||
|
// visible non async call
|
||||||
|
assert_equal(
|
||||||
|
COMMANDS.calltree.arrow_up(first_async_call_selected)
|
||||||
|
.state
|
||||||
|
.current_calltree_node
|
||||||
|
.args[0],
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
// After we press arrow left when first async call selected, we stay on
|
||||||
|
// this call
|
||||||
|
assert_equal(
|
||||||
|
COMMANDS.calltree.arrow_left(first_async_call_selected)
|
||||||
|
.current_calltree_node
|
||||||
|
.args[0],
|
||||||
|
1
|
||||||
|
)
|
||||||
|
|
||||||
// Navigate logs
|
|
||||||
const nav = COMMANDS.calltree.navigate_logs_position(expanded, 0)
|
|
||||||
assert_equal(nav.state.current_calltree_node.is_log, true)
|
|
||||||
|
|
||||||
const nav2 = COMMANDS.calltree.arrow_left(nav.state)
|
|
||||||
assert_equal(nav2.state.current_calltree_node.fn.name, 'fn2')
|
|
||||||
}),
|
}),
|
||||||
*/
|
|
||||||
|
|
||||||
test_only('async_calls find_call', () => {
|
test('async_calls find_call', () => {
|
||||||
const code = `
|
const code = `
|
||||||
const fn = () => {
|
export const fn = () => {
|
||||||
fn2()
|
fn2()
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn2 = () => {
|
const fn2 = () => {
|
||||||
console.log(1)
|
console.log(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Function constructor to exec impure code for testing
|
|
||||||
new Function('fn', 'globalThis.__run_async_call = fn')(fn)
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const {get_async_call, on_async_call} = (new Function(`
|
const {get_async_call, on_async_call} = (new Function(`
|
||||||
@@ -2439,12 +2469,58 @@ const y = x()`
|
|||||||
`))()
|
`))()
|
||||||
|
|
||||||
const i = test_initial_state(code, { on_async_call })
|
const i = test_initial_state(code, { on_async_call })
|
||||||
globalThis.__run_async_call(10)
|
|
||||||
|
// Make async call
|
||||||
|
i.modules[''].fn()
|
||||||
|
|
||||||
const call = get_async_call()
|
const call = get_async_call()
|
||||||
const state = COMMANDS.on_async_call(i, call)
|
const state = COMMANDS.on_async_call(i, call)
|
||||||
|
|
||||||
const {state: moved} = COMMANDS.move_cursor(state, code.indexOf('fn2'))
|
const {state: moved} = COMMANDS.move_cursor(state, code.indexOf('fn2'))
|
||||||
console.log('active_calltree_node', moved.active_calltree_node)
|
assert_equal(moved.active_calltree_node.fn.name, 'fn')
|
||||||
|
|
||||||
|
// Move cursor to toplevel and back, find cached (calltree_node_by_loc) call
|
||||||
|
const move_back = COMMANDS.move_cursor(
|
||||||
|
COMMANDS.move_cursor(moved, 0).state,
|
||||||
|
code.indexOf('fn2')
|
||||||
|
).state
|
||||||
|
|
||||||
|
assert_equal(move_back.active_calltree_node.fn.name, 'fn')
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
test('async_calls find_call then async_call bug', () => {
|
||||||
|
const code = `
|
||||||
|
export const fn = () => { /* label */ }
|
||||||
|
`
|
||||||
|
|
||||||
|
const {get_async_call, on_async_call} = (new Function(`
|
||||||
|
let call
|
||||||
|
return {
|
||||||
|
get_async_call() {
|
||||||
|
return call
|
||||||
|
},
|
||||||
|
on_async_call(_call) {
|
||||||
|
call = _call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`))()
|
||||||
|
|
||||||
|
const i = test_initial_state(code, { on_async_call })
|
||||||
|
|
||||||
|
// Make async call
|
||||||
|
i.modules[''].fn(1)
|
||||||
|
|
||||||
|
const state = COMMANDS.on_async_call(i, get_async_call())
|
||||||
|
|
||||||
|
// find call
|
||||||
|
const {state: moved} = COMMANDS.move_cursor(state, code.indexOf('label'))
|
||||||
|
|
||||||
|
// Make async call
|
||||||
|
i.modules[''].fn(2)
|
||||||
|
|
||||||
|
const result = COMMANDS.on_async_call(moved, get_async_call())
|
||||||
|
|
||||||
|
// there was a bug throwing error when added second async call
|
||||||
|
assert_equal(get_async_calls(result).map(c => c.args), [[1], [2]])
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user