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 self.emit_value_type_def(&mut ir)?;
88
89 self.emit_string_and_symbol_globals(&mut ir)?;
91
92 if self.instrument {
94 self.emit_instrumentation_globals(&mut ir)?;
95 }
96
97 emit_runtime_decls(&mut ir)?;
99
100 if !self.external_builtins.is_empty() {
102 writeln!(&mut ir, "; External builtin declarations")?;
103 for symbol in self.external_builtins.values() {
104 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
106 }
107 writeln!(&mut ir)?;
108 }
109
110 if !self.quotation_functions.is_empty() {
112 writeln!(&mut ir, "; Quotation functions")?;
113 ir.push_str(&self.quotation_functions);
114 writeln!(&mut ir)?;
115 }
116
117 ir.push_str(&self.output);
119
120 Ok(ir)
121 }
122
123 pub fn codegen_program_with_ffi(
127 &mut self,
128 program: &Program,
129 type_map: HashMap<usize, Type>,
130 statement_types: HashMap<(String, usize), Type>,
131 config: &CompilerConfig,
132 ffi_bindings: &FfiBindings,
133 ) -> Result<String, CodeGenError> {
134 self.ffi_bindings = ffi_bindings.clone();
136
137 self.generate_ffi_wrappers()?;
139
140 self.type_map = type_map;
142 self.statement_types = statement_types;
143
144 self.unions = program.unions.clone();
146
147 self.external_builtins = config
149 .external_builtins
150 .iter()
151 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
152 .collect();
153
154 self.instrument = config.instrument;
156 if self.instrument {
157 for (id, word) in program.words.iter().enumerate() {
158 self.word_instrument_ids.insert(word.name.clone(), id);
159 }
160 }
161
162 if program.find_word("main").is_none() {
164 return Err(CodeGenError::Logic("No main word defined".to_string()));
165 }
166
167 for word in &program.words {
169 self.codegen_word(word)?;
170 }
171
172 self.codegen_main()?;
174
175 let mut ir = String::new();
177
178 writeln!(&mut ir, "; ModuleID = 'main'")?;
180 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
181 writeln!(&mut ir)?;
182
183 self.emit_value_type_def(&mut ir)?;
185
186 self.emit_string_and_symbol_globals(&mut ir)?;
188
189 if self.instrument {
191 self.emit_instrumentation_globals(&mut ir)?;
192 }
193
194 self.emit_runtime_declarations(&mut ir)?;
196
197 if !self.ffi_bindings.functions.is_empty() {
199 writeln!(&mut ir, "; FFI C function declarations")?;
200 writeln!(&mut ir, "declare ptr @malloc(i64)")?;
201 writeln!(&mut ir, "declare void @free(ptr)")?;
202 writeln!(&mut ir, "declare i64 @strlen(ptr)")?;
203 writeln!(&mut ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
204 writeln!(
206 &mut ir,
207 "declare ptr @patch_seq_string_to_cstring(ptr, ptr)"
208 )?;
209 writeln!(
210 &mut ir,
211 "declare ptr @patch_seq_cstring_to_string(ptr, ptr)"
212 )?;
213 for func in self.ffi_bindings.functions.values() {
214 let c_ret_type = ffi_return_type(&func.return_spec);
215 let c_args = ffi_c_args(&func.args);
216 writeln!(
217 &mut ir,
218 "declare {} @{}({})",
219 c_ret_type, func.c_name, c_args
220 )?;
221 }
222 writeln!(&mut ir)?;
223 }
224
225 if !self.external_builtins.is_empty() {
227 writeln!(&mut ir, "; External builtin declarations")?;
228 for symbol in self.external_builtins.values() {
229 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
230 }
231 writeln!(&mut ir)?;
232 }
233
234 if !self.ffi_wrapper_code.is_empty() {
236 writeln!(&mut ir, "; FFI wrapper functions")?;
237 ir.push_str(&self.ffi_wrapper_code);
238 writeln!(&mut ir)?;
239 }
240
241 if !self.quotation_functions.is_empty() {
243 writeln!(&mut ir, "; Quotation functions")?;
244 ir.push_str(&self.quotation_functions);
245 writeln!(&mut ir)?;
246 }
247
248 ir.push_str(&self.output);
250
251 Ok(ir)
252 }
253
254 pub(super) fn emit_runtime_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
256 emit_runtime_decls(ir)
257 }
258
259 fn emit_instrumentation_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
266 let n = self.word_instrument_ids.len();
267 if n == 0 {
268 return Ok(());
269 }
270
271 writeln!(ir, "; Instrumentation globals (--instrument)")?;
272
273 writeln!(
275 ir,
276 "@seq_word_counters = global [{} x i64] zeroinitializer",
277 n
278 )?;
279
280 let mut words: Vec<(usize, &str)> = self
282 .word_instrument_ids
283 .iter()
284 .map(|(name, &id)| (id, name.as_str()))
285 .collect();
286 words.sort_by_key(|&(id, _)| id);
287
288 for &(id, name) in &words {
290 let name_bytes = name.as_bytes();
291 let len = name_bytes.len() + 1; let escaped: String = name_bytes
293 .iter()
294 .map(|&b| format!("\\{:02X}", b))
295 .collect::<String>();
296 writeln!(
297 ir,
298 "@seq_word_name_{} = private constant [{} x i8] c\"{}\\00\"",
299 id, len, escaped
300 )?;
301 }
302
303 let ptrs: Vec<String> = words
305 .iter()
306 .map(|&(id, _name)| format!("ptr @seq_word_name_{}", id))
307 .collect();
308 writeln!(
309 ir,
310 "@seq_word_names = private constant [{} x ptr] [{}]",
311 n,
312 ptrs.join(", ")
313 )?;
314
315 writeln!(ir)?;
316 Ok(())
317 }
318}