use std::collections::HashMap;
use brink_format::{DefinitionId, Value};
use crate::program::Program;
pub struct DebugSnapshot {
pub status: &'static str,
pub current_location: Option<String>,
pub turn_index: u32,
pub globals: Vec<DebugGlobal>,
pub call_stack: Vec<DebugFrame>,
pub visit_counts: Vec<DebugVisit>,
pub pending_choices: Vec<DebugChoice>,
pub rng: DebugRng,
}
pub struct DebugGlobal {
pub name: String,
pub value: String,
}
pub struct DebugFrame {
pub kind: &'static str,
pub location: Option<String>,
pub temps: usize,
}
pub struct DebugVisit {
pub path: String,
pub count: u32,
}
pub struct DebugChoice {
pub text: String,
pub target: Option<String>,
}
pub struct DebugRng {
pub seed: i32,
pub previous: i32,
}
pub(crate) struct NameResolver<'p> {
program: &'p Program,
rev: HashMap<u32, String>,
}
impl<'p> NameResolver<'p> {
pub(crate) fn new(program: &'p Program) -> Self {
let mut rev: HashMap<u32, String> = HashMap::new();
for (path, target) in &program.address_by_path {
if target.byte_offset != 0 {
continue;
}
let idx = &target.container_idx;
let better = match rev.get(idx) {
None => true,
Some(existing) => {
path.len() < existing.len()
|| (path.len() == existing.len() && path.as_str() < existing.as_str())
}
};
if better {
rev.insert(*idx, path.clone());
}
}
Self { program, rev }
}
pub(crate) fn container_path(&self, idx: u32) -> Option<&str> {
self.rev.get(&idx).map(String::as_str)
}
pub(crate) fn def_path(&self, id: DefinitionId) -> Option<&str> {
let (idx, _) = self.program.resolve_target(id)?;
self.container_path(idx)
}
pub(crate) fn format_value(&self, value: &Value) -> String {
match value {
Value::Int(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::Bool(b) => b.to_string(),
Value::String(s) => format!("\"{s}\""),
Value::Null => "null".to_owned(),
Value::List(list) => {
let members: Vec<&str> = list
.items
.iter()
.filter_map(|id| self.program.list_item_name(*id))
.collect();
format!("({})", members.join(", "))
}
Value::DivertTarget(id) => match self.def_path(*id) {
Some(p) => format!("-> {p}"),
None => "-> ?".to_owned(),
},
Value::VariablePointer(id) => match self.program.global_var_name(*id) {
Some(n) => format!("ref {n}"),
None => "ref ?".to_owned(),
},
Value::TempPointer { slot, frame_depth } => {
format!("temp[{slot}]@{frame_depth}")
}
Value::FragmentRef(idx) => format!("<fragment {idx}>"),
}
}
}