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() {
103 for internal_function_def in &module.symbol_table.internal_functions() {
104 code_gen.emit_function_def(
105 internal_function_def,
106 source_map_lookup,
107 options.ignore_host_call,
108 );
109 }
110 }
111
112 for (_associated_on_type, impl_functions) in &program.state.associated_impls.functions {
113 for (_name, func) in &impl_functions.functions {
114 match &**func {
115 Function::Internal(int_fn) => {
116 code_gen.emit_function_def(int_fn, source_map_lookup, options.ignore_host_call);
117 }
118
119 Function::External(_ext_fn) => {
120 }
122
123 Function::Intrinsic(_) => {
124 }
126 }
127 }
128 }
129
130 code_gen.emit_constants_expression_functions_in_order(
131 &program.state.constants_in_dependency_order,
132 source_map_lookup,
133 );
134
135 code_gen.finalize();
136
137 if options.show_types {
138 for (id, basic_type) in &code_gen.codegen_state.layout_cache.id_to_layout {
139 let mut str = String::new();
140 write_basic_type(basic_type, FrameMemoryAddress(0), &mut str, 0).expect("output error");
141 eprintln!("{id}>{str}");
142 }
143 }
144
145 if options.show_disasm {
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 let instructions_slice =
164 &instructions[current_ip as usize..end_ip as usize];
165
166 let output_string = disasm_function(
167 &debug_info_for_pc.function_debug_info.return_type,
168 instructions_slice,
169 &InstructionPositionOffset(current_ip),
170 code_gen.debug_info(),
171 source_map_lookup,
172 );
173 println!("{output_string}"); }
175
176 current_ip += debug_info_for_pc.function_debug_info.ip_range.count.0;
177 } else {
178 panic!("instruction pointer that is not covered")
179 }
180 }
181 } else {
182 disasm_whole_program(
184 code_gen.debug_info(),
185 source_map_lookup,
186 code_gen.instructions(),
187 );
188 }
189 }
190
191 code_gen
192}