refactor calltree WIP

This commit is contained in:
Dmitry Vasilev
2022-11-15 20:53:16 +08:00
parent a81dbe74a2
commit ed2ce2b28b
4 changed files with 32 additions and 38 deletions

View File

@@ -41,17 +41,15 @@ export const calltree_node_loc = node => node.toplevel
? {module: node.module}
: node.fn.__location
// Finds the last module that was evaluated. If all modules evaluated without
// problems, then it is the entrypoint module. Else it is the module that
// throws error
export const root_calltree_module = state =>
findLast(
state.parse_result.sorted,
module => state.calltree[module] != null
)
export const root_calltree_node = state =>
state.calltree[root_calltree_module(state)].calls
// Returns calltree node for toplevel
// It is either toplevel for entrypoint module, or for module that throw
// error and prevent entrypoint module from executing.
// state.calltree[1] is async calls
state.calltree[0]
export const root_calltree_module = state =>
root_calltree_node(state).module
export const is_native_fn = calltree_node =>
!calltree_node.toplevel && calltree_node.fn.__location == null
@@ -109,7 +107,7 @@ export const add_frame = (
) => {
let with_frame
if(state.frames?.[active_calltree_node.id] == null) {
const frame = eval_frame(active_calltree_node, state.calltree)
const frame = eval_frame(active_calltree_node, state.modules)
const coloring = color(frame)
with_frame = {...state,
frames: {...state.frames,
@@ -162,16 +160,13 @@ const replace_calltree_node = (root, node, replacement) => {
return result
}
// TODO remove, after refactoring async_calls
const replace_calltree_node_in_state = (state, node, replacement) => {
const root = root_calltree_module(state)
// Update calltree, replacing node with expanded node
const {exports, calls} = state.calltree[root]
const replaced = replace_calltree_node(
{
children: [
calls,
root_calltree_node(state),
{children: state.async_calls},
]
},
@@ -179,13 +174,10 @@ const replace_calltree_node_in_state = (state, node, replacement) => {
replacement
)
const calltree = {...state.calltree,
[root]: {
exports,
calls: replaced.children[0],
}
return {...state,
calltree: {children: [replaced.children[0]]},
async_calls: replaced.children[1].children,
}
return {...state, calltree, async_calls: replaced.children[1].children}
}
const expand_calltree_node = (state, node) => {
@@ -257,7 +249,7 @@ const jump_calltree_node = (_state, _current_calltree_node) => {
const loc = show_body
? calltree_node_loc(next.active_calltree_node)
: find_callsite(next.calltree, active_calltree_node, current_calltree_node)
: find_callsite(next.modules, active_calltree_node, current_calltree_node)
return {
state: {...next, current_module: loc.module},
@@ -452,8 +444,8 @@ const arrow_right = state => {
}
}
const find_callsite = (calltree, parent, node) => {
const frame = eval_frame(parent, calltree)
const find_callsite = (modules, parent, node) => {
const frame = eval_frame(parent, modules)
const result = find_node(frame, n => n.result?.call == node)
return {module: calltree_node_loc(parent).module, index: result.index}
}

View File

@@ -42,6 +42,7 @@ const apply_eval_result = (state, eval_result) => {
calltree: eval_result.calltree,
calltree_actions: eval_result.calltree_actions,
logs: {logs, log_position: null},
modules: eval_result.modules,
}
}
@@ -69,6 +70,7 @@ const run_code = (s, index, dirty_files) => {
...s,
parse_result,
calltree: null,
modules: null,
async_calls: null,
// Shows that calltree is brand new and requires entire rerender

View File

@@ -31,7 +31,7 @@ that records invocation. So its call will be recorded.
Note that it is not enough to record all invocation at call site, because
hosted function can be called by native functions (for example Array::map).
For each invocation, we can replay function body with metacirculat interpreter,
For each invocation, we can replay function body with metacircular interpreter,
collecting information for editor
*/
@@ -602,7 +602,7 @@ export const eval_tree = node => {
modules: {'': node}},
sorted: ['']
}
).calltree[''].calls
).calltree
}
@@ -998,7 +998,7 @@ const apply_assignments = (do_node, assignments) => {
}
const eval_statement = (s, scope, calls, calltree) => {
const eval_statement = (s, scope, calls, modules) => {
if(s.type == 'do') {
const node = s
const {ok, assignments, returned, stmts, calls: nextcalls} = node.stmts.reduce(
@@ -1013,7 +1013,7 @@ const eval_statement = (s, scope, calls, calltree) => {
assignments: next_assignments,
scope: nextscope,
calls: next_calls,
} = eval_statement(s, scope, calls, calltree)
} = eval_statement(s, scope, calls, modules)
return {
ok,
returned,
@@ -1137,7 +1137,7 @@ const eval_statement = (s, scope, calls, calltree) => {
} else if(s.type == 'import') {
const children = s.imports.map(i => (
{...i,
result: {ok: true, value: calltree[s.full_import_path].exports[i.value]}
result: {ok: true, value: modules[s.full_import_path][i.value]}
}
))
const imported_scope = Object.fromEntries(children.map(i => [i.value, i.result.value]))
@@ -1262,7 +1262,7 @@ const eval_statement = (s, scope, calls, calltree) => {
}
}
export const eval_frame = (calltree_node, calltree) => {
export const eval_frame = (calltree_node, modules) => {
if(calltree_node.has_more_children) {
throw new Error('illegal state')
}
@@ -1272,7 +1272,7 @@ export const eval_frame = (calltree_node, calltree) => {
node,
{},
calltree_node.children,
calltree,
modules,
).node
} else {
// TODO default values for destructuring can be function calls

View File

@@ -633,8 +633,8 @@ export const tests = [
'b' : 'import {a} from "a"; export const b = a*2;',
}
)
const calltree = eval_modules(parsed).calltree;
const frame = eval_frame(calltree.b.calls, calltree)
const {calltree, modules} = eval_modules(parsed);
const frame = eval_frame(calltree, modules)
assert_equal(frame.children[1].result, {ok: true})
assert_equal(frame.children[1].children[0].children[1].result, {ok: true, value: 2})
}),
@@ -757,8 +757,8 @@ export const tests = [
}
)
assert_equal(parsed.sorted, ['a', 'b', 'c1', 'c2', 'd'])
const result = eval_modules(parsed).calltree;
assert_equal(result.d.exports.d, 8)
const modules = eval_modules(parsed).modules;
assert_equal(modules.d.d, 8)
}),
test('module loaded just once', () => {
@@ -779,10 +779,10 @@ export const tests = [
'leaf' : 'export const leaf = {}',
}
)
const mods = eval_modules(parsed).calltree
const mods = eval_modules(parsed).modules
// Check that the same symbol improted through different paths gives the
// same result
assert_equal(mods.root.exports.is_eq, true)
assert_equal(mods.root.is_eq, true)
}),
test('bug parser pragma external', () => {