1use source_map_cache::SourceMapWrapper;
6use source_map_node::FileId;
7use std::fmt;
8use std::fmt::Write;
9use swamp_vm_debug_info::DebugInfo;
10use swamp_vm_disasm::disasm_instructions_color;
11use swamp_vm_isa::BinaryInstruction;
12use swamp_vm_types::types::{show_frame_memory, write_basic_type, VariableRegister, VmType};
13use swamp_vm_types::{FrameMemoryAddress, InstructionRange};
14
15#[must_use]
16pub const fn is_valid_file_id(file_id: FileId) -> bool {
17 file_id != 0 && file_id != 0xffff
18}
19pub fn show_parameters_and_variables(
20 return_type: &VmType,
21 variables: &[VariableRegister],
22 f: &mut dyn Write,
23 use_color: bool,
24) -> Result<(), fmt::Error> {
25 if use_color {
26 if !return_type.is_scalar() {
27 writeln!(f, "{}: {}", tinter::blue("r0"), &return_type, )?;
28 write_basic_type(&return_type.basic_type, FrameMemoryAddress(0), f, 0)?;
29 writeln!(f)?;
30 }
31
32 for variable_register in variables {
33 writeln!(
34 f,
35 "var {}: ({}): {} {}",
36 tinter::yellow(format!("{}", variable_register.unique_id_in_function)),
37 tinter::magenta(variable_register),
38 variable_register.register.ty,
39 variable_register.register.comment
40 )?;
41 }
42 } else {
43 if !return_type.is_scalar() {
44 writeln!(f, "{}: {}", "r0", &return_type, )?;
45 write_basic_type(&return_type.basic_type, FrameMemoryAddress(0), f, 0)?;
46 writeln!(f)?;
47 }
48
49 for variable_register in variables {
50 writeln!(
51 f,
52 "var {}: ({}): {} {}",
53 format!("{}", variable_register.unique_id_in_function),
54 variable_register,
55 variable_register.register.ty,
56 variable_register.register.comment
57 )?;
58 }
59 }
60
61 Ok(())
62}
63
64#[must_use]
67pub fn disasm_function(
68 return_type: &VmType,
69 instructions: &[BinaryInstruction],
70 range: &InstructionRange,
71 debug_info: &DebugInfo,
72 source_map_wrapper: &SourceMapWrapper,
73 use_color: bool,
74) -> String {
75 let mut header_output = String::new();
76
77 let info = debug_info.fetch(range.start.0 as usize).unwrap();
78
79 show_frame_memory(
80 &info.function_debug_info.frame_memory,
81 &mut header_output,
82 use_color,
83 )
84 .unwrap();
85
86 show_parameters_and_variables(
87 return_type,
88 &info.function_debug_info.frame_memory.variable_registers,
89 &mut header_output,
90 use_color,
91 )
92 .expect("should work");
93
94 let asm = disasm_instructions_color(
95 instructions,
96 range,
97 debug_info,
98 source_map_wrapper,
99 use_color,
100 );
101
102 format!("{header_output}\n{asm}", )
103}
104
105pub fn disasm_whole_program(
106 debug_info: &DebugInfo,
107 source_map_wrapper: &SourceMapWrapper,
108 instructions: &[BinaryInstruction],
109 use_color: bool,
110) {
111 let mut current_ip: u32 = 0;
112
113 while current_ip < (instructions.len() - 1) as u32 {
114 if let Some(debug_info_for_pc) = debug_info.fetch(current_ip as usize) {
115 println!(
117 "{} ==========================================================================",
118 debug_info_for_pc.function_debug_info.name
119 );
120 let end_ip = current_ip + debug_info_for_pc.function_debug_info.ip_range.count.0;
121 let output_string = disasm_function(
124 &debug_info_for_pc.function_debug_info.return_type,
125 instructions,
126 &debug_info_for_pc.function_debug_info.ip_range,
127 debug_info,
128 source_map_wrapper,
129 use_color,
130 );
131 println!("{output_string}"); current_ip = end_ip;
133 } else {
134 panic!("instruction pointer that is not covered")
135 }
136 }
137}