///|
fn between_status_name(status : FunctionPathBetweenStatus) -> String {
match status {
BetweenPathFound => "found"
BetweenPathNotFound => "not-found-within-model"
}
}
///|
pub fn render_function_path_between(
report : FunctionPathBetweenReport,
) -> String {
let out = StringBuilder()
out.write_string("FUNCTION-TO-FUNCTION MODEL PATH\n\n")
out.write_string(
"Query: \{report.source.index} -> \{report.target_index}\nSource: " +
search_terminal_string(report.source.name) +
"\nInput: \{report.file_size} B; SHA-256 \{report.sha256}\nStatus: " +
between_status_name(report.status) +
"\n",
)
if !report.graph_warning.is_empty() {
out.write_string(report.graph_warning + "\n")
}
out.write_string(
"Prepared closure functions: \{report.prepared_closure_function_count} of \{report.function_count}\nUnresolved table call sites (no static candidates): \{report.unresolved_count}\n",
)
match report.status {
BetweenPathNotFound =>
out.write_string(
"No path recorded in this direction within the current model. Destination identity was not re-read or guessed.\nHops: n/a (null)\n",
)
BetweenPathFound => {
out.write_string(
"Hops: " +
(match report.hop_count {
Some(n) => n.to_string()
None => "n/a (null)"
}) +
"\n",
)
if report.path_edges.is_empty() {
out.write_string(
"Zero-step path: source and destination are the same index; this is not evidence of a nonempty cycle.\n",
)
}
out.write_string(
"\nNODES (FROM -> TO)\nINDEX IDENTITY ENCODED BYTES NAME\n",
)
for node in report.path_nodes {
let size = match node.encoded_size {
Some(n) => n.to_string()
None => "n/a (not measured)"
}
out.write_string(
"\{node.index} " +
(if node.imported { "imported" } else { "local" }) +
" " +
size +
" " +
search_terminal_string(node.name) +
"\n",
)
}
out.write_string(
"\nEDGES (original caller -> callee)\nCALLER CALLEE KIND FILE OFFSET\n",
)
for edge in report.path_edges {
let kind = match edge.kind {
Direct => "direct"
Reference => "reference taken"
Indirect => "indirect candidate"
}
out.write_string(
"\{edge.caller} \{edge.callee} " + kind + " \{edge.offset}\n",
)
}
}
}
out.write_string("\n" + report.modeling_scope + "\n")
out.to_string()
}
///|
pub fn render_function_path_between_json(
report : FunctionPathBetweenReport,
) -> String {
let root : Map[String, Json] = Map([])
root.set("format", Json::string("moonsize-function-path-between"))
root.set("schema_version", int_json(1))
root.set("source", path_node_json(report.source))
root.set("target_index", int_json(report.target_index))
root.set("file_size", int_json(report.file_size))
root.set("sha256", Json::string(report.sha256))
root.set("function_count", int_json(report.function_count))
root.set("status", Json::string(between_status_name(report.status)))
root.set("path_nodes", Json::array(report.path_nodes.map(path_node_json)))
root.set("path_edges", Json::array(report.path_edges.map(cycle_edge_json)))
root.set(
"hop_count",
match report.hop_count {
Some(n) => int_json(n)
None => Json::null()
},
)
root.set(
"prepared_closure_function_count",
int_json(report.prepared_closure_function_count),
)
root.set("graph_complete", Json::boolean(report.graph_complete))
root.set("unresolved_count", int_json(report.unresolved_count))
root.set("diagnostics", diagnostic_records_json(report.diagnostics))
root.set("graph_warning", Json::string(report.graph_warning))
root.set("modeling_scope", Json::string(report.modeling_scope))
Json::object(root).stringify(indent=2) + "\n"
}