logicaffeine_compile/codegen_c/
mod.rs1use std::collections::HashMap;
2use std::fmt::Write;
3
4use crate::analysis::TypeRegistry;
5use crate::ast::stmt::*;
6use crate::intern::{Interner, Symbol};
7
8pub(crate) mod runtime;
9pub(crate) mod types;
10pub(crate) mod emit;
11
12use runtime::C_RUNTIME;
13use types::{CType, CContext, c_type_str, c_type_str_resolved, resolve_type_expr,
14 resolve_type_expr_with_registry, field_type_to_ctype, escape_c_ident, infer_expr_type};
15use emit::{codegen_expr, codegen_stmt, codegen_literal};
16
17fn codegen_function(stmt: &Stmt, ctx: &mut CContext, output: &mut String) {
18 if let Stmt::FunctionDef { name, params, body, return_type, is_native, .. } = stmt {
19 if *is_native {
20 return;
21 }
22
23 let func_name = ctx.resolve(*name).to_string();
24
25 let ret_type = if let Some(rt) = return_type {
26 resolve_type_expr_with_registry(rt, ctx.interner, Some(ctx.registry))
27 } else {
28 CType::Void
29 };
30
31 ctx.funcs.insert(*name, ret_type.clone());
32
33 let mut param_strs = Vec::new();
34 let mut param_types = Vec::new();
35 for (param_name, param_type) in params {
36 let p_type = resolve_type_expr_with_registry(param_type, ctx.interner, Some(ctx.registry));
37 param_strs.push(format!("{} {}", c_type_str_resolved(&p_type, ctx.interner), ctx.resolve(*param_name)));
38 param_types.push((*param_name, p_type));
39 }
40
41 write!(output, "{} {}({})", c_type_str_resolved(&ret_type, ctx.interner), func_name, param_strs.join(", ")).unwrap();
42 writeln!(output, " {{").unwrap();
43
44 let saved_vars = ctx.vars.clone();
45 for (pname, ptype) in ¶m_types {
46 ctx.vars.insert(*pname, ptype.clone());
47 }
48
49 for s in *body {
50 codegen_stmt(s, ctx, output, 1);
51 }
52
53 ctx.vars = saved_vars;
54 writeln!(output, "}}\n").unwrap();
55 }
56}
57
58fn codegen_c_struct_defs(registry: &TypeRegistry, interner: &Interner, output: &mut String) {
63 use std::fmt::Write;
64 use std::collections::HashSet;
65
66 let struct_syms: Vec<Symbol> = registry.iter_types()
68 .filter_map(|(sym, td)| {
69 if matches!(td, crate::analysis::TypeDef::Struct { .. }) { Some(*sym) } else { None }
70 })
71 .collect();
72
73 let mut emitted: HashSet<Symbol> = HashSet::new();
75 let mut ordered: Vec<Symbol> = Vec::new();
76
77 fn field_deps(fields: &[crate::analysis::FieldDef], registry: &TypeRegistry) -> Vec<Symbol> {
78 fields.iter().filter_map(|f| {
79 if let crate::analysis::FieldType::Named(sym) = &f.ty {
80 if matches!(registry.get(*sym), Some(crate::analysis::TypeDef::Struct { .. })) {
81 return Some(*sym);
82 }
83 }
84 None
85 }).collect()
86 }
87
88 let mut remaining = struct_syms;
90 while !remaining.is_empty() {
91 let prev_len = remaining.len();
92 remaining.retain(|sym| {
93 if let Some(crate::analysis::TypeDef::Struct { fields, .. }) = registry.get(*sym) {
94 let deps = field_deps(fields, registry);
95 if deps.iter().all(|d| emitted.contains(d)) {
96 emitted.insert(*sym);
97 ordered.push(*sym);
98 return false; }
100 }
101 true
102 });
103 if remaining.len() == prev_len {
104 for sym in &remaining {
106 ordered.push(*sym);
107 }
108 break;
109 }
110 }
111
112 for sym in &ordered {
113 if let Some(crate::analysis::TypeDef::Struct { fields, .. }) = registry.get(*sym) {
114 let name = escape_c_ident(interner.resolve(*sym));
115 writeln!(output, "typedef struct {{").unwrap();
116 for field in fields {
117 let field_name = escape_c_ident(interner.resolve(field.name));
118 let ctype = field_type_to_ctype(&field.ty, interner, registry);
119 let type_str = c_type_str_resolved(&ctype, interner);
120 writeln!(output, " {} {};", type_str, field_name).unwrap();
121 }
122 writeln!(output, "}} {};\n", name).unwrap();
123 }
124 }
125}
126
127fn codegen_c_enum_defs(registry: &TypeRegistry, interner: &Interner, output: &mut String) {
128 use std::fmt::Write;
129 for (sym, typedef) in registry.iter_types() {
130 if let crate::analysis::TypeDef::Enum { variants, .. } = typedef {
131 let name = escape_c_ident(interner.resolve(*sym));
132
133 write!(output, "typedef enum {{ ").unwrap();
135 for (i, v) in variants.iter().enumerate() {
136 let vname = escape_c_ident(interner.resolve(v.name));
137 if i > 0 { write!(output, ", ").unwrap(); }
138 write!(output, "{}_{}", name, vname).unwrap();
139 }
140 writeln!(output, " }} {}_tag;\n", name).unwrap();
141
142 let has_data = variants.iter().any(|v| !v.fields.is_empty());
144
145 let is_recursive = variants.iter().any(|v| {
147 v.fields.iter().any(|f| {
148 if let crate::analysis::FieldType::Named(fsym) = &f.ty {
149 *fsym == *sym
150 } else {
151 false
152 }
153 })
154 });
155
156 if is_recursive {
157 writeln!(output, "typedef struct {} {};", name, name).unwrap();
158 }
159
160 if is_recursive {
161 writeln!(output, "struct {} {{", name).unwrap();
162 } else {
163 writeln!(output, "typedef struct {{").unwrap();
164 }
165 writeln!(output, " {}_tag tag;", name).unwrap();
166 if has_data {
167 writeln!(output, " union {{").unwrap();
168 for v in variants {
169 if v.fields.is_empty() { continue; }
170 let vname = escape_c_ident(interner.resolve(v.name));
171 writeln!(output, " struct {{").unwrap();
172 for f in &v.fields {
173 let fname = escape_c_ident(interner.resolve(f.name));
174 let is_self_ref = if let crate::analysis::FieldType::Named(fsym) = &f.ty {
175 *fsym == *sym
176 } else {
177 false
178 };
179 if is_self_ref {
180 writeln!(output, " {} *{};", name, fname).unwrap();
181 } else {
182 let ctype = field_type_to_ctype(&f.ty, interner, registry);
183 let type_str = c_type_str_resolved(&ctype, interner);
184 writeln!(output, " {} {};", type_str, fname).unwrap();
185 }
186 }
187 writeln!(output, " }} {};", vname).unwrap();
188 }
189 writeln!(output, " }} data;").unwrap();
190 }
191 if is_recursive {
192 writeln!(output, "}};\n").unwrap();
193 } else {
194 writeln!(output, "}} {};\n", name).unwrap();
195 }
196 }
197 }
198}
199
200pub fn codegen_program_c(stmts: &[Stmt], _registry: &TypeRegistry, interner: &Interner) -> String {
201 let mut output = String::with_capacity(4096);
202 let mut ctx = CContext::new(interner, _registry);
203
204 output.push_str(C_RUNTIME);
205
206 codegen_c_struct_defs(_registry, interner, &mut output);
208 codegen_c_enum_defs(_registry, interner, &mut output);
209
210 for stmt in stmts {
212 if let Stmt::FunctionDef { name, return_type, is_native, .. } = stmt {
213 if *is_native {
214 let fname = interner.resolve(*name);
215 let ret_type = match fname {
216 "args" => CType::SeqStr,
217 "parseInt" => CType::Int64,
218 "parseFloat" => CType::Float64,
219 _ => {
220 if let Some(rt) = return_type {
221 resolve_type_expr_with_registry(rt, interner, Some(_registry))
222 } else {
223 CType::Void
224 }
225 }
226 };
227 ctx.funcs.insert(*name, ret_type);
228 } else {
229 let ret_type = if let Some(rt) = return_type {
230 resolve_type_expr_with_registry(rt, interner, Some(_registry))
231 } else {
232 CType::Void
233 };
234 ctx.funcs.insert(*name, ret_type);
235 }
236 }
237 }
238
239 for stmt in stmts {
241 if let Stmt::FunctionDef { name, params, return_type, is_native, .. } = stmt {
242 if *is_native {
243 continue;
244 }
245 let func_name = ctx.resolve(*name).to_string();
246 let ret_type = if let Some(rt) = return_type {
247 resolve_type_expr_with_registry(rt, interner, Some(_registry))
248 } else {
249 CType::Void
250 };
251 let param_strs: Vec<String> = params.iter().map(|(pname, ptype)| {
252 let p_type = resolve_type_expr_with_registry(ptype, interner, Some(_registry));
253 format!("{} {}", c_type_str_resolved(&p_type, interner), ctx.resolve(*pname))
254 }).collect();
255 writeln!(output, "{} {}({});", c_type_str_resolved(&ret_type, interner), func_name, param_strs.join(", ")).unwrap();
256 }
257 }
258 output.push('\n');
259
260 for stmt in stmts {
262 if let Stmt::FunctionDef { is_native: false, .. } = stmt {
263 codegen_function(stmt, &mut ctx, &mut output);
264 }
265 }
266
267 writeln!(output, "int main(int argc, char **argv) {{").unwrap();
269 writeln!(output, " _logos_argc = argc;").unwrap();
270 writeln!(output, " _logos_argv = argv;").unwrap();
271
272 for stmt in stmts {
273 match stmt {
274 Stmt::FunctionDef { .. } => continue,
275 _ => codegen_stmt(stmt, &mut ctx, &mut output, 1),
276 }
277 }
278
279 writeln!(output, " return 0;").unwrap();
280 writeln!(output, "}}").unwrap();
281
282 output
283}