swamp_code_gen_program/
lib.rs1use source_map_cache::SourceMapWrapper;
6use swamp_code_gen::code_bld::CodeBuilderOptions;
7use swamp_code_gen::disasm::{disasm_function, disasm_whole_program};
8use swamp_code_gen::top_state::TopLevelGenState;
9use swamp_compile::Program;
10use swamp_semantic::Function;
11use swamp_vm_types::FrameMemoryAddress;
12use swamp_vm_types::InstructionPositionOffset;
13use swamp_vm_types::types::write_basic_type;
14use time_dilation::ScopedTimer;
15
16pub struct CodeGenOptions {
17 pub show_disasm: bool,
18 pub disasm_filter: Option<String>,
19 pub show_debug: bool,
20 pub show_types: bool,
21 pub ignore_host_call: bool,
22}
23
24#[must_use]
30pub fn matches_pattern(function_name: &str, pattern: &str) -> bool {
31 if pattern.ends_with("::") {
32 function_name.starts_with(pattern)
33 } else if pattern.contains('*') {
34 let parts: Vec<&str> = pattern.split('*').collect();
35 if parts.len() > 2 {
36 return false;
37 }
38
39 let prefix = parts[0];
40 let suffix = if parts.len() == 2 { parts[1] } else { "" };
41
42 if !function_name.starts_with(prefix) {
43 return false;
44 }
45
46 let remaining_name = &function_name[prefix.len()..];
47 remaining_name.ends_with(suffix)
48 } else {
49 function_name == pattern
50 }
51}
52
53#[must_use]
55pub fn function_name_matches_filter(function_name: &str, filter_string: &str) -> bool {
56 if filter_string.trim().is_empty() {
57 return true;
58 }
59
60 let patterns: Vec<&str> = filter_string.split(',').collect();
61
62 for pattern in patterns {
63 let trimmed_pattern = pattern.trim();
64 let simplified_function_name = function_name
65 .strip_prefix("crate::")
66 .map_or(function_name, |stripped| stripped);
67
68 if matches_pattern(simplified_function_name, trimmed_pattern) {
69 return true;
70 }
71 }
72
73 false
74}
75
76#[must_use]
79pub fn code_gen_program(
80 program: &Program,
81 source_map_lookup: &SourceMapWrapper,
82 options: &CodeGenOptions,
83) -> TopLevelGenState {
84 let _compile_all_modules_timer = ScopedTimer::new("code generate whole program");
85 let mut code_gen = TopLevelGenState::new(CodeBuilderOptions {
86 should_show_debug: options.show_debug,
87 });
88
89 code_gen.reserve_space_for_constants(&program.state.constants_in_dependency_order);
90
91 for (_path, module) in program.modules.modules() {
102 for internal_function_def in &module.symbol_table.internal_functions() {
103 code_gen.emit_function_def(
104 internal_function_def,
105 source_map_lookup,
106 options.ignore_host_call,
107 );
108 }
109 }
110
111 for (_associated_on_type, impl_functions) in &program.state.associated_impls.functions {
112 for (_name, func) in &impl_functions.functions {
113 match &**func {
114 Function::Internal(int_fn) => {
115 code_gen.emit_function_def(int_fn, source_map_lookup, options.ignore_host_call);
116 }
117
118 Function::External(_ext_fn) => {
119 }
121
122 Function::Intrinsic(_) => {
123 }
125 }
126 }
127 }
128
129 code_gen.emit_constants_expression_functions_in_order(
130 &program.state.constants_in_dependency_order,
131 source_map_lookup,
132 );
133
134 code_gen.finalize();
135
136 if options.show_types {
137 for (id, basic_type) in &code_gen.codegen_state.layout_cache.id_to_layout {
138 let mut str = String::new();
139 write_basic_type(basic_type, FrameMemoryAddress(0), &mut str, 0).expect("output error");
140 eprintln!("{id}>{str}");
141 }
142 }
143
144 if options.show_disasm {
145 if let Some(filter) = &options.disasm_filter {
146 let mut current_ip: u32 = 0;
148 let instructions = code_gen.instructions();
149
150 while current_ip < (instructions.len() - 1) as u32 {
151 if let Some(debug_info_for_pc) = code_gen.debug_info().fetch(current_ip as usize) {
152 let function_name = &debug_info_for_pc.function_debug_info.name;
153 if function_name_matches_filter(function_name, filter) {
156 println!(
158 "{function_name} ==========================================================================",
159 );
160 let end_ip =
161 current_ip + debug_info_for_pc.function_debug_info.ip_range.count.0;
162 let instructions_slice =
163 &instructions[current_ip as usize..end_ip as usize];
164
165 let output_string = disasm_function(
166 &debug_info_for_pc.function_debug_info.return_type,
167 instructions_slice,
168 &InstructionPositionOffset(current_ip),
169 code_gen.debug_info(),
170 source_map_lookup,
171 );
172 println!("{output_string}"); }
174
175 current_ip += debug_info_for_pc.function_debug_info.ip_range.count.0;
176 } else {
177 panic!("instruction pointer that is not covered")
178 }
179 }
180 } else {
181 disasm_whole_program(
183 code_gen.debug_info(),
184 source_map_lookup,
185 code_gen.instructions(),
186 );
187 }
188 }
189
190 code_gen
191}