1use super::{
7 CodeGen, CodeGenError, emit_runtime_decls, ffi_c_args, ffi_return_type, get_target_triple,
8};
9use crate::ast::{Program, WordDef};
10use crate::config::CompilerConfig;
11use crate::ffi::FfiBindings;
12use crate::types::{StackType, Type};
13use std::collections::HashMap;
14use std::fmt::Write as _;
15
16fn main_returns_int_effect(word: &WordDef) -> bool {
23 let Some(effect) = &word.effect else {
24 return false;
25 };
26 matches!(
29 &effect.outputs,
30 StackType::Cons { rest, top: Type::Int }
31 if matches!(**rest, StackType::Empty | StackType::RowVar(_))
32 )
33}
34
35impl CodeGen {
36 pub fn codegen_program(
38 &mut self,
39 program: &Program,
40 type_map: HashMap<usize, Type>,
41 statement_types: HashMap<(String, usize), Type>,
42 ) -> Result<String, CodeGenError> {
43 self.codegen_program_with_config(
44 program,
45 type_map,
46 statement_types,
47 &CompilerConfig::default(),
48 )
49 }
50
51 pub fn codegen_program_with_config(
56 &mut self,
57 program: &Program,
58 type_map: HashMap<usize, Type>,
59 statement_types: HashMap<(String, usize), Type>,
60 config: &CompilerConfig,
61 ) -> Result<String, CodeGenError> {
62 self.prepare_program_state(program, type_map, statement_types, config)?;
63 self.generate_words_and_main(program)?;
64
65 let mut ir = String::new();
66 self.emit_ir_header(&mut ir)?;
67 self.emit_ir_type_and_globals(&mut ir)?;
68 emit_runtime_decls(&mut ir)?;
69 self.emit_external_builtins(&mut ir)?;
70 self.emit_quotation_functions(&mut ir)?;
71 ir.push_str(&self.output);
72 self.dbg_emit_module_metadata(&mut ir);
73 Ok(ir)
74 }
75
76 pub fn codegen_program_with_ffi(
80 &mut self,
81 program: &Program,
82 type_map: HashMap<usize, Type>,
83 statement_types: HashMap<(String, usize), Type>,
84 config: &CompilerConfig,
85 ffi_bindings: &FfiBindings,
86 ) -> Result<String, CodeGenError> {
87 self.ffi_bindings = ffi_bindings.clone();
88 self.generate_ffi_wrappers()?;
89
90 self.prepare_program_state(program, type_map, statement_types, config)?;
91 self.generate_words_and_main(program)?;
92
93 let mut ir = String::new();
94 self.emit_ir_header(&mut ir)?;
95 self.emit_ir_type_and_globals(&mut ir)?;
96 emit_runtime_decls(&mut ir)?;
97 self.emit_ffi_c_declarations(&mut ir)?;
98 self.emit_external_builtins(&mut ir)?;
99 self.emit_ffi_wrappers_section(&mut ir)?;
100 self.emit_quotation_functions(&mut ir)?;
101 ir.push_str(&self.output);
102 self.dbg_emit_module_metadata(&mut ir);
103 Ok(ir)
104 }
105
106 fn prepare_program_state(
113 &mut self,
114 program: &Program,
115 type_map: HashMap<usize, Type>,
116 statement_types: HashMap<(String, usize), Type>,
117 config: &CompilerConfig,
118 ) -> Result<(), CodeGenError> {
119 self.type_map = type_map;
120 self.statement_types = statement_types;
121 self.unions = program.unions.clone();
123 self.external_builtins = config
124 .external_builtins
125 .iter()
126 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
127 .collect();
128
129 self.instrument = config.instrument;
130 self.loop_opt_enabled = config.loop_opt;
131 self.loop_yield_cadence = config.loop_yield_cadence;
132 if self.instrument {
133 for (id, word) in program.words.iter().enumerate() {
134 self.word_instrument_ids.insert(word.name.clone(), id);
135 }
136 }
137
138 let main_word = program
141 .find_word("main")
142 .ok_or_else(|| CodeGenError::Logic("No main word defined".to_string()))?;
143 self.main_returns_int = main_returns_int_effect(main_word);
144
145 Ok(())
146 }
147
148 fn generate_words_and_main(&mut self, program: &Program) -> Result<(), CodeGenError> {
150 for word in &program.words {
151 self.codegen_word(word)?;
152 }
153 self.codegen_main()
154 }
155
156 fn emit_ir_header(&self, ir: &mut String) -> Result<(), CodeGenError> {
158 writeln!(ir, "; ModuleID = 'main'")?;
159 writeln!(ir, "target triple = \"{}\"", get_target_triple())?;
160 writeln!(ir)?;
161 Ok(())
162 }
163
164 fn emit_ir_type_and_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
167 self.emit_value_type_def(ir)?;
168 self.emit_string_and_symbol_globals(ir)?;
169 if self.instrument {
170 self.emit_instrumentation_globals(ir)?;
171 }
172 Ok(())
173 }
174
175 fn emit_external_builtins(&self, ir: &mut String) -> Result<(), CodeGenError> {
176 if self.external_builtins.is_empty() {
177 return Ok(());
178 }
179 writeln!(ir, "; External builtin declarations")?;
180 for symbol in self.external_builtins.values() {
182 writeln!(ir, "declare ptr @{}(ptr)", symbol)?;
183 }
184 writeln!(ir)?;
185 Ok(())
186 }
187
188 fn emit_quotation_functions(&self, ir: &mut String) -> Result<(), CodeGenError> {
189 if self.quotation_functions.is_empty() {
190 return Ok(());
191 }
192 writeln!(ir, "; Quotation functions")?;
193 ir.push_str(&self.quotation_functions);
194 writeln!(ir)?;
195 Ok(())
196 }
197
198 fn emit_ffi_c_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
199 if self.ffi_bindings.functions.is_empty() {
200 return Ok(());
201 }
202 writeln!(ir, "; FFI C function declarations")?;
203 writeln!(ir, "declare ptr @malloc(i64)")?;
204 writeln!(ir, "declare void @free(ptr)")?;
205 writeln!(ir, "declare i64 @strlen(ptr)")?;
206 writeln!(ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
207 writeln!(ir, "declare ptr @patch_seq_string_to_cstring(ptr, ptr)")?;
209 writeln!(ir, "declare ptr @patch_seq_cstring_to_string(ptr, ptr)")?;
210 for func in self.ffi_bindings.functions.values() {
211 let c_ret_type = ffi_return_type(&func.return_spec);
212 let c_args = ffi_c_args(&func.args);
213 writeln!(ir, "declare {} @{}({})", c_ret_type, func.c_name, c_args)?;
214 }
215 writeln!(ir)?;
216 Ok(())
217 }
218
219 fn emit_ffi_wrappers_section(&self, ir: &mut String) -> Result<(), CodeGenError> {
220 if self.ffi_wrapper_code.is_empty() {
221 return Ok(());
222 }
223 writeln!(ir, "; FFI wrapper functions")?;
224 ir.push_str(&self.ffi_wrapper_code);
225 writeln!(ir)?;
226 Ok(())
227 }
228
229 fn emit_instrumentation_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
234 let n = self.word_instrument_ids.len();
235 if n == 0 {
236 return Ok(());
237 }
238
239 writeln!(ir, "; Instrumentation globals (--instrument)")?;
240
241 writeln!(
242 ir,
243 "@seq_word_counters = global [{} x i64] zeroinitializer",
244 n
245 )?;
246
247 let mut words: Vec<(usize, &str)> = self
249 .word_instrument_ids
250 .iter()
251 .map(|(name, &id)| (id, name.as_str()))
252 .collect();
253 words.sort_by_key(|&(id, _)| id);
254
255 for &(id, name) in &words {
256 let name_bytes = name.as_bytes();
257 let len = name_bytes.len() + 1; let escaped: String = name_bytes
259 .iter()
260 .map(|&b| format!("\\{:02X}", b))
261 .collect::<String>();
262 writeln!(
263 ir,
264 "@seq_word_name_{} = private constant [{} x i8] c\"{}\\00\"",
265 id, len, escaped
266 )?;
267 }
268
269 let ptrs: Vec<String> = words
270 .iter()
271 .map(|&(id, _name)| format!("ptr @seq_word_name_{}", id))
272 .collect();
273 writeln!(
274 ir,
275 "@seq_word_names = private constant [{} x ptr] [{}]",
276 n,
277 ptrs.join(", ")
278 )?;
279
280 writeln!(ir)?;
281 Ok(())
282 }
283}