mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 21:14:28 -08:00
find_call eagerly
This commit is contained in:
111
src/calltree.js
111
src/calltree.js
@@ -2,7 +2,7 @@ import {map_accum, map_find, map_object, stringify, findLast} from './utils.js'
|
||||
import {is_eq, find_error_origin_node} from './ast_utils.js'
|
||||
import {find_node, find_leaf, ancestry_inc} from './ast_utils.js'
|
||||
import {color} from './color.js'
|
||||
import {eval_frame, eval_expand_calltree_node, eval_find_call} from './eval.js'
|
||||
import {eval_frame, eval_expand_calltree_node} from './eval.js'
|
||||
|
||||
export const pp_calltree = tree => ({
|
||||
id: tree.id,
|
||||
@@ -82,8 +82,17 @@ export const is_native_fn = calltree_node =>
|
||||
export const active_frame = state =>
|
||||
state.frames[state.active_calltree_node.id]
|
||||
|
||||
const get_calltree_node_by_loc = (state, node) =>
|
||||
state.calltree_node_by_loc
|
||||
export const get_calltree_node_by_loc = (state, index) => {
|
||||
const nodes_of_module = state.calltree_node_by_loc.get(state.current_module)
|
||||
if(nodes_of_module == null) {
|
||||
return null
|
||||
} else {
|
||||
return nodes_of_module.get(index)
|
||||
}
|
||||
}
|
||||
|
||||
const get_selected_calltree_node_by_loc = (state, node) =>
|
||||
state.selected_calltree_node_by_loc
|
||||
?.[state.current_module]
|
||||
?.[
|
||||
state.parse_result.modules[state.current_module] == node
|
||||
@@ -93,13 +102,13 @@ const get_calltree_node_by_loc = (state, node) =>
|
||||
: node.index
|
||||
]
|
||||
|
||||
const add_calltree_node_by_loc = (state, loc, node_id) => {
|
||||
const add_selected_calltree_node_by_loc = (state, loc, node_id) => {
|
||||
return {
|
||||
...state,
|
||||
calltree_node_by_loc:
|
||||
{...state.calltree_node_by_loc,
|
||||
selected_calltree_node_by_loc:
|
||||
{...state.selected_calltree_node_by_loc,
|
||||
[loc.module]: {
|
||||
...state.calltree_node_by_loc?.[loc.module],
|
||||
...state.selected_calltree_node_by_loc?.[loc.module],
|
||||
[loc.index ?? -1]: node_id
|
||||
}
|
||||
}
|
||||
@@ -111,18 +120,11 @@ export const set_active_calltree_node = (
|
||||
active_calltree_node,
|
||||
current_calltree_node = state.current_calltree_node,
|
||||
) => {
|
||||
const result = {
|
||||
return {
|
||||
...state,
|
||||
active_calltree_node,
|
||||
current_calltree_node,
|
||||
}
|
||||
// TODO currently commented, required to implement livecoding second and
|
||||
// subsequent fn calls
|
||||
/*
|
||||
// Record last_good_state every time active_calltree_node changes
|
||||
return {...result, last_good_state: result}
|
||||
*/
|
||||
return result
|
||||
}
|
||||
|
||||
export const add_frame = (
|
||||
@@ -142,7 +144,8 @@ export const add_frame = (
|
||||
} else {
|
||||
with_frame = state
|
||||
}
|
||||
const result = add_calltree_node_by_loc(
|
||||
// TODO only add if it is not the same
|
||||
const result = add_selected_calltree_node_by_loc(
|
||||
with_frame,
|
||||
calltree_node_loc(active_calltree_node),
|
||||
active_calltree_node.id,
|
||||
@@ -571,18 +574,21 @@ export const find_call = (state, index) => {
|
||||
return state
|
||||
}
|
||||
|
||||
const ct_node_id = get_calltree_node_by_loc(state, node)
|
||||
const selected_ct_node_id = get_selected_calltree_node_by_loc(state, node)
|
||||
|
||||
if(ct_node_id === null) {
|
||||
/*
|
||||
TODO remove because it interferes with find_call deferred calls
|
||||
if(selected_ct_node_id === null) {
|
||||
// strict compare (===) with null, to check if we put null earlier to
|
||||
// designate that fn is not reachable
|
||||
return set_active_calltree_node(state, null)
|
||||
}
|
||||
*/
|
||||
|
||||
if(ct_node_id != null) {
|
||||
if(selected_ct_node_id != null) {
|
||||
const ct_node = find_node(
|
||||
state.calltree,
|
||||
n => n.id == ct_node_id
|
||||
n => n.id == selected_ct_node_id
|
||||
)
|
||||
if(ct_node == null) {
|
||||
throw new Error('illegal state')
|
||||
@@ -604,69 +610,22 @@ export const find_call = (state, index) => {
|
||||
return state
|
||||
}
|
||||
|
||||
const loc = {index: node.index, module: state.current_module}
|
||||
const ct_node_id = get_calltree_node_by_loc(state, node.index)
|
||||
|
||||
// First try to find node among existing calltree nodes
|
||||
const call = find_node(state.calltree, node =>
|
||||
true
|
||||
&& node.fn != null
|
||||
&& node.fn.__location != null
|
||||
&& node.fn.__location.index == loc.index
|
||||
&& node.fn.__location.module == loc.module
|
||||
)
|
||||
|
||||
let next_calltree, active_calltree_node
|
||||
|
||||
if(call != null) {
|
||||
if(call.has_more_children) {
|
||||
active_calltree_node = eval_expand_calltree_node(
|
||||
// TODO copy eval_cxt?
|
||||
state.eval_cxt,
|
||||
state.parse_result,
|
||||
call
|
||||
)
|
||||
next_calltree = replace_calltree_node(
|
||||
state.calltree,
|
||||
call,
|
||||
active_calltree_node
|
||||
)
|
||||
} else {
|
||||
active_calltree_node = call
|
||||
next_calltree = state.calltree
|
||||
}
|
||||
} else {
|
||||
const find_result = eval_find_call(
|
||||
// TODO copy eval_cxt?
|
||||
state.eval_cxt,
|
||||
state.parse_result,
|
||||
state.calltree,
|
||||
loc
|
||||
)
|
||||
if(find_result == null) {
|
||||
return add_calltree_node_by_loc(
|
||||
// Remove active_calltree_node
|
||||
// current_calltree_node may stay not null, because it is calltree node
|
||||
// explicitly selected by user in calltree view
|
||||
set_active_calltree_node(state, null),
|
||||
loc,
|
||||
null
|
||||
)
|
||||
if(ct_node_id == null) {
|
||||
return set_active_calltree_node(state, null)
|
||||
}
|
||||
|
||||
active_calltree_node = find_result.call
|
||||
next_calltree = replace_calltree_node(
|
||||
const ct_node = find_node(
|
||||
state.calltree,
|
||||
find_node(state.calltree, n => n.id == find_result.node.id),
|
||||
find_result.node,
|
||||
n => n.id == ct_node_id
|
||||
)
|
||||
if(ct_node == null) {
|
||||
throw new Error('illegal state')
|
||||
}
|
||||
|
||||
return add_frame(
|
||||
expand_path(
|
||||
{...state, calltree: next_calltree},
|
||||
active_calltree_node
|
||||
),
|
||||
active_calltree_node,
|
||||
expand_path(state, ct_node),
|
||||
ct_node,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
70
src/cmd.js
70
src/cmd.js
@@ -11,10 +11,10 @@ import {
|
||||
root_calltree_node, root_calltree_module, make_calltree,
|
||||
get_deferred_calls,
|
||||
calltree_commands,
|
||||
add_frame, calltree_node_loc, expand_path,
|
||||
add_frame, calltree_node_loc, get_calltree_node_by_loc, expand_path,
|
||||
initial_calltree_node, default_expand_path, toggle_expanded, active_frame,
|
||||
find_call, find_call_node, set_active_calltree_node,
|
||||
set_cursor_position, current_cursor_position, set_location
|
||||
set_cursor_position, current_cursor_position, set_location,
|
||||
} from './calltree.js'
|
||||
|
||||
const collect_logs = (logs, call) => {
|
||||
@@ -45,6 +45,8 @@ const apply_eval_result = (state, eval_result) => {
|
||||
return {
|
||||
...state,
|
||||
calltree: make_calltree(eval_result.calltree, null),
|
||||
calltree_node_by_loc: eval_result.calltree_node_by_loc,
|
||||
// TODO copy eval_cxt?
|
||||
eval_cxt: eval_result.eval_cxt,
|
||||
logs: {
|
||||
logs: collect_logs(eval_result.logs, eval_result.calltree),
|
||||
@@ -95,6 +97,7 @@ const run_code = (s, dirty_files) => {
|
||||
calltree_node_is_expanded: null,
|
||||
frames: null,
|
||||
calltree_node_by_loc: null,
|
||||
selected_calltree_node_by_loc: null,
|
||||
selection_state: null,
|
||||
loading_external_imports_state: null,
|
||||
value_explorer: null,
|
||||
@@ -185,75 +188,38 @@ const external_imports_loaded = (
|
||||
}
|
||||
}
|
||||
|
||||
const node = find_call_node(state, current_cursor_position(state))
|
||||
|
||||
let toplevel, result
|
||||
|
||||
if(
|
||||
// edit module that is not imported (maybe recursively by state.entrypoint)
|
||||
// TODO if module not imported, then do not run code on edit at all
|
||||
node == null
|
||||
||
|
||||
node.type == 'do' /* toplevel AST node */
|
||||
) {
|
||||
result = eval_modules(
|
||||
const result = eval_modules(
|
||||
state.parse_result,
|
||||
external_imports,
|
||||
state.on_deferred_call,
|
||||
state.calltree_changed_token,
|
||||
state.io_trace,
|
||||
)
|
||||
toplevel = true
|
||||
} else {
|
||||
result = eval_modules(
|
||||
state.parse_result,
|
||||
external_imports,
|
||||
state.on_deferred_call,
|
||||
state.calltree_changed_token,
|
||||
state.io_trace,
|
||||
{index: node.index, module: state.current_module},
|
||||
)
|
||||
toplevel = false
|
||||
}
|
||||
|
||||
if(result.then != null) {
|
||||
return {...state,
|
||||
eval_modules_state: {
|
||||
promise: result, node, toplevel,
|
||||
}
|
||||
eval_modules_state: { promise: result }
|
||||
}
|
||||
} else {
|
||||
return eval_modules_finished(state, state, result, node, toplevel)
|
||||
return eval_modules_finished(state, state, result)
|
||||
}
|
||||
}
|
||||
|
||||
const eval_modules_finished = (state, prev_state, result, node, toplevel) => {
|
||||
const eval_modules_finished = (state, prev_state, result) => {
|
||||
if(state.calltree_changed_token != prev_state.calltree_changed_token) {
|
||||
// code was modified after prev vesion of code was executed, discard
|
||||
return state
|
||||
}
|
||||
const next = apply_eval_result(state, result)
|
||||
|
||||
let active_calltree_node
|
||||
|
||||
if(toplevel) {
|
||||
if(node == state.parse_result.modules[root_calltree_module(next)]) {
|
||||
active_calltree_node = root_calltree_node(next)
|
||||
} else {
|
||||
active_calltree_node = null
|
||||
}
|
||||
} else {
|
||||
if(result.call == null) {
|
||||
// Unreachable call
|
||||
active_calltree_node = null
|
||||
} else {
|
||||
active_calltree_node = result.call
|
||||
}
|
||||
}
|
||||
const next = find_call(
|
||||
apply_eval_result(state, result),
|
||||
current_cursor_position(state)
|
||||
)
|
||||
|
||||
let result_state
|
||||
|
||||
if(active_calltree_node == null) {
|
||||
if(next.active_calltree_node == null) {
|
||||
const {node, state: next2} = initial_calltree_node(next)
|
||||
result_state = set_active_calltree_node(next2, null, node)
|
||||
} else {
|
||||
@@ -261,10 +227,10 @@ const eval_modules_finished = (state, prev_state, result, node, toplevel) => {
|
||||
default_expand_path(
|
||||
expand_path(
|
||||
next,
|
||||
active_calltree_node
|
||||
next.active_calltree_node
|
||||
)
|
||||
),
|
||||
active_calltree_node,
|
||||
next.active_calltree_node,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -883,7 +849,7 @@ const open_app_window = (state, globals) => {
|
||||
})
|
||||
}
|
||||
|
||||
const get_initial_state = (state, entrypoint_settings) => {
|
||||
const get_initial_state = (state, entrypoint_settings, cursor_pos = 0) => {
|
||||
const with_files = state.project_dir == null
|
||||
? state
|
||||
: load_files(state, state.project_dir)
|
||||
@@ -892,7 +858,7 @@ const get_initial_state = (state, entrypoint_settings) => {
|
||||
|
||||
return {
|
||||
...with_settings,
|
||||
cursor_position_by_file: {[with_settings.current_module]: 0},
|
||||
cursor_position_by_file: {[with_settings.current_module]: cursor_pos},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ export const color = frame => {
|
||||
|
||||
export const color_file = (state, file) =>
|
||||
Object
|
||||
.values(state.calltree_node_by_loc?.[file] ?? {})
|
||||
.values(state.selected_calltree_node_by_loc?.[file] ?? {})
|
||||
// node_id == null means it is unreachable, so do not color
|
||||
.filter(node_id => node_id != null)
|
||||
.map(node_id => state.frames[node_id].coloring)
|
||||
|
||||
4
src/effects.js
vendored
4
src/effects.js
vendored
@@ -185,8 +185,6 @@ export const apply_side_effects = (prev, next, command, ui) => {
|
||||
exec('eval_modules_finished',
|
||||
next, /* becomes prev_state */
|
||||
result,
|
||||
s.node,
|
||||
s.toplevel
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -251,7 +249,7 @@ export const apply_side_effects = (prev, next, command, ui) => {
|
||||
ui.calltree.render_select_node(prev, next)
|
||||
}
|
||||
|
||||
if(prev.calltree_node_by_loc != next.calltree_node_by_loc) {
|
||||
if(prev.selected_calltree_node_by_loc != next.selected_calltree_node_by_loc) {
|
||||
render_coloring(ui, next)
|
||||
}
|
||||
|
||||
|
||||
23
src/eval.js
23
src/eval.js
@@ -17,7 +17,7 @@ import {has_toplevel_await} from './find_definitions.js'
|
||||
|
||||
// import runtime as external because it has non-functional code
|
||||
// external
|
||||
import {run, do_eval_expand_calltree_node, do_eval_find_call} from './runtime.js'
|
||||
import {run, do_eval_expand_calltree_node} from './runtime.js'
|
||||
|
||||
// TODO: fix error messages. For example, "__fn is not a function"
|
||||
|
||||
@@ -331,9 +331,6 @@ export const eval_modules = (
|
||||
// TODO use native array for stack for perf? stack contains booleans
|
||||
stack: new Array(),
|
||||
|
||||
searched_location: location,
|
||||
found_call: null,
|
||||
|
||||
is_recording_deferred_calls: false,
|
||||
on_deferred_call: (call, calltree_changed_token, logs) => {
|
||||
return on_deferred_call(
|
||||
@@ -352,15 +349,12 @@ export const eval_modules = (
|
||||
|
||||
const make_result = result => {
|
||||
const calltree = assign_code(parse_result.modules, result.calltree)
|
||||
const call = result.call == null
|
||||
? null
|
||||
: find_node(calltree, node => node.id == result.call.id)
|
||||
return {
|
||||
modules: result.modules,
|
||||
logs: result.logs,
|
||||
eval_cxt: result.eval_cxt,
|
||||
calltree,
|
||||
call,
|
||||
calltree_node_by_loc: result.eval_cxt.calltree_node_by_loc,
|
||||
io_trace: result.eval_cxt.io_trace,
|
||||
}
|
||||
}
|
||||
@@ -372,19 +366,6 @@ export const eval_modules = (
|
||||
}
|
||||
}
|
||||
|
||||
export const eval_find_call = (cxt, parse_result, calltree, location) => {
|
||||
const result = do_eval_find_call(cxt, calltree, location)
|
||||
if(result == null) {
|
||||
return null
|
||||
}
|
||||
const {node, call} = result
|
||||
const node_with_code = assign_code(parse_result.modules, node)
|
||||
const call_with_code = find_node(node_with_code, n => n.id == call.id)
|
||||
return {
|
||||
node: node_with_code,
|
||||
call: call_with_code,
|
||||
}
|
||||
}
|
||||
|
||||
export const eval_expand_calltree_node = (cxt, parse_result, node) => {
|
||||
return assign_code(
|
||||
|
||||
141
src/runtime.js
141
src/runtime.js
@@ -45,11 +45,13 @@ const do_run = function*(module_fns, cxt, io_trace){
|
||||
// TODO group all io_trace_ properties to single object?
|
||||
? {...cxt,
|
||||
logs: [],
|
||||
calltree_node_by_loc: new Map(),
|
||||
io_trace_is_recording: true,
|
||||
io_trace: [],
|
||||
}
|
||||
: {...cxt,
|
||||
logs: [],
|
||||
calltree_node_by_loc: new Map(),
|
||||
io_trace_is_recording: false,
|
||||
io_trace,
|
||||
io_trace_is_replay_aborted: false,
|
||||
@@ -63,13 +65,16 @@ const do_run = function*(module_fns, cxt, io_trace){
|
||||
apply_promise_patch(cxt)
|
||||
set_current_context(cxt)
|
||||
|
||||
for(let {module, fn} of module_fns) {
|
||||
cxt.found_call = null
|
||||
for(let i = 0; i < module_fns.length; i++) {
|
||||
const {module, fn} = module_fns[i]
|
||||
|
||||
cxt.is_entrypoint = i == module_fns.length - 1
|
||||
|
||||
cxt.children = null
|
||||
calltree = {
|
||||
toplevel: true,
|
||||
module,
|
||||
id: cxt.call_counter++
|
||||
id: ++cxt.call_counter,
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -98,14 +103,9 @@ const do_run = function*(module_fns, cxt, io_trace){
|
||||
|
||||
remove_promise_patch(cxt)
|
||||
|
||||
cxt.searched_location = null
|
||||
const call = cxt.found_call
|
||||
cxt.found_call = null
|
||||
|
||||
return {
|
||||
modules: cxt.modules,
|
||||
calltree,
|
||||
call,
|
||||
logs: _logs,
|
||||
eval_cxt: cxt,
|
||||
}
|
||||
@@ -170,23 +170,6 @@ export const set_record_call = cxt => {
|
||||
}
|
||||
}
|
||||
|
||||
const do_expand_calltree_node = (cxt, node) => {
|
||||
if(node.fn.__location != null) {
|
||||
// fn is hosted, it created call, this time with children
|
||||
const result = cxt.children[0]
|
||||
result.id = node.id
|
||||
result.children = cxt.prev_children
|
||||
result.has_more_children = false
|
||||
return result
|
||||
} else {
|
||||
// fn is native, it did not created call, only its child did
|
||||
return {...node,
|
||||
children: cxt.children,
|
||||
has_more_children: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const do_eval_expand_calltree_node = (cxt, node) => {
|
||||
cxt.is_recording_deferred_calls = false
|
||||
cxt.children = null
|
||||
@@ -199,79 +182,28 @@ export const do_eval_expand_calltree_node = (cxt, node) => {
|
||||
} catch(e) {
|
||||
// do nothing. Exception was caught and recorded inside '__trace'
|
||||
}
|
||||
|
||||
cxt.is_recording_deferred_calls = true
|
||||
const result = do_expand_calltree_node(cxt, node)
|
||||
cxt.children = null
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Try to find call of function with given 'location'
|
||||
|
||||
Function is synchronous, because we recorded calltree nodes for all async
|
||||
function calls. Here we walk over calltree, find leaves that have
|
||||
'has_more_children' set to true, and rerunning fns in these leaves with
|
||||
'searched_location' being set, until we find find call or no children
|
||||
left.
|
||||
|
||||
We dont rerun entire execution because we want find_call to be
|
||||
synchronous for simplicity
|
||||
*/
|
||||
export const do_eval_find_call = (cxt, calltree, location) => {
|
||||
// TODO always cleanup children when work finished, not before it started
|
||||
const children = cxt.children
|
||||
cxt.children = null
|
||||
|
||||
const do_find = node => {
|
||||
if(node.children != null) {
|
||||
for(let c of node.children) {
|
||||
const result = do_find(c)
|
||||
if(result != null) {
|
||||
if(node.fn.__location != null) {
|
||||
// fn is hosted, it created call, this time with children
|
||||
const result = children[0]
|
||||
result.id = node.id
|
||||
result.children = cxt.prev_children
|
||||
result.has_more_children = false
|
||||
return result
|
||||
}
|
||||
}
|
||||
// call was not find in children, return null
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
if(node.has_more_children) {
|
||||
try {
|
||||
if(node.is_new) {
|
||||
new node.fn(...node.args)
|
||||
} else {
|
||||
node.fn.apply(node.context, node.args)
|
||||
// fn is native, it did not created call, only its child did
|
||||
return {...node,
|
||||
children: children,
|
||||
has_more_children: false,
|
||||
}
|
||||
} catch(e) {
|
||||
// do nothing. Exception was caught and recorded inside '__trace'
|
||||
}
|
||||
|
||||
if(cxt.found_call != null) {
|
||||
return {
|
||||
node: do_expand_calltree_node(cxt, node),
|
||||
call: cxt.found_call,
|
||||
}
|
||||
} else {
|
||||
cxt.children = null
|
||||
}
|
||||
}
|
||||
|
||||
// node has no children, return null
|
||||
return null
|
||||
}
|
||||
|
||||
cxt.is_recording_deferred_calls = false
|
||||
cxt.searched_location = location
|
||||
|
||||
const result = do_find(calltree)
|
||||
|
||||
cxt.children = null
|
||||
cxt.searched_location = null
|
||||
cxt.found_call = null
|
||||
cxt.is_recording_deferred_calls = true
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
const __do_await = async (cxt, value) => {
|
||||
// children is an array of child calls for current function call. But it
|
||||
@@ -309,19 +241,19 @@ const __trace = (cxt, fn, name, argscount, __location, get_closure) => {
|
||||
cxt.children = null
|
||||
cxt.stack.push(false)
|
||||
|
||||
const is_found_call =
|
||||
(cxt.searched_location != null && cxt.found_call == null)
|
||||
&&
|
||||
(
|
||||
__location.index == cxt.searched_location.index
|
||||
&&
|
||||
__location.module == cxt.searched_location.module
|
||||
)
|
||||
const call_id = ++cxt.call_counter
|
||||
|
||||
if(is_found_call) {
|
||||
// Assign temporary value to prevent nested calls from populating
|
||||
// found_call
|
||||
cxt.found_call = {}
|
||||
// populate calltree_node_by_loc only for entrypoint module
|
||||
if(cxt.is_entrypoint) {
|
||||
let nodes_of_module = cxt.calltree_node_by_loc.get(__location.module)
|
||||
if(nodes_of_module == null) {
|
||||
nodes_of_module = new Map()
|
||||
cxt.calltree_node_by_loc.set(__location.module, nodes_of_module)
|
||||
}
|
||||
if(nodes_of_module.get(__location.index) == null) {
|
||||
set_record_call(cxt)
|
||||
nodes_of_module.set(__location.index, call_id)
|
||||
}
|
||||
}
|
||||
|
||||
let ok, value, error
|
||||
@@ -351,7 +283,7 @@ const __trace = (cxt, fn, name, argscount, __location, get_closure) => {
|
||||
cxt.prev_children = cxt.children
|
||||
|
||||
const call = {
|
||||
id: cxt.call_counter++,
|
||||
id: call_id,
|
||||
ok,
|
||||
value,
|
||||
error,
|
||||
@@ -362,11 +294,6 @@ const __trace = (cxt, fn, name, argscount, __location, get_closure) => {
|
||||
: args.slice(0, argscount),
|
||||
}
|
||||
|
||||
if(is_found_call) {
|
||||
cxt.found_call = call
|
||||
set_record_call(cxt)
|
||||
}
|
||||
|
||||
const should_record_call = cxt.stack.pop()
|
||||
|
||||
if(should_record_call) {
|
||||
@@ -453,7 +380,7 @@ const __trace_call = (cxt, fn, context, args, errormessage, is_new = false) => {
|
||||
cxt.prev_children = cxt.children
|
||||
|
||||
const call = {
|
||||
id: cxt.call_counter++,
|
||||
id: ++cxt.call_counter,
|
||||
ok,
|
||||
value,
|
||||
error,
|
||||
|
||||
@@ -69,8 +69,9 @@ console.time('run')
|
||||
|
||||
const i = test_initial_state(
|
||||
{}, // files
|
||||
undefined,
|
||||
{project_dir: dir},
|
||||
{entrypoint: 'test/run.js'},
|
||||
{project_dir: dir}
|
||||
)
|
||||
|
||||
assert_equal(i.loading_external_imports_state != null, true)
|
||||
|
||||
57
test/test.js
57
test/test.js
@@ -1426,7 +1426,8 @@ export const tests = [
|
||||
]
|
||||
)
|
||||
|
||||
const step_into = COMMANDS.calltree.click(initial, 1)
|
||||
const x_call = root_calltree_node(initial).children[0]
|
||||
const step_into = COMMANDS.calltree.click(initial, x_call.id)
|
||||
assert_equal(
|
||||
color_file(step_into, '').sort((a,b) => a.index - b.index),
|
||||
[
|
||||
@@ -1479,7 +1480,8 @@ export const tests = [
|
||||
|
||||
x()`
|
||||
const initial = test_initial_state(code)
|
||||
const step_into = COMMANDS.calltree.click(initial, 1)
|
||||
const x_call = root_calltree_node(initial).children[0]
|
||||
const step_into = COMMANDS.calltree.click(initial, x_call.id)
|
||||
|
||||
assert_equal(
|
||||
color_file(step_into, '').sort((c1, c2) => c1.index - c2.index),
|
||||
@@ -1563,6 +1565,20 @@ const y = x()`
|
||||
)
|
||||
}),
|
||||
|
||||
test('coloring function body after move inside', () => {
|
||||
const code = `
|
||||
const x = () => {
|
||||
1
|
||||
}
|
||||
x()
|
||||
`
|
||||
const i = test_initial_state(code)
|
||||
const moved = COMMANDS.move_cursor(i, code.indexOf('1'))
|
||||
const coloring = color_file(moved, '')
|
||||
const color_body = coloring.find(c => c.index == code.indexOf('('))
|
||||
assert_equal(color_body.result.ok, true)
|
||||
}),
|
||||
|
||||
test('better parse errors', () => {
|
||||
const code = `
|
||||
const x = z => {
|
||||
@@ -1634,7 +1650,7 @@ const y = x()`
|
||||
|
||||
assert_equal(res.result.value, 6)
|
||||
assert_equal(
|
||||
n.calltree_node_by_loc[''][edited.indexOf('foo =>')] == null,
|
||||
n.calltree_node_by_loc.get('').get(edited.indexOf('foo =>')) == null,
|
||||
false
|
||||
)
|
||||
}),
|
||||
@@ -1786,8 +1802,8 @@ const y = x()`
|
||||
countdown(10)
|
||||
`)
|
||||
const first = root_calltree_node(s).children[0]
|
||||
assert_equal(first.children, undefined)
|
||||
assert_equal(first.has_more_children, true)
|
||||
assert_equal(first.children[0].children, undefined)
|
||||
assert_equal(first.children[0].has_more_children, true)
|
||||
assert_equal(first.value, 10)
|
||||
const s2 = COMMANDS.calltree.click(s, first.id)
|
||||
const first2 = root_calltree_node(s2).children[0]
|
||||
@@ -1816,7 +1832,6 @@ const y = x()`
|
||||
test('expand_calltree_node native', () => {
|
||||
const s = test_initial_state(`[1,2,3].map(x => x + 1)`)
|
||||
const map = root_calltree_node(s).children[0]
|
||||
assert_equal(map.children, null)
|
||||
const s2 = COMMANDS.calltree.click(s, map.id)
|
||||
const map_expanded = root_calltree_node(s2).children[0]
|
||||
assert_equal(map_expanded.children.length, 3)
|
||||
@@ -1854,18 +1869,11 @@ const y = x()`
|
||||
y([1,2,3])
|
||||
`
|
||||
|
||||
const assert_loc = (s, substring, is_assert_node_by_loc) => {
|
||||
const assert_loc = (s, substring) => {
|
||||
const state = COMMANDS.calltree.arrow_right(s)
|
||||
const index = code.indexOf(substring)
|
||||
assert_equal(current_cursor_position(state), index)
|
||||
if(is_assert_node_by_loc) {
|
||||
assert_equal(
|
||||
state.calltree_node_by_loc[''][index] == null,
|
||||
false
|
||||
)
|
||||
}
|
||||
assert_equal(active_frame(state) != null, true)
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
@@ -1876,7 +1884,7 @@ const y = x()`
|
||||
const s2 = assert_loc(s1, 'y([')
|
||||
|
||||
// Expand call of `y()`
|
||||
const s3 = assert_loc(s2, 'arr =>', true)
|
||||
const s3 = assert_loc(s2, 'arr =>')
|
||||
|
||||
// Select call of arr.map
|
||||
const s4 = assert_loc(s3, 'arr.map')
|
||||
@@ -1886,8 +1894,7 @@ const y = x()`
|
||||
const s5 = assert_loc(s4, 'arr.map')
|
||||
|
||||
// Select call of x
|
||||
const s6 = assert_loc(s5, 'foo =>', true)
|
||||
|
||||
const s6 = assert_loc(s5, 'foo =>')
|
||||
}),
|
||||
|
||||
test('jump_calltree select callsite', () => {
|
||||
@@ -1918,6 +1925,14 @@ const y = x()`
|
||||
assert_equal(good.code.index, code.indexOf('() => {/*good'))
|
||||
}),
|
||||
|
||||
test('jump_calltree select another call of the same fn', () => {
|
||||
const code = '[1,2].map(x => x*10)'
|
||||
const i = test_initial_state(code, code.indexOf('10'))
|
||||
assert_equal(i.value_explorer.result.value, 10)
|
||||
const second_iter = COMMANDS.calltree.arrow_down(i)
|
||||
const moved = COMMANDS.move_cursor(second_iter, code.indexOf('x*10'))
|
||||
assert_equal(moved.value_explorer.result.value, 20)
|
||||
}),
|
||||
|
||||
test('unwind_stack', () => {
|
||||
const s = test_initial_state(`
|
||||
@@ -2079,10 +2094,6 @@ const y = x()`
|
||||
assert_equal(node.children.length, 3)
|
||||
assert_equal(node.code != null, true)
|
||||
|
||||
// Siblings are not expanded
|
||||
assert_equal(node.children[0].has_more_children, true)
|
||||
assert_equal(node.children[2].has_more_children, true)
|
||||
|
||||
return find_target(node.children[1], i + 1)
|
||||
}
|
||||
|
||||
@@ -2091,8 +2102,6 @@ const y = x()`
|
||||
assert_equal(target.args, [10])
|
||||
|
||||
const target2 = target.children[0]
|
||||
// Target is expanded, but only one level deep
|
||||
assert_equal(target2.has_more_children, true)
|
||||
}),
|
||||
|
||||
test('find_call error', () => {
|
||||
@@ -2567,6 +2576,8 @@ const y = x()`
|
||||
'' : `import {x} from 'x'; x()`,
|
||||
'x' : `export const x = () => 1; x()`,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
entrypoint: '',
|
||||
current_module: 'x',
|
||||
|
||||
@@ -102,7 +102,7 @@ export const assert_code_error_async = async (codestring, error) => {
|
||||
assert_equal(result.error, error)
|
||||
}
|
||||
|
||||
export const test_initial_state = (code, entrypoint_settings, other) => {
|
||||
export const test_initial_state = (code, cursor_pos, other, entrypoint_settings) => {
|
||||
return COMMANDS.open_app_window(
|
||||
COMMANDS.get_initial_state(
|
||||
{
|
||||
@@ -113,7 +113,8 @@ export const test_initial_state = (code, entrypoint_settings, other) => {
|
||||
entrypoint: '',
|
||||
current_module: '',
|
||||
...entrypoint_settings,
|
||||
}
|
||||
},
|
||||
cursor_pos
|
||||
),
|
||||
new Set(Object.getOwnPropertyNames(globalThis.app_window))
|
||||
)
|
||||
@@ -127,8 +128,6 @@ export const test_initial_state_async = async code => {
|
||||
s,
|
||||
s,
|
||||
result,
|
||||
s.eval_modules_state.node,
|
||||
s.eval_modules_state.toplevel
|
||||
)
|
||||
}
|
||||
|
||||
@@ -139,8 +138,6 @@ export const command_input_async = async (...args) => {
|
||||
after_input,
|
||||
after_input,
|
||||
result,
|
||||
after_input.eval_modules_state.node,
|
||||
after_input.eval_modules_state.toplevel
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user