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 if self.instrument {
131 for (id, word) in program.words.iter().enumerate() {
132 self.word_instrument_ids.insert(word.name.clone(), id);
133 }
134 }
135
136 let main_word = program
139 .find_word("main")
140 .ok_or_else(|| CodeGenError::Logic("No main word defined".to_string()))?;
141 self.main_returns_int = main_returns_int_effect(main_word);
142
143 Ok(())
144 }
145
146 fn generate_words_and_main(&mut self, program: &Program) -> Result<(), CodeGenError> {
148 for word in &program.words {
149 self.codegen_word(word)?;
150 }
151 self.codegen_main()
152 }
153
154 fn emit_ir_header(&self, ir: &mut String) -> Result<(), CodeGenError> {
156 writeln!(ir, "; ModuleID = 'main'")?;
157 writeln!(ir, "target triple = \"{}\"", get_target_triple())?;
158 writeln!(ir)?;
159 Ok(())
160 }
161
162 fn emit_ir_type_and_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
165 self.emit_value_type_def(ir)?;
166 self.emit_string_and_symbol_globals(ir)?;
167 if self.instrument {
168 self.emit_instrumentation_globals(ir)?;
169 }
170 Ok(())
171 }
172
173 fn emit_external_builtins(&self, ir: &mut String) -> Result<(), CodeGenError> {
174 if self.external_builtins.is_empty() {
175 return Ok(());
176 }
177 writeln!(ir, "; External builtin declarations")?;
178 for symbol in self.external_builtins.values() {
180 writeln!(ir, "declare ptr @{}(ptr)", symbol)?;
181 }
182 writeln!(ir)?;
183 Ok(())
184 }
185
186 fn emit_quotation_functions(&self, ir: &mut String) -> Result<(), CodeGenError> {
187 if self.quotation_functions.is_empty() {
188 return Ok(());
189 }
190 writeln!(ir, "; Quotation functions")?;
191 ir.push_str(&self.quotation_functions);
192 writeln!(ir)?;
193 Ok(())
194 }
195
196 fn emit_ffi_c_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
197 if self.ffi_bindings.functions.is_empty() {
198 return Ok(());
199 }
200 writeln!(ir, "; FFI C function declarations")?;
201 writeln!(ir, "declare ptr @malloc(i64)")?;
202 writeln!(ir, "declare void @free(ptr)")?;
203 writeln!(ir, "declare i64 @strlen(ptr)")?;
204 writeln!(ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
205 writeln!(ir, "declare ptr @patch_seq_string_to_cstring(ptr, ptr)")?;
207 writeln!(ir, "declare ptr @patch_seq_cstring_to_string(ptr, ptr)")?;
208 for func in self.ffi_bindings.functions.values() {
209 let c_ret_type = ffi_return_type(&func.return_spec);
210 let c_args = ffi_c_args(&func.args);
211 writeln!(ir, "declare {} @{}({})", c_ret_type, func.c_name, c_args)?;
212 }
213 writeln!(ir)?;
214 Ok(())
215 }
216
217 fn emit_ffi_wrappers_section(&self, ir: &mut String) -> Result<(), CodeGenError> {
218 if self.ffi_wrapper_code.is_empty() {
219 return Ok(());
220 }
221 writeln!(ir, "; FFI wrapper functions")?;
222 ir.push_str(&self.ffi_wrapper_code);
223 writeln!(ir)?;
224 Ok(())
225 }
226
227 fn emit_instrumentation_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
232 let n = self.word_instrument_ids.len();
233 if n == 0 {
234 return Ok(());
235 }
236
237 writeln!(ir, "; Instrumentation globals (--instrument)")?;
238
239 writeln!(
240 ir,
241 "@seq_word_counters = global [{} x i64] zeroinitializer",
242 n
243 )?;
244
245 let mut words: Vec<(usize, &str)> = self
247 .word_instrument_ids
248 .iter()
249 .map(|(name, &id)| (id, name.as_str()))
250 .collect();
251 words.sort_by_key(|&(id, _)| id);
252
253 for &(id, name) in &words {
254 let name_bytes = name.as_bytes();
255 let len = name_bytes.len() + 1; let escaped: String = name_bytes
257 .iter()
258 .map(|&b| format!("\\{:02X}", b))
259 .collect::<String>();
260 writeln!(
261 ir,
262 "@seq_word_name_{} = private constant [{} x i8] c\"{}\\00\"",
263 id, len, escaped
264 )?;
265 }
266
267 let ptrs: Vec<String> = words
268 .iter()
269 .map(|&(id, _name)| format!("ptr @seq_word_name_{}", id))
270 .collect();
271 writeln!(
272 ir,
273 "@seq_word_names = private constant [{} x ptr] [{}]",
274 n,
275 ptrs.join(", ")
276 )?;
277
278 writeln!(ir)?;
279 Ok(())
280 }
281}