mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 21:14:28 -08:00
refactor calltree finished
This commit is contained in:
@@ -4,18 +4,13 @@ import {find_node, find_leaf, ancestry_inc} from './ast_utils.js'
|
|||||||
import {color} from './color.js'
|
import {color} from './color.js'
|
||||||
import {eval_frame} from './eval.js'
|
import {eval_frame} from './eval.js'
|
||||||
|
|
||||||
export const pp_calltree = calltree => stringify(map_object(
|
export const pp_calltree = tree => ({
|
||||||
calltree,
|
|
||||||
(module, {exports, calls}) => do_pp_calltree(calls)
|
|
||||||
))
|
|
||||||
|
|
||||||
export const do_pp_calltree = tree => ({
|
|
||||||
id: tree.id,
|
id: tree.id,
|
||||||
ok: tree.ok,
|
ok: tree.ok,
|
||||||
is_log: tree.is_log,
|
is_log: tree.is_log,
|
||||||
has_more_children: tree.has_more_children,
|
has_more_children: tree.has_more_children,
|
||||||
string: tree.code?.string,
|
string: tree.code?.string,
|
||||||
children: tree.children && tree.children.map(do_pp_calltree)
|
children: tree.children && tree.children.map(pp_calltree)
|
||||||
})
|
})
|
||||||
|
|
||||||
const find_calltree_node = (state, id) => {
|
const find_calltree_node = (state, id) => {
|
||||||
@@ -45,8 +40,8 @@ export const root_calltree_node = state =>
|
|||||||
// Returns calltree node for toplevel
|
// Returns calltree node for toplevel
|
||||||
// It is either toplevel for entrypoint module, or for module that throw
|
// It is either toplevel for entrypoint module, or for module that throw
|
||||||
// error and prevent entrypoint module from executing.
|
// error and prevent entrypoint module from executing.
|
||||||
// state.calltree[1] is async calls
|
// state.calltree.children[1] is async calls
|
||||||
state.calltree[0]
|
state.calltree.children[0]
|
||||||
|
|
||||||
export const root_calltree_module = state =>
|
export const root_calltree_module = state =>
|
||||||
root_calltree_node(state).module
|
root_calltree_node(state).module
|
||||||
@@ -484,23 +479,9 @@ After find_call, we have two calltrees that have common subtree (starting from
|
|||||||
root node). Nodes in these subtrees are the same, but have different ids. Copy
|
root node). Nodes in these subtrees are the same, but have different ids. Copy
|
||||||
nodes that are in the second tree that are not in the first tree
|
nodes that are in the second tree that are not in the first tree
|
||||||
*/
|
*/
|
||||||
const merge_calltrees = (prev, next) => {
|
const merge_calltrees = (a, b) => do_merge_calltrees(a, b)[1]
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(prev).map(([module, {is_external, exports, calls}]) =>
|
|
||||||
[
|
|
||||||
module,
|
|
||||||
is_external
|
|
||||||
? {is_external, exports}
|
|
||||||
: {
|
|
||||||
exports,
|
|
||||||
calls: merge_calltree_nodes(calls, next[module].calls)[1]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const merge_calltree_nodes = (a, b) => {
|
const do_merge_calltrees = (a, b) => {
|
||||||
// TODO Quick workaround, should be fixed by not saving stack in eval.js in
|
// TODO Quick workaround, should be fixed by not saving stack in eval.js in
|
||||||
// case of stackoverflow
|
// case of stackoverflow
|
||||||
if(!a.ok && is_stackoverflow(a)) {
|
if(!a.ok && is_stackoverflow(a)) {
|
||||||
@@ -526,7 +507,7 @@ const merge_calltree_nodes = (a, b) => {
|
|||||||
|
|
||||||
const [has_update, children] = map_accum(
|
const [has_update, children] = map_accum(
|
||||||
(has_update, c, i) => {
|
(has_update, c, i) => {
|
||||||
const [upd, merged] = merge_calltree_nodes(c, b.children[i])
|
const [upd, merged] = do_merge_calltrees(c, b.children[i])
|
||||||
return [has_update || upd, merged]
|
return [has_update || upd, merged]
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@@ -545,13 +526,6 @@ const merge_calltree_nodes = (a, b) => {
|
|||||||
in calltree `b`. Null if not found
|
in calltree `b`. Null if not found
|
||||||
*/
|
*/
|
||||||
const find_same_node = (a, b, id) => {
|
const find_same_node = (a, b, id) => {
|
||||||
return map_find(
|
|
||||||
Object.entries(a),
|
|
||||||
([module, {calls}]) => do_find_same_node(calls, b[module].calls, id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const do_find_same_node = (a, b, id) => {
|
|
||||||
if(b == null) {
|
if(b == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -566,7 +540,7 @@ const do_find_same_node = (a, b, id) => {
|
|||||||
|
|
||||||
return map_find(
|
return map_find(
|
||||||
a.children,
|
a.children,
|
||||||
(c, i) => do_find_same_node(c, b.children[i], id)
|
(c, i) => find_same_node(c, b.children[i], id)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,8 +669,18 @@ export const find_call = (state, index) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const merged = merge_calltrees(state.calltree, calltree)
|
const merged = {
|
||||||
const active_calltree_node = find_same_node(merged, calltree, call.id)
|
children: [
|
||||||
|
merge_calltrees(root_calltree_node(state), calltree),
|
||||||
|
state.calltree.children[1],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const active_calltree_node = find_same_node(
|
||||||
|
merged.children[0],
|
||||||
|
calltree,
|
||||||
|
call.id
|
||||||
|
)
|
||||||
|
|
||||||
return add_frame(
|
return add_frame(
|
||||||
expand_path(
|
expand_path(
|
||||||
|
|||||||
@@ -33,13 +33,11 @@ const collect_logs = call =>
|
|||||||
const apply_eval_result = (state, eval_result) => {
|
const apply_eval_result = (state, eval_result) => {
|
||||||
// TODO what if console.log called from native fn (like Array::map)?
|
// TODO what if console.log called from native fn (like Array::map)?
|
||||||
// Currently it is not recorded. Maybe we should monkey patch `console`?
|
// Currently it is not recorded. Maybe we should monkey patch `console`?
|
||||||
const logs = collect_logs(
|
const logs = collect_logs(eval_result.calltree)
|
||||||
root_calltree_node({...state, calltree: eval_result.calltree})
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
calltree: eval_result.calltree,
|
calltree: {children: [eval_result.calltree]},
|
||||||
calltree_actions: eval_result.calltree_actions,
|
calltree_actions: eval_result.calltree_actions,
|
||||||
logs: {logs, log_position: null},
|
logs: {logs, log_position: null},
|
||||||
modules: eval_result.modules,
|
modules: eval_result.modules,
|
||||||
|
|||||||
13
src/eval.js
13
src/eval.js
@@ -271,6 +271,8 @@ export const eval_modules = (
|
|||||||
|
|
||||||
let call_counter = 0
|
let call_counter = 0
|
||||||
|
|
||||||
|
let current_module
|
||||||
|
|
||||||
let searched_location
|
let searched_location
|
||||||
let found_call
|
let found_call
|
||||||
|
|
||||||
@@ -490,7 +492,7 @@ export const eval_modules = (
|
|||||||
parse_result.sorted
|
parse_result.sorted
|
||||||
.map((m, i) =>
|
.map((m, i) =>
|
||||||
`
|
`
|
||||||
const current_module = '${m}'
|
current_module = '${m}'
|
||||||
found_call = null
|
found_call = null
|
||||||
children = null
|
children = null
|
||||||
current_call = {
|
current_call = {
|
||||||
@@ -523,7 +525,7 @@ export const eval_modules = (
|
|||||||
`
|
`
|
||||||
is_recording_async_calls = true
|
is_recording_async_calls = true
|
||||||
children = null
|
children = null
|
||||||
return { modules: __modules, call: calltree: current_call }
|
return { modules: __modules, calltree: current_call }
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -541,10 +543,7 @@ export const eval_modules = (
|
|||||||
/* external_imports */
|
/* external_imports */
|
||||||
external_imports == null
|
external_imports == null
|
||||||
? null
|
? null
|
||||||
: map_object(external_imports, (name, {module}) =>
|
: map_object(external_imports, (name, {module}) => module),
|
||||||
({exports: module, is_external: true})
|
|
||||||
)
|
|
||||||
,
|
|
||||||
|
|
||||||
/* on_async_call */
|
/* on_async_call */
|
||||||
call => on_async_call(assign_code(parse_result.modules, call))
|
call => on_async_call(assign_code(parse_result.modules, call))
|
||||||
@@ -599,7 +598,7 @@ const assign_code = (modules, call) => {
|
|||||||
export const eval_tree = node => {
|
export const eval_tree = node => {
|
||||||
return eval_modules(
|
return eval_modules(
|
||||||
{
|
{
|
||||||
modules: {'': node}},
|
modules: {'': node},
|
||||||
sorted: ['']
|
sorted: ['']
|
||||||
}
|
}
|
||||||
).calltree
|
).calltree
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {find_leaf, ancestry, find_node} from '../src/ast_utils.js'
|
|||||||
import {parse, print_debug_node} from '../src/parse_js.js'
|
import {parse, print_debug_node} from '../src/parse_js.js'
|
||||||
import {eval_tree, eval_frame, eval_modules} from '../src/eval.js'
|
import {eval_tree, eval_frame, eval_modules} from '../src/eval.js'
|
||||||
import {COMMANDS, get_initial_state} from '../src/cmd.js'
|
import {COMMANDS, get_initial_state} from '../src/cmd.js'
|
||||||
import {root_calltree_node, active_frame, pp_calltree, do_pp_calltree}
|
import {root_calltree_node, active_frame, pp_calltree}
|
||||||
from '../src/calltree.js'
|
from '../src/calltree.js'
|
||||||
import {color_file} from '../src/color.js'
|
import {color_file} from '../src/color.js'
|
||||||
import {
|
import {
|
||||||
@@ -2172,7 +2172,7 @@ const y = x()`
|
|||||||
assert_equal(s3.current_calltree_node.code.index, code.indexOf('() =>'))
|
assert_equal(s3.current_calltree_node.code.index, code.indexOf('() =>'))
|
||||||
// Check that node for `y` call was reused
|
// Check that node for `y` call was reused
|
||||||
assert_equal(
|
assert_equal(
|
||||||
find_node(s2.calltree[''].calls, n => n == s3.current_calltree_node)
|
find_node(root_calltree_node(s2), n => n == s3.current_calltree_node)
|
||||||
== null,
|
== null,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user