1use core::fmt::{Display, Formatter, Result};
2use crate::codegen::opcodes::OpCode;
3use crate::runtime::Variant;
4use crate::runtime::module::Chunk;
5
6
7pub struct VMSnapshot {
8 pub calls: Vec<VMFrameSnapshot>,
9 pub frame: VMFrameSnapshot,
10 pub stack: Vec<Variant>,
11 pub locals: Vec<Variant>,
12}
13
14impl Display for VMSnapshot {
15 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
16
17 writeln!(fmt, "== Call Stack ==")?;
18
19 for (idx, state) in self.calls.iter().enumerate() {
20 write!(fmt, "{: >4}: Module: {}, Chunk: ", idx, state.module)?;
21 format_chunk_id(fmt,state.chunk_id)?;
22 writeln!(fmt, ", Frame: {}, Locals: {}", state.stack_idx, state.local_idx)?;
23 }
24
25 write!(fmt, "{: >4}: Module: {}, Chunk: ", self.calls.len(), self.frame.module)?;
26 format_chunk_id(fmt, self.frame.chunk_id)?;
27 writeln!(fmt, ", Frame: {}, Locals: {}", self.frame.stack_idx, self.frame.local_idx)?;
28
29 writeln!(fmt, "\n== Locals ==")?;
30 for (idx, chunk) in self.locals.chunks(10).enumerate() {
31 write!(fmt, "{: >4}: ", idx * 10)?;
32 let items = chunk.iter().map(|value| format!("{:?}", value))
33 .collect::<Vec<String>>()
34 .join(", ");
35 writeln!(fmt, "{}", items)?;
36 }
37
38 writeln!(fmt, "\n== Temporaries ==")?;
39 for (idx, chunk) in self.stack.chunks(10).enumerate() {
40 write!(fmt, "{: >4}: ", idx * 10)?;
41 let items = chunk.iter().map(|value| format!("{:?}", value))
42 .collect::<Vec<String>>()
43 .join(", ");
44 writeln!(fmt, "{}", items)?;
45 }
46
47 writeln!(fmt, "\n== Active Frame ==")?;
48 writeln!(fmt, "{}", self.frame)?;
49
50 Ok(())
51 }
52}
53
54
55pub struct VMFrameSnapshot {
56 pub module: String,
57 pub chunk_id: Chunk,
58 pub stack_idx: usize,
59 pub local_idx: usize,
60 pub pc: usize,
61 pub next_instr: Option<Vec<u8>>,
62}
63
64impl Display for VMFrameSnapshot {
65 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
66
67 write!(fmt, "Module: {}, Chunk: ", self.module)?;
68 format_chunk_id(fmt, self.chunk_id)?;
69 writeln!(fmt)?;
70
71 writeln!(fmt, "Frame: {}, Locals: {}", self.stack_idx, self.local_idx)?;
72
73 write!(fmt, "PC: {:#X}", self.pc)?;
74 if let Some(instr) = self.next_instr.as_ref() {
75 let opcode = OpCode::try_from(instr[0])
76 .map_or("INVALID".to_string(), |opcode| format!("{}", opcode));
77
78 let bytes = instr.iter()
79 .map(|b| format!("{:0>2X}", b))
80 .collect::<Vec<String>>()
81 .join(" ");
82
83 write!(fmt, ", Next: {} [{}]", opcode, bytes)?;
84 }
85 writeln!(fmt)?;
86
87 Ok(())
88 }
89}
90
91fn format_chunk_id(fmt: &mut Formatter<'_>, chunk_id: Chunk) -> Result {
92 match chunk_id {
93 Chunk::Main => fmt.write_str("<main>"),
94 Chunk::Function(fun_id) => write!(fmt, "{}", fun_id),
95 }
96}
97