1use super::{
7 CodeGen, CodeGenError, emit_runtime_decls, ffi_c_args, ffi_return_type, get_target_triple,
8};
9use crate::ast::Program;
10use crate::config::CompilerConfig;
11use crate::ffi::FfiBindings;
12use crate::types::Type;
13use std::collections::HashMap;
14use std::fmt::Write as _;
15
16impl CodeGen {
17 pub fn codegen_program(
19 &mut self,
20 program: &Program,
21 type_map: HashMap<usize, Type>,
22 statement_types: HashMap<(String, usize), Type>,
23 ) -> Result<String, CodeGenError> {
24 self.codegen_program_with_config(
25 program,
26 type_map,
27 statement_types,
28 &CompilerConfig::default(),
29 )
30 }
31
32 pub fn codegen_program_with_config(
37 &mut self,
38 program: &Program,
39 type_map: HashMap<usize, Type>,
40 statement_types: HashMap<(String, usize), Type>,
41 config: &CompilerConfig,
42 ) -> Result<String, CodeGenError> {
43 self.type_map = type_map;
45 self.statement_types = statement_types;
46
47 self.unions = program.unions.clone();
49
50 self.external_builtins = config
52 .external_builtins
53 .iter()
54 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
55 .collect();
56
57 self.instrument = config.instrument;
59 if self.instrument {
60 for (id, word) in program.words.iter().enumerate() {
61 self.word_instrument_ids.insert(word.name.clone(), id);
62 }
63 }
64
65 if program.find_word("main").is_none() {
67 return Err(CodeGenError::Logic("No main word defined".to_string()));
68 }
69
70 for word in &program.words {
72 self.codegen_word(word)?;
73 }
74
75 self.codegen_main()?;
77
78 let mut ir = String::new();
80
81 writeln!(&mut ir, "; ModuleID = 'main'")?;
83 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
84 writeln!(&mut ir)?;
85
86 writeln!(&mut ir, "; Value type (Rust enum - 40 bytes)")?;
88 writeln!(&mut ir, "%Value = type {{ i64, i64, i64, i64, i64 }}")?;
89 writeln!(&mut ir)?;
90
91 self.emit_string_and_symbol_globals(&mut ir)?;
93
94 if self.instrument {
96 self.emit_instrumentation_globals(&mut ir)?;
97 }
98
99 emit_runtime_decls(&mut ir)?;
101
102 if !self.external_builtins.is_empty() {
104 writeln!(&mut ir, "; External builtin declarations")?;
105 for symbol in self.external_builtins.values() {
106 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
108 }
109 writeln!(&mut ir)?;
110 }
111
112 if !self.quotation_functions.is_empty() {
114 writeln!(&mut ir, "; Quotation functions")?;
115 ir.push_str(&self.quotation_functions);
116 writeln!(&mut ir)?;
117 }
118
119 ir.push_str(&self.output);
121
122 Ok(ir)
123 }
124
125 pub fn codegen_program_with_ffi(
129 &mut self,
130 program: &Program,
131 type_map: HashMap<usize, Type>,
132 statement_types: HashMap<(String, usize), Type>,
133 config: &CompilerConfig,
134 ffi_bindings: &FfiBindings,
135 ) -> Result<String, CodeGenError> {
136 self.ffi_bindings = ffi_bindings.clone();
138
139 self.generate_ffi_wrappers()?;
141
142 self.type_map = type_map;
144 self.statement_types = statement_types;
145
146 self.unions = program.unions.clone();
148
149 self.external_builtins = config
151 .external_builtins
152 .iter()
153 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
154 .collect();
155
156 self.instrument = config.instrument;
158 if self.instrument {
159 for (id, word) in program.words.iter().enumerate() {
160 self.word_instrument_ids.insert(word.name.clone(), id);
161 }
162 }
163
164 if program.find_word("main").is_none() {
166 return Err(CodeGenError::Logic("No main word defined".to_string()));
167 }
168
169 for word in &program.words {
171 self.codegen_word(word)?;
172 }
173
174 self.codegen_main()?;
176
177 let mut ir = String::new();
179
180 writeln!(&mut ir, "; ModuleID = 'main'")?;
182 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
183 writeln!(&mut ir)?;
184
185 writeln!(&mut ir, "; Value type (Rust enum - 40 bytes)")?;
187 writeln!(&mut ir, "%Value = type {{ i64, i64, i64, i64, i64 }}")?;
188 writeln!(&mut ir)?;
189
190 self.emit_string_and_symbol_globals(&mut ir)?;
192
193 if self.instrument {
195 self.emit_instrumentation_globals(&mut ir)?;
196 }
197
198 self.emit_runtime_declarations(&mut ir)?;
200
201 if !self.ffi_bindings.functions.is_empty() {
203 writeln!(&mut ir, "; FFI C function declarations")?;
204 writeln!(&mut ir, "declare ptr @malloc(i64)")?;
205 writeln!(&mut ir, "declare void @free(ptr)")?;
206 writeln!(&mut ir, "declare i64 @strlen(ptr)")?;
207 writeln!(&mut ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
208 writeln!(
210 &mut ir,
211 "declare ptr @patch_seq_string_to_cstring(ptr, ptr)"
212 )?;
213 writeln!(
214 &mut ir,
215 "declare ptr @patch_seq_cstring_to_string(ptr, ptr)"
216 )?;
217 for func in self.ffi_bindings.functions.values() {
218 let c_ret_type = ffi_return_type(&func.return_spec);
219 let c_args = ffi_c_args(&func.args);
220 writeln!(
221 &mut ir,
222 "declare {} @{}({})",
223 c_ret_type, func.c_name, c_args
224 )?;
225 }
226 writeln!(&mut ir)?;
227 }
228
229 if !self.external_builtins.is_empty() {
231 writeln!(&mut ir, "; External builtin declarations")?;
232 for symbol in self.external_builtins.values() {
233 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
234 }
235 writeln!(&mut ir)?;
236 }
237
238 if !self.ffi_wrapper_code.is_empty() {
240 writeln!(&mut ir, "; FFI wrapper functions")?;
241 ir.push_str(&self.ffi_wrapper_code);
242 writeln!(&mut ir)?;
243 }
244
245 if !self.quotation_functions.is_empty() {
247 writeln!(&mut ir, "; Quotation functions")?;
248 ir.push_str(&self.quotation_functions);
249 writeln!(&mut ir)?;
250 }
251
252 ir.push_str(&self.output);
254
255 Ok(ir)
256 }
257
258 pub(super) fn emit_runtime_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
260 emit_runtime_decls(ir)
261 }
262
263 fn emit_instrumentation_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
270 let n = self.word_instrument_ids.len();
271 if n == 0 {
272 return Ok(());
273 }
274
275 writeln!(ir, "; Instrumentation globals (--instrument)")?;
276
277 writeln!(
279 ir,
280 "@seq_word_counters = global [{} x i64] zeroinitializer",
281 n
282 )?;
283
284 let mut words: Vec<(usize, &str)> = self
286 .word_instrument_ids
287 .iter()
288 .map(|(name, &id)| (id, name.as_str()))
289 .collect();
290 words.sort_by_key(|&(id, _)| id);
291
292 for &(id, name) in &words {
294 let name_bytes = name.as_bytes();
295 let len = name_bytes.len() + 1; let escaped: String = name_bytes
297 .iter()
298 .map(|&b| format!("\\{:02X}", b))
299 .collect::<String>();
300 writeln!(
301 ir,
302 "@seq_word_name_{} = private constant [{} x i8] c\"{}\\00\"",
303 id, len, escaped
304 )?;
305 }
306
307 let ptrs: Vec<String> = words
309 .iter()
310 .map(|&(id, _name)| format!("ptr @seq_word_name_{}", id))
311 .collect();
312 writeln!(
313 ir,
314 "@seq_word_names = private constant [{} x ptr] [{}]",
315 n,
316 ptrs.join(", ")
317 )?;
318
319 writeln!(ir)?;
320 Ok(())
321 }
322}