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.type_map = type_map;
64 self.statement_types = statement_types;
65 self.unions = program.unions.clone();
69
70 self.external_builtins = config
72 .external_builtins
73 .iter()
74 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
75 .collect();
76
77 self.instrument = config.instrument;
79 if self.instrument {
80 for (id, word) in program.words.iter().enumerate() {
81 self.word_instrument_ids.insert(word.name.clone(), id);
82 }
83 }
84
85 let main_word = program
87 .find_word("main")
88 .ok_or_else(|| CodeGenError::Logic("No main word defined".to_string()))?;
89 self.main_returns_int = main_returns_int_effect(main_word);
90
91 for word in &program.words {
93 self.codegen_word(word)?;
94 }
95
96 self.codegen_main()?;
98
99 let mut ir = String::new();
101
102 writeln!(&mut ir, "; ModuleID = 'main'")?;
104 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
105 writeln!(&mut ir)?;
106
107 self.emit_value_type_def(&mut ir)?;
109
110 self.emit_string_and_symbol_globals(&mut ir)?;
112
113 if self.instrument {
115 self.emit_instrumentation_globals(&mut ir)?;
116 }
117
118 emit_runtime_decls(&mut ir)?;
120
121 if !self.external_builtins.is_empty() {
123 writeln!(&mut ir, "; External builtin declarations")?;
124 for symbol in self.external_builtins.values() {
125 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
127 }
128 writeln!(&mut ir)?;
129 }
130
131 if !self.quotation_functions.is_empty() {
133 writeln!(&mut ir, "; Quotation functions")?;
134 ir.push_str(&self.quotation_functions);
135 writeln!(&mut ir)?;
136 }
137
138 ir.push_str(&self.output);
140
141 Ok(ir)
142 }
143
144 pub fn codegen_program_with_ffi(
148 &mut self,
149 program: &Program,
150 type_map: HashMap<usize, Type>,
151 statement_types: HashMap<(String, usize), Type>,
152 config: &CompilerConfig,
153 ffi_bindings: &FfiBindings,
154 ) -> Result<String, CodeGenError> {
155 self.ffi_bindings = ffi_bindings.clone();
157
158 self.generate_ffi_wrappers()?;
160
161 self.type_map = type_map;
163 self.statement_types = statement_types;
164
165 self.unions = program.unions.clone();
167
168 self.external_builtins = config
170 .external_builtins
171 .iter()
172 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
173 .collect();
174
175 self.instrument = config.instrument;
177 if self.instrument {
178 for (id, word) in program.words.iter().enumerate() {
179 self.word_instrument_ids.insert(word.name.clone(), id);
180 }
181 }
182
183 let main_word = program
185 .find_word("main")
186 .ok_or_else(|| CodeGenError::Logic("No main word defined".to_string()))?;
187 self.main_returns_int = main_returns_int_effect(main_word);
188
189 for word in &program.words {
191 self.codegen_word(word)?;
192 }
193
194 self.codegen_main()?;
196
197 let mut ir = String::new();
199
200 writeln!(&mut ir, "; ModuleID = 'main'")?;
202 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
203 writeln!(&mut ir)?;
204
205 self.emit_value_type_def(&mut ir)?;
207
208 self.emit_string_and_symbol_globals(&mut ir)?;
210
211 if self.instrument {
213 self.emit_instrumentation_globals(&mut ir)?;
214 }
215
216 self.emit_runtime_declarations(&mut ir)?;
218
219 if !self.ffi_bindings.functions.is_empty() {
221 writeln!(&mut ir, "; FFI C function declarations")?;
222 writeln!(&mut ir, "declare ptr @malloc(i64)")?;
223 writeln!(&mut ir, "declare void @free(ptr)")?;
224 writeln!(&mut ir, "declare i64 @strlen(ptr)")?;
225 writeln!(&mut ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
226 writeln!(
228 &mut ir,
229 "declare ptr @patch_seq_string_to_cstring(ptr, ptr)"
230 )?;
231 writeln!(
232 &mut ir,
233 "declare ptr @patch_seq_cstring_to_string(ptr, ptr)"
234 )?;
235 for func in self.ffi_bindings.functions.values() {
236 let c_ret_type = ffi_return_type(&func.return_spec);
237 let c_args = ffi_c_args(&func.args);
238 writeln!(
239 &mut ir,
240 "declare {} @{}({})",
241 c_ret_type, func.c_name, c_args
242 )?;
243 }
244 writeln!(&mut ir)?;
245 }
246
247 if !self.external_builtins.is_empty() {
249 writeln!(&mut ir, "; External builtin declarations")?;
250 for symbol in self.external_builtins.values() {
251 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
252 }
253 writeln!(&mut ir)?;
254 }
255
256 if !self.ffi_wrapper_code.is_empty() {
258 writeln!(&mut ir, "; FFI wrapper functions")?;
259 ir.push_str(&self.ffi_wrapper_code);
260 writeln!(&mut ir)?;
261 }
262
263 if !self.quotation_functions.is_empty() {
265 writeln!(&mut ir, "; Quotation functions")?;
266 ir.push_str(&self.quotation_functions);
267 writeln!(&mut ir)?;
268 }
269
270 ir.push_str(&self.output);
272
273 Ok(ir)
274 }
275
276 pub(super) fn emit_runtime_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
278 emit_runtime_decls(ir)
279 }
280
281 fn emit_instrumentation_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
288 let n = self.word_instrument_ids.len();
289 if n == 0 {
290 return Ok(());
291 }
292
293 writeln!(ir, "; Instrumentation globals (--instrument)")?;
294
295 writeln!(
297 ir,
298 "@seq_word_counters = global [{} x i64] zeroinitializer",
299 n
300 )?;
301
302 let mut words: Vec<(usize, &str)> = self
304 .word_instrument_ids
305 .iter()
306 .map(|(name, &id)| (id, name.as_str()))
307 .collect();
308 words.sort_by_key(|&(id, _)| id);
309
310 for &(id, name) in &words {
312 let name_bytes = name.as_bytes();
313 let len = name_bytes.len() + 1; let escaped: String = name_bytes
315 .iter()
316 .map(|&b| format!("\\{:02X}", b))
317 .collect::<String>();
318 writeln!(
319 ir,
320 "@seq_word_name_{} = private constant [{} x i8] c\"{}\\00\"",
321 id, len, escaped
322 )?;
323 }
324
325 let ptrs: Vec<String> = words
327 .iter()
328 .map(|&(id, _name)| format!("ptr @seq_word_name_{}", id))
329 .collect();
330 writeln!(
331 ir,
332 "@seq_word_names = private constant [{} x ptr] [{}]",
333 n,
334 ptrs.join(", ")
335 )?;
336
337 writeln!(ir)?;
338 Ok(())
339 }
340}