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 Ok(ir)
73 }
74
75 pub fn codegen_program_with_ffi(
79 &mut self,
80 program: &Program,
81 type_map: HashMap<usize, Type>,
82 statement_types: HashMap<(String, usize), Type>,
83 config: &CompilerConfig,
84 ffi_bindings: &FfiBindings,
85 ) -> Result<String, CodeGenError> {
86 self.ffi_bindings = ffi_bindings.clone();
87 self.generate_ffi_wrappers()?;
88
89 self.prepare_program_state(program, type_map, statement_types, config)?;
90 self.generate_words_and_main(program)?;
91
92 let mut ir = String::new();
93 self.emit_ir_header(&mut ir)?;
94 self.emit_ir_type_and_globals(&mut ir)?;
95 emit_runtime_decls(&mut ir)?;
96 self.emit_ffi_c_declarations(&mut ir)?;
97 self.emit_external_builtins(&mut ir)?;
98 self.emit_ffi_wrappers_section(&mut ir)?;
99 self.emit_quotation_functions(&mut ir)?;
100 ir.push_str(&self.output);
101 Ok(ir)
102 }
103
104 fn prepare_program_state(
111 &mut self,
112 program: &Program,
113 type_map: HashMap<usize, Type>,
114 statement_types: HashMap<(String, usize), Type>,
115 config: &CompilerConfig,
116 ) -> Result<(), CodeGenError> {
117 self.type_map = type_map;
118 self.statement_types = statement_types;
119 self.unions = program.unions.clone();
121 self.external_builtins = config
122 .external_builtins
123 .iter()
124 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
125 .collect();
126
127 self.instrument = config.instrument;
128 if self.instrument {
129 for (id, word) in program.words.iter().enumerate() {
130 self.word_instrument_ids.insert(word.name.clone(), id);
131 }
132 }
133
134 let main_word = program
137 .find_word("main")
138 .ok_or_else(|| CodeGenError::Logic("No main word defined".to_string()))?;
139 self.main_returns_int = main_returns_int_effect(main_word);
140
141 Ok(())
142 }
143
144 fn generate_words_and_main(&mut self, program: &Program) -> Result<(), CodeGenError> {
146 for word in &program.words {
147 self.codegen_word(word)?;
148 }
149 self.codegen_main()
150 }
151
152 fn emit_ir_header(&self, ir: &mut String) -> Result<(), CodeGenError> {
154 writeln!(ir, "; ModuleID = 'main'")?;
155 writeln!(ir, "target triple = \"{}\"", get_target_triple())?;
156 writeln!(ir)?;
157 Ok(())
158 }
159
160 fn emit_ir_type_and_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
163 self.emit_value_type_def(ir)?;
164 self.emit_string_and_symbol_globals(ir)?;
165 if self.instrument {
166 self.emit_instrumentation_globals(ir)?;
167 }
168 Ok(())
169 }
170
171 fn emit_external_builtins(&self, ir: &mut String) -> Result<(), CodeGenError> {
172 if self.external_builtins.is_empty() {
173 return Ok(());
174 }
175 writeln!(ir, "; External builtin declarations")?;
176 for symbol in self.external_builtins.values() {
178 writeln!(ir, "declare ptr @{}(ptr)", symbol)?;
179 }
180 writeln!(ir)?;
181 Ok(())
182 }
183
184 fn emit_quotation_functions(&self, ir: &mut String) -> Result<(), CodeGenError> {
185 if self.quotation_functions.is_empty() {
186 return Ok(());
187 }
188 writeln!(ir, "; Quotation functions")?;
189 ir.push_str(&self.quotation_functions);
190 writeln!(ir)?;
191 Ok(())
192 }
193
194 fn emit_ffi_c_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
195 if self.ffi_bindings.functions.is_empty() {
196 return Ok(());
197 }
198 writeln!(ir, "; FFI C function declarations")?;
199 writeln!(ir, "declare ptr @malloc(i64)")?;
200 writeln!(ir, "declare void @free(ptr)")?;
201 writeln!(ir, "declare i64 @strlen(ptr)")?;
202 writeln!(ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
203 writeln!(ir, "declare ptr @patch_seq_string_to_cstring(ptr, ptr)")?;
205 writeln!(ir, "declare ptr @patch_seq_cstring_to_string(ptr, ptr)")?;
206 for func in self.ffi_bindings.functions.values() {
207 let c_ret_type = ffi_return_type(&func.return_spec);
208 let c_args = ffi_c_args(&func.args);
209 writeln!(ir, "declare {} @{}({})", c_ret_type, func.c_name, c_args)?;
210 }
211 writeln!(ir)?;
212 Ok(())
213 }
214
215 fn emit_ffi_wrappers_section(&self, ir: &mut String) -> Result<(), CodeGenError> {
216 if self.ffi_wrapper_code.is_empty() {
217 return Ok(());
218 }
219 writeln!(ir, "; FFI wrapper functions")?;
220 ir.push_str(&self.ffi_wrapper_code);
221 writeln!(ir)?;
222 Ok(())
223 }
224
225 fn emit_instrumentation_globals(&self, ir: &mut String) -> Result<(), CodeGenError> {
230 let n = self.word_instrument_ids.len();
231 if n == 0 {
232 return Ok(());
233 }
234
235 writeln!(ir, "; Instrumentation globals (--instrument)")?;
236
237 writeln!(
238 ir,
239 "@seq_word_counters = global [{} x i64] zeroinitializer",
240 n
241 )?;
242
243 let mut words: Vec<(usize, &str)> = self
245 .word_instrument_ids
246 .iter()
247 .map(|(name, &id)| (id, name.as_str()))
248 .collect();
249 words.sort_by_key(|&(id, _)| id);
250
251 for &(id, name) in &words {
252 let name_bytes = name.as_bytes();
253 let len = name_bytes.len() + 1; let escaped: String = name_bytes
255 .iter()
256 .map(|&b| format!("\\{:02X}", b))
257 .collect::<String>();
258 writeln!(
259 ir,
260 "@seq_word_name_{} = private constant [{} x i8] c\"{}\\00\"",
261 id, len, escaped
262 )?;
263 }
264
265 let ptrs: Vec<String> = words
266 .iter()
267 .map(|&(id, _name)| format!("ptr @seq_word_name_{}", id))
268 .collect();
269 writeln!(
270 ir,
271 "@seq_word_names = private constant [{} x ptr] [{}]",
272 n,
273 ptrs.join(", ")
274 )?;
275
276 writeln!(ir)?;
277 Ok(())
278 }
279}