use std::fmt::Write as _;
use crate::debug::{
DebugFilters, FocusPlan, ProtoSummaryRow, build_proto_nodes, compute_focus_plan,
format_proto_summary_row,
};
use crate::parser::{DecodedText, Endianness, Origin, RawLiteralConst, RawProto, RawString, Span};
#[derive(Debug, Clone, Copy)]
pub(crate) struct ParserProtoEntry<'a> {
pub id: usize,
pub parent: Option<usize>,
pub depth: usize,
pub proto: &'a RawProto,
}
pub(crate) fn collect_parser_proto_entries(root: &RawProto) -> Vec<ParserProtoEntry<'_>> {
let mut entries = Vec::new();
collect_parser_proto_entries_inner(root, None, 0, &mut entries);
entries
}
fn collect_parser_proto_entries_inner<'a>(
proto: &'a RawProto,
parent: Option<usize>,
depth: usize,
entries: &mut Vec<ParserProtoEntry<'a>>,
) {
let id = entries.len();
entries.push(ParserProtoEntry {
id,
parent,
depth,
proto,
});
for child in &proto.common.children {
collect_parser_proto_entries_inner(child, Some(id), depth + 1, entries);
}
}
pub(crate) fn plan_parser_focus(
entries: &[ParserProtoEntry<'_>],
filters: &DebugFilters,
) -> FocusPlan {
let parents: Vec<Option<usize>> = entries.iter().map(|entry| entry.parent).collect();
let nodes = build_proto_nodes(&parents);
compute_focus_plan(&nodes, &filters.as_focus_request())
}
pub(crate) fn build_parser_summary_row(entry: &ParserProtoEntry<'_>) -> ProtoSummaryRow {
ProtoSummaryRow {
id: entry.id,
depth_below_focus: entry.depth,
name: None,
first: None,
lines: Some((
entry.proto.common.line_range.defined_start,
entry.proto.common.line_range.defined_end,
)),
instrs: Some(entry.proto.common.instructions.len()),
children: Some(entry.proto.common.children.len()),
}
}
pub(crate) fn write_elided_summary(
output: &mut String,
indent: &str,
entry: &ParserProtoEntry<'_>,
) {
let _ = writeln!(
output,
"{indent}{}",
format_proto_summary_row(&build_parser_summary_row(entry)),
);
}
pub(crate) fn format_optional_source(source: Option<&RawString>) -> String {
source.map_or_else(|| "-".to_owned(), format_raw_string)
}
pub(crate) fn format_raw_string(raw: &RawString) -> String {
match raw.text.as_ref() {
Some(DecodedText { value, .. }) => format!("{value:?}"),
None => format!("<{} bytes>", raw.bytes.len()),
}
}
pub(crate) fn format_literal(literal: &RawLiteralConst) -> String {
match literal {
RawLiteralConst::Nil => "nil".to_owned(),
RawLiteralConst::Boolean(value) => format!("bool({value})"),
RawLiteralConst::Integer(value) => format!("int({value})"),
RawLiteralConst::Number(value) => format!("num({value})"),
RawLiteralConst::String(value) => format!("str({})", format_raw_string(value)),
RawLiteralConst::Int64(value) => format!("i64({value})"),
RawLiteralConst::UInt64(value) => format!("u64({value})"),
RawLiteralConst::Complex { real, imag } => format!("complex({real},{imag})"),
}
}
pub(crate) fn format_origin(origin: Origin) -> String {
let Span { offset, size } = origin.span;
let end = offset + size;
let raw = format_optional_raw_word(origin.raw_word);
format!("[{offset}..{end} raw={raw}]")
}
pub(crate) fn format_optional_raw_word(raw_word: Option<u64>) -> String {
raw_word.map_or_else(|| "-".to_owned(), |word| format!("0x{word:08x}"))
}
pub(crate) fn format_optional_u32(value: Option<u32>) -> String {
value.map_or_else(|| "-".to_owned(), |value| value.to_string())
}
pub(crate) fn format_optional_line(line: Option<&u32>) -> String {
line.map_or_else(|| "-".to_owned(), |line| line.to_string())
}
pub(crate) fn format_endianness(endianness: Endianness) -> &'static str {
match endianness {
Endianness::Little => "little",
Endianness::Big => "big",
}
}