use std::fmt;
use super::state::{VmState, VmValue, ValueInvariants};
impl<'ctx, 'tcx> VmState<'ctx, 'tcx> {
pub fn describe(&self) -> String {
let mut lines = Vec::new();
if !self.locals.is_empty() {
lines.push("-- VM Locals --".to_string());
for (local, value) in self.locals.iter() {
lines.push(format!(
" _{}: {:?}",
local.as_usize(),
value.describe()
));
}
}
if !self.allocations.is_empty() {
lines.push("-- Allocations --".to_string());
for alloc in &self.allocations {
lines.push(format!(
" alloc_{}: base={}, size={}, align={}",
alloc.id.0,
alloc.base.to_string(),
alloc.size.to_string(),
alloc.align,
));
}
}
if !self.path_conditions.is_empty() {
lines.push(format!(
" {} path conditions asserted",
self.path_conditions.len()
));
}
if !self.notes.is_empty() {
lines.push("-- Notes --".to_string());
for note in &self.notes {
lines.push(format!(" * {note}"));
}
}
lines.join("\n")
}
}
impl<'ctx, 'tcx> VmValue<'ctx, 'tcx> {
fn describe(&self) -> String {
let term_str = self.term.to_string();
let mut flags = Vec::new();
if self.invariants.non_null {
flags.push("NN");
}
if self.invariants.aligned {
flags.push("AL");
}
if self.invariants.init {
flags.push("IN");
}
if self.invariants.in_bounds {
flags.push("IB");
}
let provenance = self
.provenance
.as_ref()
.map(|p| format!("@alloc{}", p.alloc_id.0))
.unwrap_or_default();
if flags.is_empty() {
format!("{term_str} {provenance}")
} else {
format!("{term_str} [{}] {}", flags.join(","), provenance)
}
}
}
impl fmt::Display for ValueInvariants {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut flags = Vec::new();
if self.non_null {
flags.push("non_null");
}
if self.aligned {
flags.push("aligned");
}
if self.init {
flags.push("init");
}
if self.in_bounds {
flags.push("in_bounds");
}
write!(f, "{}", flags.join("|"))
}
}