seqc/codegen/
program.rs

1//! Program Code Generation
2//!
3//! This module contains the main entry points for generating LLVM IR
4//! from a complete Seq program.
5
6use 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    /// Generate LLVM IR for entire program
18    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    /// Generate LLVM IR for entire program with custom configuration
33    ///
34    /// This allows external projects to extend the compiler with additional
35    /// builtins that will be declared and callable from Seq code.
36    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        // Store type map for use during code generation
44        self.type_map = type_map;
45        self.statement_types = statement_types;
46
47        // Store union definitions for pattern matching
48        self.unions = program.unions.clone();
49
50        // Build external builtins map from config
51        self.external_builtins = config
52            .external_builtins
53            .iter()
54            .map(|b| (b.seq_name.clone(), b.symbol.clone()))
55            .collect();
56
57        // Verify we have a main word
58        if program.find_word("main").is_none() {
59            return Err(CodeGenError::Logic("No main word defined".to_string()));
60        }
61
62        // Generate all user-defined words
63        for word in &program.words {
64            self.codegen_word(word)?;
65        }
66
67        // Generate main function
68        self.codegen_main()?;
69
70        // Assemble final IR
71        let mut ir = String::new();
72
73        // Target and type declarations
74        writeln!(&mut ir, "; ModuleID = 'main'")?;
75        writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
76        writeln!(&mut ir)?;
77
78        // Value type definition: Rust enum with #[repr(C)], 40 bytes
79        writeln!(&mut ir, "; Value type (Rust enum - 40 bytes)")?;
80        writeln!(&mut ir, "%Value = type {{ i64, i64, i64, i64, i64 }}")?;
81        writeln!(&mut ir)?;
82
83        // String and symbol constants
84        self.emit_string_and_symbol_globals(&mut ir)?;
85
86        // Runtime function declarations
87        emit_runtime_decls(&mut ir)?;
88
89        // External builtin declarations (from config)
90        if !self.external_builtins.is_empty() {
91            writeln!(&mut ir, "; External builtin declarations")?;
92            for symbol in self.external_builtins.values() {
93                // All external builtins follow the standard stack convention: ptr -> ptr
94                writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
95            }
96            writeln!(&mut ir)?;
97        }
98
99        // Quotation functions (generated from quotation literals)
100        if !self.quotation_functions.is_empty() {
101            writeln!(&mut ir, "; Quotation functions")?;
102            ir.push_str(&self.quotation_functions);
103            writeln!(&mut ir)?;
104        }
105
106        // User-defined words and main
107        ir.push_str(&self.output);
108
109        Ok(ir)
110    }
111
112    /// Generate LLVM IR for entire program with FFI support
113    ///
114    /// This is the main entry point for compiling programs that use FFI.
115    pub fn codegen_program_with_ffi(
116        &mut self,
117        program: &Program,
118        type_map: HashMap<usize, Type>,
119        statement_types: HashMap<(String, usize), Type>,
120        config: &CompilerConfig,
121        ffi_bindings: &FfiBindings,
122    ) -> Result<String, CodeGenError> {
123        // Store FFI bindings
124        self.ffi_bindings = ffi_bindings.clone();
125
126        // Generate FFI wrapper functions
127        self.generate_ffi_wrappers()?;
128
129        // Store type map for use during code generation
130        self.type_map = type_map;
131        self.statement_types = statement_types;
132
133        // Store union definitions for pattern matching
134        self.unions = program.unions.clone();
135
136        // Build external builtins map from config
137        self.external_builtins = config
138            .external_builtins
139            .iter()
140            .map(|b| (b.seq_name.clone(), b.symbol.clone()))
141            .collect();
142
143        // Verify we have a main word
144        if program.find_word("main").is_none() {
145            return Err(CodeGenError::Logic("No main word defined".to_string()));
146        }
147
148        // Generate all user-defined words
149        for word in &program.words {
150            self.codegen_word(word)?;
151        }
152
153        // Generate main function
154        self.codegen_main()?;
155
156        // Assemble final IR
157        let mut ir = String::new();
158
159        // Target and type declarations
160        writeln!(&mut ir, "; ModuleID = 'main'")?;
161        writeln!(&mut ir, "target triple = \"{}\"", get_target_triple())?;
162        writeln!(&mut ir)?;
163
164        // Value type definition: Rust enum with #[repr(C)], 40 bytes
165        writeln!(&mut ir, "; Value type (Rust enum - 40 bytes)")?;
166        writeln!(&mut ir, "%Value = type {{ i64, i64, i64, i64, i64 }}")?;
167        writeln!(&mut ir)?;
168
169        // String and symbol constants
170        self.emit_string_and_symbol_globals(&mut ir)?;
171
172        // Runtime function declarations (same as codegen_program_with_config)
173        self.emit_runtime_declarations(&mut ir)?;
174
175        // FFI C function declarations
176        if !self.ffi_bindings.functions.is_empty() {
177            writeln!(&mut ir, "; FFI C function declarations")?;
178            writeln!(&mut ir, "declare ptr @malloc(i64)")?;
179            writeln!(&mut ir, "declare void @free(ptr)")?;
180            writeln!(&mut ir, "declare i64 @strlen(ptr)")?;
181            writeln!(&mut ir, "declare ptr @memcpy(ptr, ptr, i64)")?;
182            // Declare FFI string helpers from runtime
183            writeln!(
184                &mut ir,
185                "declare ptr @patch_seq_string_to_cstring(ptr, ptr)"
186            )?;
187            writeln!(
188                &mut ir,
189                "declare ptr @patch_seq_cstring_to_string(ptr, ptr)"
190            )?;
191            for func in self.ffi_bindings.functions.values() {
192                let c_ret_type = ffi_return_type(&func.return_spec);
193                let c_args = ffi_c_args(&func.args);
194                writeln!(
195                    &mut ir,
196                    "declare {} @{}({})",
197                    c_ret_type, func.c_name, c_args
198                )?;
199            }
200            writeln!(&mut ir)?;
201        }
202
203        // External builtin declarations (from config)
204        if !self.external_builtins.is_empty() {
205            writeln!(&mut ir, "; External builtin declarations")?;
206            for symbol in self.external_builtins.values() {
207                writeln!(&mut ir, "declare ptr @{}(ptr)", symbol)?;
208            }
209            writeln!(&mut ir)?;
210        }
211
212        // FFI wrapper functions
213        if !self.ffi_wrapper_code.is_empty() {
214            writeln!(&mut ir, "; FFI wrapper functions")?;
215            ir.push_str(&self.ffi_wrapper_code);
216            writeln!(&mut ir)?;
217        }
218
219        // Quotation functions
220        if !self.quotation_functions.is_empty() {
221            writeln!(&mut ir, "; Quotation functions")?;
222            ir.push_str(&self.quotation_functions);
223            writeln!(&mut ir)?;
224        }
225
226        // User-defined words and main
227        ir.push_str(&self.output);
228
229        Ok(ir)
230    }
231
232    /// Emit runtime function declarations
233    pub(super) fn emit_runtime_declarations(&self, ir: &mut String) -> Result<(), CodeGenError> {
234        emit_runtime_decls(ir)
235    }
236}