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 if program.find_word("main").is_none() {
59 return Err(CodeGenError::Logic("No main word defined".to_string()));
60 }
61
62 for word in &program.words {
64 self.codegen_word(word)?;
65 }
66
67 self.codegen_main()?;
69
70 let mut ir = String::new();
72
73 writeln!(&mut ir, "; ModuleID = 'main'")?;
75 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
76 writeln!(&mut ir)?;
77
78 #[cfg(not(feature = "nanbox"))]
80 {
81 writeln!(&mut ir, "; Value type (Rust enum - 40 bytes)")?;
83 writeln!(&mut ir, "%Value = type {{ i64, i64, i64, i64, i64 }}")?;
84 }
85 #[cfg(feature = "nanbox")]
86 {
87 writeln!(&mut ir, "; Value type (NaN-boxed - 8 bytes)")?;
89 writeln!(&mut ir, "%Value = type i64")?;
90 }
91 writeln!(&mut ir)?;
92
93 self.emit_string_and_symbol_globals(&mut ir)?;
95
96 emit_runtime_decls(&mut ir)?;
98
99 if !self.external_builtins.is_empty() {
101 writeln!(&mut ir, "; External builtin declarations")?;
102 for symbol in self.external_builtins.values() {
103 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
105 }
106 writeln!(&mut ir)?;
107 }
108
109 if !self.quotation_functions.is_empty() {
111 writeln!(&mut ir, "; Quotation functions")?;
112 ir.push_str(&self.quotation_functions);
113 writeln!(&mut ir)?;
114 }
115
116 ir.push_str(&self.output);
118
119 Ok(ir)
120 }
121
122 pub fn codegen_program_with_ffi(
126 &mut self,
127 program: &Program,
128 type_map: HashMap<usize, Type>,
129 statement_types: HashMap<(String, usize), Type>,
130 config: &CompilerConfig,
131 ffi_bindings: &FfiBindings,
132 ) -> Result<String, CodeGenError> {
133 self.ffi_bindings = ffi_bindings.clone();
135
136 self.generate_ffi_wrappers()?;
138
139 self.type_map = type_map;
141 self.statement_types = statement_types;
142
143 self.unions = program.unions.clone();
145
146 self.external_builtins = config
148 .external_builtins
149 .iter()
150 .map(|b| (b.seq_name.clone(), b.symbol.clone()))
151 .collect();
152
153 if program.find_word("main").is_none() {
155 return Err(CodeGenError::Logic("No main word defined".to_string()));
156 }
157
158 for word in &program.words {
160 self.codegen_word(word)?;
161 }
162
163 self.codegen_main()?;
165
166 let mut ir = String::new();
168
169 writeln!(&mut ir, "; ModuleID = 'main'")?;
171 writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
172 writeln!(&mut ir)?;
173
174 #[cfg(not(feature = "nanbox"))]
176 {
177 writeln!(&mut ir, "; Value type (Rust enum - 40 bytes)")?;
178 writeln!(&mut ir, "%Value = type {{ i64, i64, i64, i64, i64 }}")?;
179 }
180 #[cfg(feature = "nanbox")]
181 {
182 writeln!(&mut ir, "; Value type (NaN-boxed - 8 bytes)")?;
183 writeln!(&mut ir, "%Value = type i64")?;
184 }
185 writeln!(&mut ir)?;
186
187 self.emit_string_and_symbol_globals(&mut ir)?;
189
190 self.emit_runtime_declarations(&mut ir)?;
192
193 if !self.ffi_bindings.functions.is_empty() {
195 writeln!(&mut ir, "; FFI C function declarations")?;
196 writeln!(&mut ir, "declare ptr @malloc(i64)")?;
197 writeln!(&mut ir, "declare void @free(ptr)")?;
198 writeln!(&mut ir, "declare i64 @strlen(ptr)")?;
199 writeln!(&mut ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
200 writeln!(
202 &mut ir,
203 "declare ptr @patch_seq_string_to_cstring(ptr, ptr)"
204 )?;
205 writeln!(
206 &mut ir,
207 "declare ptr @patch_seq_cstring_to_string(ptr, ptr)"
208 )?;
209 for func in self.ffi_bindings.functions.values() {
210 let c_ret_type = ffi_return_type(&func.return_spec);
211 let c_args = ffi_c_args(&func.args);
212 writeln!(
213 &mut ir,
214 "declare {} @{}({})",
215 c_ret_type, func.c_name, c_args
216 )?;
217 }
218 writeln!(&mut ir)?;
219 }
220
221 if !self.external_builtins.is_empty() {
223 writeln!(&mut ir, "; External builtin declarations")?;
224 for symbol in self.external_builtins.values() {
225 writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
226 }
227 writeln!(&mut ir)?;
228 }
229
230 if !self.ffi_wrapper_code.is_empty() {
232 writeln!(&mut ir, "; FFI wrapper functions")?;
233 ir.push_str(&self.ffi_wrapper_code);
234 writeln!(&mut ir)?;
235 }
236
237 if !self.quotation_functions.is_empty() {
239 writeln!(&mut ir, "; Quotation functions")?;
240 ir.push_str(&self.quotation_functions);
241 writeln!(&mut ir)?;
242 }
243
244 ir.push_str(&self.output);
246
247 Ok(ir)
248 }
249
250 pub(super) fn emit_runtime_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
252 emit_runtime_decls(ir)
253 }
254}