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::types::write_basic_type;
13use time_dilation::ScopedTimer;
14
15pub struct CodeGenOptions {
16 pub show_disasm: bool,
17 pub disasm_filter: Option<String>,
18 pub show_debug: bool,
19 pub show_types: bool,
20 pub ignore_host_call: bool,
21}
22
23#[must_use]
29pub fn matches_pattern(function_name: &str, pattern: &str) -> bool {
30 if pattern.ends_with("::") {
31 function_name.starts_with(pattern)
32 } else if pattern.contains('*') {
33 let parts: Vec<&str> = pattern.split('*').collect();
34 if parts.len() > 2 {
35 return false;
36 }
37
38 let prefix = parts[0];
39 let suffix = if parts.len() == 2 { parts[1] } else { "" };
40
41 if !function_name.starts_with(prefix) {
42 return false;
43 }
44
45 let remaining_name = &function_name[prefix.len()..];
46 remaining_name.ends_with(suffix)
47 } else {
48 function_name == pattern
49 }
50}
51
52#[must_use]
54pub fn function_name_matches_filter(function_name: &str, filter_string: &str) -> bool {
55 if filter_string.trim().is_empty() {
56 return true;
57 }
58
59 let patterns: Vec<&str> = filter_string.split(',').collect();
60
61 for pattern in patterns {
62 let trimmed_pattern = pattern.trim();
63 let simplified_function_name = function_name
64 .strip_prefix("crate::")
65 .map_or(function_name, |stripped| stripped);
66
67 if matches_pattern(simplified_function_name, trimmed_pattern) {
68 return true;
69 }
70 }
71
72 false
73}
74
75#[must_use]
78pub fn code_gen_program(
79 program: &Program,
80 source_map_lookup: &SourceMapWrapper,
81 options: &CodeGenOptions,
82) -> TopLevelGenState {
83 let _compile_all_modules_timer = ScopedTimer::new("code generate whole program");
84 let mut code_gen = TopLevelGenState::new(CodeBuilderOptions {
85 should_show_debug: options.show_debug,
86 });
87
88 code_gen.reserve_space_for_constants(&program.state.constants_in_dependency_order);
89
90 for (_path, module) in program.modules.modules() {
102 for internal_function_def in &module.definition_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 let use_color = true;
146 if let Some(filter) = &options.disasm_filter {
147 let mut current_ip: u32 = 0;
149 let instructions = code_gen.instructions();
150
151 while current_ip < (instructions.len() - 1) as u32 {
152 if let Some(debug_info_for_pc) = code_gen.debug_info().fetch(current_ip as usize) {
153 let function_name = &debug_info_for_pc.function_debug_info.name;
154 if function_name_matches_filter(function_name, filter) {
157 println!(
159 "{function_name} ==========================================================================",
160 );
161 let end_ip =
162 current_ip + debug_info_for_pc.function_debug_info.ip_range.count.0;
163
164 let output_string = disasm_function(
165 &debug_info_for_pc.function_debug_info.return_type,
166 instructions,
167 &debug_info_for_pc.function_debug_info.ip_range,
168 code_gen.debug_info(),
169 source_map_lookup,
170 use_color,
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 use_color,
187 );
188 }
189 }
190
191 code_gen
192}