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}