Skip to main content

oxilean_codegen/c_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6use std::collections::{HashMap, HashSet};
7
8use super::functions::*;
9use std::collections::VecDeque;
10
11/// Helper to build indented C source text.
12pub struct CCodeWriter {
13    pub(super) buffer: String,
14    pub(super) indent_level: usize,
15    pub(super) indent_str: String,
16}
17impl CCodeWriter {
18    pub(super) fn new(indent_str: &str) -> Self {
19        CCodeWriter {
20            buffer: String::new(),
21            indent_level: 0,
22            indent_str: indent_str.to_string(),
23        }
24    }
25    pub(super) fn indent(&mut self) {
26        self.indent_level += 1;
27    }
28    pub(super) fn dedent(&mut self) {
29        if self.indent_level > 0 {
30            self.indent_level -= 1;
31        }
32    }
33    pub(super) fn write_indent(&mut self) {
34        for _ in 0..self.indent_level {
35            self.buffer.push_str(&self.indent_str);
36        }
37    }
38    pub(super) fn writeln(&mut self, line: &str) {
39        self.write_indent();
40        self.buffer.push_str(line);
41        self.buffer.push('\n');
42    }
43    pub(super) fn write_blank(&mut self) {
44        self.buffer.push('\n');
45    }
46    pub(super) fn result(&self) -> String {
47        self.buffer.clone()
48    }
49    pub(super) fn line_count(&self) -> usize {
50        self.buffer.lines().count()
51    }
52}
53/// Information about a closure struct.
54#[derive(Debug, Clone)]
55pub struct ClosureInfo {
56    /// Name of the closure struct type.
57    pub(super) struct_name: String,
58    /// The function pointer field name.
59    pub(super) fn_ptr_field: String,
60    /// Captured environment field names and types.
61    pub(super) env_fields: Vec<(String, CType)>,
62    /// Arity of the closure (number of explicit parameters).
63    pub(super) arity: usize,
64}
65/// Configuration for the C code emitter.
66#[derive(Debug, Clone)]
67pub struct CEmitConfig {
68    /// Whether to emit comments in the generated code.
69    pub emit_comments: bool,
70    /// Whether to inline small functions.
71    pub inline_small: bool,
72    /// Whether to emit reference counting operations.
73    pub use_rc: bool,
74    /// Indentation string (e.g. two spaces or a tab).
75    pub indent: String,
76    /// Module name for the header guard.
77    pub module_name: String,
78    /// Whether to emit `static` qualifiers for internal functions.
79    pub use_static: bool,
80}
81/// C expression for code generation.
82#[derive(Debug, Clone, PartialEq)]
83pub enum CExpr {
84    /// Variable reference.
85    Var(String),
86    /// Integer literal.
87    IntLit(i64),
88    /// Unsigned integer literal.
89    UIntLit(u64),
90    /// String literal.
91    StringLit(String),
92    /// Function call: `f(args...)`.
93    Call(String, Vec<CExpr>),
94    /// Binary operation: `lhs op rhs`.
95    BinOp(CBinOp, Box<CExpr>, Box<CExpr>),
96    /// Unary operation: `op expr`.
97    UnaryOp(CUnaryOp, Box<CExpr>),
98    /// Field access: `expr.field` or `expr->field`.
99    FieldAccess(Box<CExpr>, String, bool),
100    /// Array access: `expr[index]`.
101    ArrayAccess(Box<CExpr>, Box<CExpr>),
102    /// Cast: `(type)expr`.
103    Cast(CType, Box<CExpr>),
104    /// `sizeof(type)`.
105    SizeOf(CType),
106    /// `NULL`.
107    Null,
108    /// Ternary: `cond ? then : else`.
109    Ternary(Box<CExpr>, Box<CExpr>, Box<CExpr>),
110    /// Compound literal / initializer.
111    Initializer(CType, Vec<(String, CExpr)>),
112}
113impl CExpr {
114    /// Create a variable expression.
115    pub(super) fn var(name: &str) -> Self {
116        CExpr::Var(name.to_string())
117    }
118    /// Create a function call expression.
119    pub(super) fn call(name: &str, args: Vec<CExpr>) -> Self {
120        CExpr::Call(name.to_string(), args)
121    }
122    /// Create a field access (arrow style: `expr->field`).
123    pub(super) fn arrow(self, field: &str) -> Self {
124        CExpr::FieldAccess(Box::new(self), field.to_string(), true)
125    }
126    /// Create a field access (dot style: `expr.field`).
127    pub(super) fn dot(self, field: &str) -> Self {
128        CExpr::FieldAccess(Box::new(self), field.to_string(), false)
129    }
130    /// Create a binary operation.
131    pub(super) fn binop(op: CBinOp, lhs: CExpr, rhs: CExpr) -> Self {
132        CExpr::BinOp(op, Box::new(lhs), Box::new(rhs))
133    }
134}
135#[allow(dead_code)]
136#[derive(Debug, Clone)]
137pub struct CBPassConfig {
138    pub phase: CBPassPhase,
139    pub enabled: bool,
140    pub max_iterations: u32,
141    pub debug_output: bool,
142    pub pass_name: String,
143}
144impl CBPassConfig {
145    #[allow(dead_code)]
146    pub fn new(name: impl Into<String>, phase: CBPassPhase) -> Self {
147        CBPassConfig {
148            phase,
149            enabled: true,
150            max_iterations: 10,
151            debug_output: false,
152            pass_name: name.into(),
153        }
154    }
155    #[allow(dead_code)]
156    pub fn disabled(mut self) -> Self {
157        self.enabled = false;
158        self
159    }
160    #[allow(dead_code)]
161    pub fn with_debug(mut self) -> Self {
162        self.debug_output = true;
163        self
164    }
165    #[allow(dead_code)]
166    pub fn max_iter(mut self, n: u32) -> Self {
167        self.max_iterations = n;
168        self
169    }
170}
171#[allow(dead_code)]
172#[derive(Debug, Clone, Default)]
173pub struct CBPassStats {
174    pub total_runs: u32,
175    pub successful_runs: u32,
176    pub total_changes: u64,
177    pub time_ms: u64,
178    pub iterations_used: u32,
179}
180impl CBPassStats {
181    #[allow(dead_code)]
182    pub fn new() -> Self {
183        Self::default()
184    }
185    #[allow(dead_code)]
186    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
187        self.total_runs += 1;
188        self.successful_runs += 1;
189        self.total_changes += changes;
190        self.time_ms += time_ms;
191        self.iterations_used = iterations;
192    }
193    #[allow(dead_code)]
194    pub fn average_changes_per_run(&self) -> f64 {
195        if self.total_runs == 0 {
196            return 0.0;
197        }
198        self.total_changes as f64 / self.total_runs as f64
199    }
200    #[allow(dead_code)]
201    pub fn success_rate(&self) -> f64 {
202        if self.total_runs == 0 {
203            return 0.0;
204        }
205        self.successful_runs as f64 / self.total_runs as f64
206    }
207    #[allow(dead_code)]
208    pub fn format_summary(&self) -> String {
209        format!(
210            "Runs: {}/{}, Changes: {}, Time: {}ms",
211            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
212        )
213    }
214}
215/// Binary operator in C expressions.
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
217pub enum CBinOp {
218    Add,
219    Sub,
220    Mul,
221    Div,
222    Mod,
223    Eq,
224    Neq,
225    Lt,
226    Le,
227    Gt,
228    Ge,
229    And,
230    Or,
231    BitAnd,
232    BitOr,
233    BitXor,
234    Shl,
235    Shr,
236}
237/// Analyze an LCNF expression to determine which variables need RC operations,
238/// and return the expression annotated with inc/dec ref calls (as C statements).
239struct RcInserter {
240    /// Variables that are "live" (have been inc-refed and need dec-ref).
241    pub(super) live_vars: HashMap<LcnfVarId, LcnfType>,
242    /// Which variables have been consumed (ownership transferred).
243    pub(super) consumed: HashSet<LcnfVarId>,
244}
245impl RcInserter {
246    pub(super) fn new() -> Self {
247        RcInserter {
248            live_vars: HashMap::new(),
249            consumed: HashSet::new(),
250        }
251    }
252    /// Mark a variable as live (holding a reference).
253    pub(super) fn mark_live(&mut self, id: LcnfVarId, ty: LcnfType) {
254        if !is_scalar_type(&ty) {
255            self.live_vars.insert(id, ty);
256        }
257    }
258    /// Mark a variable as consumed (ownership transferred).
259    pub(super) fn mark_consumed(&mut self, id: LcnfVarId) {
260        self.consumed.insert(id);
261    }
262    /// Generate dec-ref statements for all live, unconsumed variables.
263    pub(super) fn gen_dec_refs(&self) -> Vec<CStmt> {
264        let mut stmts = Vec::new();
265        for (id, ty) in &self.live_vars {
266            if !self.consumed.contains(id) && !is_scalar_type(ty) {
267                stmts.push(lean_dec_ref(&var_name(*id)));
268            }
269        }
270        stmts
271    }
272    /// Generate inc-ref for a variable if it is used multiple times.
273    pub(super) fn gen_inc_ref_if_shared(&self, id: LcnfVarId, use_count: usize) -> Vec<CStmt> {
274        let mut stmts = Vec::new();
275        if use_count > 1 {
276            if let Some(ty) = self.live_vars.get(&id) {
277                if !is_scalar_type(ty) {
278                    for _ in 0..use_count - 1 {
279                        stmts.push(lean_inc_ref(&var_name(id)));
280                    }
281                }
282            }
283        }
284        stmts
285    }
286}
287#[allow(dead_code)]
288pub struct CBPassRegistry {
289    pub(super) configs: Vec<CBPassConfig>,
290    pub(super) stats: std::collections::HashMap<String, CBPassStats>,
291}
292impl CBPassRegistry {
293    #[allow(dead_code)]
294    pub fn new() -> Self {
295        CBPassRegistry {
296            configs: Vec::new(),
297            stats: std::collections::HashMap::new(),
298        }
299    }
300    #[allow(dead_code)]
301    pub fn register(&mut self, config: CBPassConfig) {
302        self.stats
303            .insert(config.pass_name.clone(), CBPassStats::new());
304        self.configs.push(config);
305    }
306    #[allow(dead_code)]
307    pub fn enabled_passes(&self) -> Vec<&CBPassConfig> {
308        self.configs.iter().filter(|c| c.enabled).collect()
309    }
310    #[allow(dead_code)]
311    pub fn get_stats(&self, name: &str) -> Option<&CBPassStats> {
312        self.stats.get(name)
313    }
314    #[allow(dead_code)]
315    pub fn total_passes(&self) -> usize {
316        self.configs.len()
317    }
318    #[allow(dead_code)]
319    pub fn enabled_count(&self) -> usize {
320        self.enabled_passes().len()
321    }
322    #[allow(dead_code)]
323    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
324        if let Some(stats) = self.stats.get_mut(name) {
325            stats.record_run(changes, time_ms, iter);
326        }
327    }
328}
329#[allow(dead_code)]
330#[derive(Debug, Clone)]
331pub struct CBWorklist {
332    pub(super) items: std::collections::VecDeque<u32>,
333    pub(super) in_worklist: std::collections::HashSet<u32>,
334}
335impl CBWorklist {
336    #[allow(dead_code)]
337    pub fn new() -> Self {
338        CBWorklist {
339            items: std::collections::VecDeque::new(),
340            in_worklist: std::collections::HashSet::new(),
341        }
342    }
343    #[allow(dead_code)]
344    pub fn push(&mut self, item: u32) -> bool {
345        if self.in_worklist.insert(item) {
346            self.items.push_back(item);
347            true
348        } else {
349            false
350        }
351    }
352    #[allow(dead_code)]
353    pub fn pop(&mut self) -> Option<u32> {
354        let item = self.items.pop_front()?;
355        self.in_worklist.remove(&item);
356        Some(item)
357    }
358    #[allow(dead_code)]
359    pub fn is_empty(&self) -> bool {
360        self.items.is_empty()
361    }
362    #[allow(dead_code)]
363    pub fn len(&self) -> usize {
364        self.items.len()
365    }
366    #[allow(dead_code)]
367    pub fn contains(&self, item: u32) -> bool {
368        self.in_worklist.contains(&item)
369    }
370}
371#[allow(dead_code)]
372#[derive(Debug, Clone)]
373pub struct CBLivenessInfo {
374    pub live_in: Vec<std::collections::HashSet<u32>>,
375    pub live_out: Vec<std::collections::HashSet<u32>>,
376    pub defs: Vec<std::collections::HashSet<u32>>,
377    pub uses: Vec<std::collections::HashSet<u32>>,
378}
379impl CBLivenessInfo {
380    #[allow(dead_code)]
381    pub fn new(block_count: usize) -> Self {
382        CBLivenessInfo {
383            live_in: vec![std::collections::HashSet::new(); block_count],
384            live_out: vec![std::collections::HashSet::new(); block_count],
385            defs: vec![std::collections::HashSet::new(); block_count],
386            uses: vec![std::collections::HashSet::new(); block_count],
387        }
388    }
389    #[allow(dead_code)]
390    pub fn add_def(&mut self, block: usize, var: u32) {
391        if block < self.defs.len() {
392            self.defs[block].insert(var);
393        }
394    }
395    #[allow(dead_code)]
396    pub fn add_use(&mut self, block: usize, var: u32) {
397        if block < self.uses.len() {
398            self.uses[block].insert(var);
399        }
400    }
401    #[allow(dead_code)]
402    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
403        self.live_in
404            .get(block)
405            .map(|s| s.contains(&var))
406            .unwrap_or(false)
407    }
408    #[allow(dead_code)]
409    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
410        self.live_out
411            .get(block)
412            .map(|s| s.contains(&var))
413            .unwrap_or(false)
414    }
415}
416/// The output of C code generation.
417#[derive(Debug, Clone)]
418pub struct COutput {
419    /// The `.h` header content.
420    pub header: String,
421    /// The `.c` source content.
422    pub source: String,
423    /// The collected declarations.
424    pub declarations: Vec<CDecl>,
425}
426impl COutput {
427    pub(super) fn new() -> Self {
428        COutput {
429            header: String::new(),
430            source: String::new(),
431            declarations: Vec::new(),
432        }
433    }
434}
435#[allow(dead_code)]
436#[derive(Debug, Clone, PartialEq)]
437pub enum CBPassPhase {
438    Analysis,
439    Transformation,
440    Verification,
441    Cleanup,
442}
443impl CBPassPhase {
444    #[allow(dead_code)]
445    pub fn name(&self) -> &str {
446        match self {
447            CBPassPhase::Analysis => "analysis",
448            CBPassPhase::Transformation => "transformation",
449            CBPassPhase::Verification => "verification",
450            CBPassPhase::Cleanup => "cleanup",
451        }
452    }
453    #[allow(dead_code)]
454    pub fn is_modifying(&self) -> bool {
455        matches!(self, CBPassPhase::Transformation | CBPassPhase::Cleanup)
456    }
457}
458/// Information about a generated struct's layout.
459#[derive(Debug, Clone)]
460pub struct StructLayout {
461    /// Name of the struct.
462    pub name: String,
463    /// Fields with their offsets.
464    pub fields: Vec<(String, CType, usize)>,
465    /// Total size of the struct.
466    pub total_size: usize,
467    /// Required alignment.
468    pub alignment: usize,
469}
470#[allow(dead_code)]
471#[derive(Debug, Clone)]
472pub struct CBDepGraph {
473    pub(super) nodes: Vec<u32>,
474    pub(super) edges: Vec<(u32, u32)>,
475}
476impl CBDepGraph {
477    #[allow(dead_code)]
478    pub fn new() -> Self {
479        CBDepGraph {
480            nodes: Vec::new(),
481            edges: Vec::new(),
482        }
483    }
484    #[allow(dead_code)]
485    pub fn add_node(&mut self, id: u32) {
486        if !self.nodes.contains(&id) {
487            self.nodes.push(id);
488        }
489    }
490    #[allow(dead_code)]
491    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
492        self.add_node(dep);
493        self.add_node(dependent);
494        self.edges.push((dep, dependent));
495    }
496    #[allow(dead_code)]
497    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
498        self.edges
499            .iter()
500            .filter(|(d, _)| *d == node)
501            .map(|(_, dep)| *dep)
502            .collect()
503    }
504    #[allow(dead_code)]
505    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
506        self.edges
507            .iter()
508            .filter(|(_, dep)| *dep == node)
509            .map(|(d, _)| *d)
510            .collect()
511    }
512    #[allow(dead_code)]
513    pub fn topological_sort(&self) -> Vec<u32> {
514        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
515        for &n in &self.nodes {
516            in_degree.insert(n, 0);
517        }
518        for (_, dep) in &self.edges {
519            *in_degree.entry(*dep).or_insert(0) += 1;
520        }
521        let mut queue: std::collections::VecDeque<u32> = self
522            .nodes
523            .iter()
524            .filter(|&&n| in_degree[&n] == 0)
525            .copied()
526            .collect();
527        let mut result = Vec::new();
528        while let Some(node) = queue.pop_front() {
529            result.push(node);
530            for dep in self.dependents_of(node) {
531                let cnt = in_degree.entry(dep).or_insert(0);
532                *cnt = cnt.saturating_sub(1);
533                if *cnt == 0 {
534                    queue.push_back(dep);
535                }
536            }
537        }
538        result
539    }
540    #[allow(dead_code)]
541    pub fn has_cycle(&self) -> bool {
542        self.topological_sort().len() < self.nodes.len()
543    }
544}
545/// A top-level C declaration.
546#[derive(Debug, Clone, PartialEq)]
547pub enum CDecl {
548    /// Function definition.
549    Function {
550        ret_type: CType,
551        name: String,
552        params: Vec<(CType, String)>,
553        body: Vec<CStmt>,
554        is_static: bool,
555    },
556    /// Struct definition.
557    Struct {
558        name: String,
559        fields: Vec<(CType, String)>,
560    },
561    /// Typedef.
562    Typedef { original: CType, alias: String },
563    /// Global variable.
564    Global {
565        ty: CType,
566        name: String,
567        init: Option<CExpr>,
568        is_static: bool,
569    },
570    /// Forward declaration (function prototype).
571    ForwardDecl {
572        ret_type: CType,
573        name: String,
574        params: Vec<(CType, String)>,
575    },
576}
577/// C type representation for code generation.
578#[derive(Debug, Clone, PartialEq, Eq, Hash)]
579pub enum CType {
580    /// `void`
581    Void,
582    /// `int64_t`
583    Int,
584    /// `uint64_t`
585    UInt,
586    /// `uint8_t` (boolean)
587    Bool,
588    /// `char`
589    Char,
590    /// Pointer: `T*`
591    Ptr(Box<CType>),
592    /// Named struct: `struct Foo`
593    Struct(String),
594    /// Function pointer: `ret (*)(params...)`
595    FnPtr(Vec<CType>, Box<CType>),
596    /// Fixed-size array: `T[N]`
597    Array(Box<CType>, usize),
598    /// `size_t`
599    SizeT,
600    /// `uint8_t`
601    U8,
602    /// `lean_object*` — the universal OxiLean object type
603    LeanObject,
604}
605#[allow(dead_code)]
606#[derive(Debug, Clone)]
607pub struct CBAnalysisCache {
608    pub(super) entries: std::collections::HashMap<String, CBCacheEntry>,
609    pub(super) max_size: usize,
610    pub(super) hits: u64,
611    pub(super) misses: u64,
612}
613impl CBAnalysisCache {
614    #[allow(dead_code)]
615    pub fn new(max_size: usize) -> Self {
616        CBAnalysisCache {
617            entries: std::collections::HashMap::new(),
618            max_size,
619            hits: 0,
620            misses: 0,
621        }
622    }
623    #[allow(dead_code)]
624    pub fn get(&mut self, key: &str) -> Option<&CBCacheEntry> {
625        if self.entries.contains_key(key) {
626            self.hits += 1;
627            self.entries.get(key)
628        } else {
629            self.misses += 1;
630            None
631        }
632    }
633    #[allow(dead_code)]
634    pub fn insert(&mut self, key: String, data: Vec<u8>) {
635        if self.entries.len() >= self.max_size {
636            if let Some(oldest) = self.entries.keys().next().cloned() {
637                self.entries.remove(&oldest);
638            }
639        }
640        self.entries.insert(
641            key.clone(),
642            CBCacheEntry {
643                key,
644                data,
645                timestamp: 0,
646                valid: true,
647            },
648        );
649    }
650    #[allow(dead_code)]
651    pub fn invalidate(&mut self, key: &str) {
652        if let Some(entry) = self.entries.get_mut(key) {
653            entry.valid = false;
654        }
655    }
656    #[allow(dead_code)]
657    pub fn clear(&mut self) {
658        self.entries.clear();
659    }
660    #[allow(dead_code)]
661    pub fn hit_rate(&self) -> f64 {
662        let total = self.hits + self.misses;
663        if total == 0 {
664            return 0.0;
665        }
666        self.hits as f64 / total as f64
667    }
668    #[allow(dead_code)]
669    pub fn size(&self) -> usize {
670        self.entries.len()
671    }
672}
673/// Unary operator in C expressions.
674#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
675pub enum CUnaryOp {
676    Neg,
677    Not,
678    BitNot,
679    Deref,
680    AddrOf,
681}
682/// The C code generation backend.
683///
684/// Translates an LCNF module into C99 source code with Lean-compatible
685/// runtime support.
686pub struct CBackend {
687    pub(super) config: CEmitConfig,
688    pub(super) stats: CEmitStats,
689    /// Struct declarations generated so far (name -> fields).
690    pub(super) struct_decls: HashMap<String, Vec<(CType, String)>>,
691    /// Forward declarations needed.
692    pub(super) forward_decls: Vec<CDecl>,
693    /// Counter for generating unique temporary names.
694    pub(super) temp_counter: usize,
695    /// Mapping from LCNF function names to mangled C names.
696    pub(super) name_map: HashMap<String, String>,
697    /// Set of functions that are known to be used as closures.
698    pub(super) closure_functions: HashSet<String>,
699}
700impl CBackend {
701    /// Create a new C backend with the given configuration.
702    pub fn new(config: CEmitConfig) -> Self {
703        CBackend {
704            config,
705            stats: CEmitStats::default(),
706            struct_decls: HashMap::new(),
707            forward_decls: Vec::new(),
708            temp_counter: 0,
709            name_map: HashMap::new(),
710            closure_functions: HashSet::new(),
711        }
712    }
713    /// Create a C backend with default configuration.
714    pub fn default_backend() -> Self {
715        Self::new(CEmitConfig::default())
716    }
717    /// Get a fresh temporary variable name.
718    pub(super) fn fresh_temp(&mut self) -> String {
719        let name = format!("_t{}", self.temp_counter);
720        self.temp_counter += 1;
721        name
722    }
723    /// Get the mangled C name for an LCNF name.
724    pub(super) fn get_c_name(&mut self, lcnf_name: &str) -> String {
725        if let Some(name) = self.name_map.get(lcnf_name) {
726            return name.clone();
727        }
728        let mangled = mangle_name(lcnf_name);
729        self.name_map.insert(lcnf_name.to_string(), mangled.clone());
730        mangled
731    }
732    /// Emit a complete LCNF module to C code.
733    pub fn emit_module(&mut self, module: &LcnfModule) -> COutput {
734        let mut output = COutput::new();
735        let mut decls: Vec<CDecl> = Vec::new();
736        for fun in &module.fun_decls {
737            let c_name = self.get_c_name(&fun.name);
738            let c_params = self.emit_params(&fun.params);
739            let c_ret = lcnf_type_to_ctype(&fun.ret_type);
740            decls.push(CDecl::ForwardDecl {
741                ret_type: c_ret,
742                name: c_name,
743                params: c_params,
744            });
745        }
746        for ext in &module.extern_decls {
747            let c_name = self.get_c_name(&ext.name);
748            let c_params = self.emit_params(&ext.params);
749            let c_ret = lcnf_type_to_ctype(&ext.ret_type);
750            decls.push(CDecl::ForwardDecl {
751                ret_type: c_ret,
752                name: c_name,
753                params: c_params,
754            });
755        }
756        for fun in &module.fun_decls {
757            let fun_decl = self.emit_fun_decl(fun);
758            decls.push(fun_decl);
759        }
760        let mut header_writer = CCodeWriter::new(&self.config.indent);
761        let guard = format!(
762            "{}_H",
763            self.config.module_name.to_uppercase().replace('.', "_")
764        );
765        header_writer.writeln(&format!("#ifndef {}", guard));
766        header_writer.writeln(&format!("#define {}", guard));
767        header_writer.write_blank();
768        header_writer.writeln("#include <stdint.h>");
769        header_writer.writeln("#include <stddef.h>");
770        header_writer.writeln("#include \"lean_runtime.h\"");
771        header_writer.write_blank();
772        for name in self.struct_decls.keys() {
773            header_writer.writeln(&format!("struct {};", name));
774        }
775        header_writer.write_blank();
776        for (name, fields) in &self.struct_decls {
777            let struct_decl = CDecl::Struct {
778                name: name.clone(),
779                fields: fields.clone(),
780            };
781            emit_decl(&mut header_writer, &struct_decl);
782        }
783        for d in &decls {
784            if let CDecl::ForwardDecl { .. } = d {
785                emit_decl(&mut header_writer, d);
786            }
787        }
788        header_writer.write_blank();
789        header_writer.writeln(&format!("#endif /* {} */", guard));
790        output.header = header_writer.result();
791        let mut source_writer = CCodeWriter::new(&self.config.indent);
792        source_writer.writeln(&format!("#include \"{}.h\"", self.config.module_name));
793        source_writer.write_blank();
794        for d in &decls {
795            if let CDecl::Function { .. } = d {
796                emit_decl(&mut source_writer, d);
797            }
798        }
799        self.stats.total_lines = source_writer.line_count() + header_writer.line_count();
800        output.source = source_writer.result();
801        output.declarations = decls;
802        output
803    }
804    /// Emit an LCNF function declaration as a C function.
805    pub fn emit_fun_decl(&mut self, decl: &LcnfFunDecl) -> CDecl {
806        let c_name = self.get_c_name(&decl.name);
807        let c_params = self.emit_params(&decl.params);
808        let c_ret = lcnf_type_to_ctype(&decl.ret_type);
809        let mut body_stmts = Vec::new();
810        if self.config.emit_comments {
811            body_stmts.push(CStmt::Comment(format!(
812                "Function: {} (recursive={})",
813                decl.name, decl.is_recursive
814            )));
815        }
816        let expr_stmts = self.emit_expr(&decl.body, &decl.ret_type);
817        body_stmts.extend(expr_stmts);
818        self.stats.functions_emitted += 1;
819        CDecl::Function {
820            ret_type: c_ret,
821            name: c_name,
822            params: c_params,
823            body: body_stmts,
824            is_static: decl.is_lifted && self.config.use_static,
825        }
826    }
827    /// Convert LCNF parameters to C function parameters.
828    pub(super) fn emit_params(&self, params: &[LcnfParam]) -> Vec<(CType, String)> {
829        params
830            .iter()
831            .filter(|p| !p.erased)
832            .map(|p| (lcnf_type_to_ctype(&p.ty), var_name(p.id)))
833            .collect()
834    }
835    /// Map an LCNF type to a C type (public interface).
836    pub fn emit_type(&self, ty: &LcnfType) -> CType {
837        lcnf_type_to_ctype(ty)
838    }
839    /// Emit C statements for an LCNF expression.
840    pub fn emit_expr(&mut self, expr: &LcnfExpr, ret_ty: &LcnfType) -> Vec<CStmt> {
841        match expr {
842            LcnfExpr::Let {
843                id,
844                name,
845                ty,
846                value,
847                body,
848            } => {
849                let mut stmts = Vec::new();
850                let c_ty = lcnf_type_to_ctype(ty);
851                let c_name = var_name(*id);
852                if self.config.emit_comments && !name.is_empty() {
853                    stmts.push(CStmt::Comment(format!("{} : {}", name, ty)));
854                }
855                let (init_stmts, init_expr) = self.emit_let_value(value, ty);
856                stmts.extend(init_stmts);
857                stmts.push(CStmt::VarDecl {
858                    ty: c_ty,
859                    name: c_name,
860                    init: Some(init_expr),
861                });
862                let body_stmts = self.emit_expr(body, ret_ty);
863                stmts.extend(body_stmts);
864                stmts
865            }
866            LcnfExpr::Case {
867                scrutinee,
868                scrutinee_ty,
869                alts,
870                default,
871            } => {
872                let mut stmts = Vec::new();
873                let scrut_name = var_name(*scrutinee);
874                if is_scalar_type(scrutinee_ty) {
875                    stmts.extend(self.emit_scalar_case(&scrut_name, alts, default, ret_ty));
876                } else {
877                    let tag_var = self.fresh_temp();
878                    stmts.push(CStmt::VarDecl {
879                        ty: CType::U8,
880                        name: tag_var.clone(),
881                        init: Some(lean_obj_tag(&scrut_name)),
882                    });
883                    let mut cases: Vec<(u32, Vec<CStmt>)> = Vec::new();
884                    for alt in alts {
885                        let mut case_body = Vec::new();
886                        if self.config.emit_comments {
887                            case_body.push(CStmt::Comment(format!(
888                                "Constructor: {}#{}",
889                                alt.ctor_name, alt.ctor_tag
890                            )));
891                        }
892                        for (i, param) in alt.params.iter().enumerate() {
893                            if param.erased {
894                                continue;
895                            }
896                            let field_ty = lcnf_type_to_ctype(&param.ty);
897                            let field_name = var_name(param.id);
898                            case_body.push(CStmt::VarDecl {
899                                ty: field_ty.clone(),
900                                name: field_name.clone(),
901                                init: Some(lean_ctor_get(&scrut_name, i)),
902                            });
903                            if self.config.use_rc && needs_rc(&field_ty) {
904                                case_body.push(lean_inc_ref(&field_name));
905                                self.stats.rc_inc_calls += 1;
906                            }
907                        }
908                        let branch_stmts = self.emit_expr(&alt.body, ret_ty);
909                        case_body.extend(branch_stmts);
910                        cases.push((alt.ctor_tag, case_body));
911                    }
912                    let default_body = if let Some(def) = default {
913                        self.emit_expr(def, ret_ty)
914                    } else {
915                        vec![CStmt::Expr(CExpr::call(
916                            "lean_internal_panic_unreachable",
917                            vec![],
918                        ))]
919                    };
920                    stmts.push(CStmt::Switch {
921                        scrutinee: CExpr::var(&tag_var),
922                        cases,
923                        default: default_body,
924                    });
925                    self.stats.switches_emitted += 1;
926                }
927                if self.config.use_rc && !is_scalar_type(scrutinee_ty) {
928                    stmts.push(lean_dec_ref(&scrut_name));
929                    self.stats.rc_dec_calls += 1;
930                }
931                stmts
932            }
933            LcnfExpr::Return(arg) => {
934                let c_expr = self.emit_arg(arg);
935                vec![CStmt::Return(Some(c_expr))]
936            }
937            LcnfExpr::Unreachable => {
938                vec![
939                    CStmt::Expr(CExpr::call("lean_internal_panic_unreachable", vec![])),
940                    CStmt::Return(Some(CExpr::Null)),
941                ]
942            }
943            LcnfExpr::TailCall(func, args) => {
944                let c_func = self.emit_arg(func);
945                let c_args: Vec<CExpr> = args.iter().map(|a| self.emit_arg(a)).collect();
946                let call_expr = match c_func {
947                    CExpr::Var(name) => CExpr::Call(name, c_args),
948                    _ => {
949                        let tmp = self.fresh_temp();
950                        return vec![
951                            CStmt::Comment("Indirect tail call".to_string()),
952                            CStmt::Return(Some(CExpr::Call(tmp, c_args))),
953                        ];
954                    }
955                };
956                vec![CStmt::Return(Some(call_expr))]
957            }
958        }
959    }
960    /// Emit a scalar case (if-else chain) for Nat / simple types.
961    pub(super) fn emit_scalar_case(
962        &mut self,
963        scrut_name: &str,
964        alts: &[LcnfAlt],
965        default: &Option<Box<LcnfExpr>>,
966        ret_ty: &LcnfType,
967    ) -> Vec<CStmt> {
968        let mut stmts = Vec::new();
969        if alts.is_empty() {
970            if let Some(def) = default {
971                stmts.extend(self.emit_expr(def, ret_ty));
972            } else {
973                stmts.push(CStmt::Expr(CExpr::call(
974                    "lean_internal_panic_unreachable",
975                    vec![],
976                )));
977            }
978            return stmts;
979        }
980        let mut remaining = alts.to_vec();
981        remaining.reverse();
982        let first = remaining
983            .pop()
984            .expect("alts is non-empty after reverse; guaranteed by caller");
985        let mut result = {
986            let cond = CExpr::binop(
987                CBinOp::Eq,
988                CExpr::var(scrut_name),
989                CExpr::UIntLit(first.ctor_tag as u64),
990            );
991            let then_body = self.emit_expr(&first.body, ret_ty);
992            let else_body = if remaining.is_empty() {
993                if let Some(def) = default {
994                    self.emit_expr(def, ret_ty)
995                } else {
996                    vec![CStmt::Expr(CExpr::call(
997                        "lean_internal_panic_unreachable",
998                        vec![],
999                    ))]
1000                }
1001            } else {
1002                Vec::new()
1003            };
1004            CStmt::If {
1005                cond,
1006                then_body,
1007                else_body,
1008            }
1009        };
1010        while let Some(alt) = remaining.pop() {
1011            let cond = CExpr::binop(
1012                CBinOp::Eq,
1013                CExpr::var(scrut_name),
1014                CExpr::UIntLit(alt.ctor_tag as u64),
1015            );
1016            let then_body = self.emit_expr(&alt.body, ret_ty);
1017            let else_body = if remaining.is_empty() {
1018                if let Some(def) = default {
1019                    self.emit_expr(def, ret_ty)
1020                } else {
1021                    vec![result]
1022                }
1023            } else {
1024                vec![result]
1025            };
1026            result = CStmt::If {
1027                cond,
1028                then_body,
1029                else_body,
1030            };
1031        }
1032        stmts.push(result);
1033        stmts
1034    }
1035    /// Emit a let-value, returning any setup statements and the final expression.
1036    pub(super) fn emit_let_value(
1037        &mut self,
1038        value: &LcnfLetValue,
1039        _ty: &LcnfType,
1040    ) -> (Vec<CStmt>, CExpr) {
1041        match value {
1042            LcnfLetValue::App(func, args) => {
1043                let c_func = self.emit_arg(func);
1044                let c_args: Vec<CExpr> = args.iter().map(|a| self.emit_arg(a)).collect();
1045                let call = match c_func {
1046                    CExpr::Var(name) => CExpr::Call(name, c_args),
1047                    _ => {
1048                        let tmp = self.fresh_temp();
1049                        let stmts = gen_closure_apply("_closure", &c_args, &tmp);
1050                        return (stmts, CExpr::var(&tmp));
1051                    }
1052                };
1053                (Vec::new(), call)
1054            }
1055            LcnfLetValue::Proj(_name, idx, var) => {
1056                let obj = var_name(*var);
1057                (Vec::new(), lean_ctor_get(&obj, *idx as usize))
1058            }
1059            LcnfLetValue::Ctor(name, tag, args) => {
1060                let mut stmts = Vec::new();
1061                let num_objs = args.len();
1062                let ctor_var = self.fresh_temp();
1063                stmts.push(CStmt::VarDecl {
1064                    ty: CType::LeanObject,
1065                    name: ctor_var.clone(),
1066                    init: Some(lean_alloc_ctor(*tag, num_objs, 0)),
1067                });
1068                for (i, arg) in args.iter().enumerate() {
1069                    let c_arg = self.emit_arg(arg);
1070                    stmts.push(lean_ctor_set(&ctor_var, i, c_arg));
1071                }
1072                if self.config.emit_comments {
1073                    stmts.insert(0, CStmt::Comment(format!("Construct {}#{}", name, tag)));
1074                }
1075                (stmts, CExpr::var(&ctor_var))
1076            }
1077            LcnfLetValue::Lit(lit) => {
1078                let c_expr = match lit {
1079                    LcnfLit::Nat(n) => CExpr::UIntLit(*n),
1080                    LcnfLit::Str(s) => {
1081                        CExpr::call("lean_mk_string", vec![CExpr::StringLit(s.clone())])
1082                    }
1083                };
1084                (Vec::new(), c_expr)
1085            }
1086            LcnfLetValue::Erased => (Vec::new(), lean_box(CExpr::UIntLit(0))),
1087            LcnfLetValue::FVar(var) => (Vec::new(), CExpr::var(&var_name(*var))),
1088            LcnfLetValue::Reset(var) => (
1089                Vec::new(),
1090                CExpr::call("lean_obj_reset", vec![CExpr::var(&var_name(*var))]),
1091            ),
1092            LcnfLetValue::Reuse(slot, name, tag, args) => {
1093                let mut stmts = Vec::new();
1094                let num_objs = args.len();
1095                let ctor_var = self.fresh_temp();
1096                stmts.push(CStmt::VarDecl {
1097                    ty: CType::LeanObject,
1098                    name: ctor_var.clone(),
1099                    init: Some(CExpr::call(
1100                        "lean_alloc_ctor_using",
1101                        vec![
1102                            CExpr::var(&var_name(*slot)),
1103                            CExpr::UIntLit(*tag as u64),
1104                            CExpr::UIntLit(num_objs as u64),
1105                            CExpr::UIntLit(0),
1106                        ],
1107                    )),
1108                });
1109                for (i, arg) in args.iter().enumerate() {
1110                    let c_arg = self.emit_arg(arg);
1111                    stmts.push(lean_ctor_set(&ctor_var, i, c_arg));
1112                }
1113                if self.config.emit_comments {
1114                    stmts.insert(
1115                        0,
1116                        CStmt::Comment(format!("Reuse slot for {}#{}", name, tag)),
1117                    );
1118                }
1119                (stmts, CExpr::var(&ctor_var))
1120            }
1121        }
1122    }
1123    /// Emit a C expression for an LCNF argument.
1124    pub(super) fn emit_arg(&self, arg: &LcnfArg) -> CExpr {
1125        match arg {
1126            LcnfArg::Var(id) => CExpr::var(&var_name(*id)),
1127            LcnfArg::Lit(lit) => match lit {
1128                LcnfLit::Nat(n) => CExpr::UIntLit(*n),
1129                LcnfLit::Str(s) => CExpr::call("lean_mk_string", vec![CExpr::StringLit(s.clone())]),
1130            },
1131            LcnfArg::Erased => lean_box(CExpr::UIntLit(0)),
1132            LcnfArg::Type(_) => lean_box(CExpr::UIntLit(0)),
1133        }
1134    }
1135    /// Get the accumulated statistics.
1136    pub fn stats(&self) -> &CEmitStats {
1137        &self.stats
1138    }
1139}
1140/// C statement for code generation.
1141#[derive(Debug, Clone, PartialEq)]
1142pub enum CStmt {
1143    /// Variable declaration: `type name = init;`
1144    VarDecl {
1145        ty: CType,
1146        name: String,
1147        init: Option<CExpr>,
1148    },
1149    /// Assignment: `lhs = rhs;`
1150    Assign(CExpr, CExpr),
1151    /// If-else statement.
1152    If {
1153        cond: CExpr,
1154        then_body: Vec<CStmt>,
1155        else_body: Vec<CStmt>,
1156    },
1157    /// Switch statement.
1158    Switch {
1159        scrutinee: CExpr,
1160        cases: Vec<(u32, Vec<CStmt>)>,
1161        default: Vec<CStmt>,
1162    },
1163    /// While loop.
1164    While { cond: CExpr, body: Vec<CStmt> },
1165    /// Return statement.
1166    Return(Option<CExpr>),
1167    /// Block (compound statement).
1168    Block(Vec<CStmt>),
1169    /// Expression statement.
1170    Expr(CExpr),
1171    /// Comment.
1172    Comment(String),
1173    /// Blank line (for readability).
1174    Blank,
1175    /// Label for goto.
1176    Label(String),
1177    /// Goto statement.
1178    Goto(String),
1179    /// Break statement.
1180    Break,
1181}
1182#[allow(dead_code)]
1183#[derive(Debug, Clone)]
1184pub struct CBDominatorTree {
1185    pub idom: Vec<Option<u32>>,
1186    pub dom_children: Vec<Vec<u32>>,
1187    pub dom_depth: Vec<u32>,
1188}
1189impl CBDominatorTree {
1190    #[allow(dead_code)]
1191    pub fn new(size: usize) -> Self {
1192        CBDominatorTree {
1193            idom: vec![None; size],
1194            dom_children: vec![Vec::new(); size],
1195            dom_depth: vec![0; size],
1196        }
1197    }
1198    #[allow(dead_code)]
1199    pub fn set_idom(&mut self, node: usize, idom: u32) {
1200        self.idom[node] = Some(idom);
1201    }
1202    #[allow(dead_code)]
1203    pub fn dominates(&self, a: usize, b: usize) -> bool {
1204        if a == b {
1205            return true;
1206        }
1207        let mut cur = b;
1208        loop {
1209            match self.idom[cur] {
1210                Some(parent) if parent as usize == a => return true,
1211                Some(parent) if parent as usize == cur => return false,
1212                Some(parent) => cur = parent as usize,
1213                None => return false,
1214            }
1215        }
1216    }
1217    #[allow(dead_code)]
1218    pub fn depth(&self, node: usize) -> u32 {
1219        self.dom_depth.get(node).copied().unwrap_or(0)
1220    }
1221}
1222/// Statistics collected during C code emission.
1223#[derive(Debug, Clone, Default)]
1224pub struct CEmitStats {
1225    /// Number of functions emitted.
1226    pub functions_emitted: usize,
1227    /// Number of structs emitted.
1228    pub structs_emitted: usize,
1229    /// Number of RC inc calls inserted.
1230    pub rc_inc_calls: usize,
1231    /// Number of RC dec calls inserted.
1232    pub rc_dec_calls: usize,
1233    /// Number of closures emitted.
1234    pub closures_emitted: usize,
1235    /// Number of switch statements emitted.
1236    pub switches_emitted: usize,
1237    /// Total lines of generated C code.
1238    pub total_lines: usize,
1239}
1240#[allow(dead_code)]
1241#[derive(Debug, Clone)]
1242pub struct CBCacheEntry {
1243    pub key: String,
1244    pub data: Vec<u8>,
1245    pub timestamp: u64,
1246    pub valid: bool,
1247}
1248#[allow(dead_code)]
1249pub struct CBConstantFoldingHelper;
1250impl CBConstantFoldingHelper {
1251    #[allow(dead_code)]
1252    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
1253        a.checked_add(b)
1254    }
1255    #[allow(dead_code)]
1256    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
1257        a.checked_sub(b)
1258    }
1259    #[allow(dead_code)]
1260    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
1261        a.checked_mul(b)
1262    }
1263    #[allow(dead_code)]
1264    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
1265        if b == 0 {
1266            None
1267        } else {
1268            a.checked_div(b)
1269        }
1270    }
1271    #[allow(dead_code)]
1272    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
1273        a + b
1274    }
1275    #[allow(dead_code)]
1276    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
1277        a * b
1278    }
1279    #[allow(dead_code)]
1280    pub fn fold_neg_i64(a: i64) -> Option<i64> {
1281        a.checked_neg()
1282    }
1283    #[allow(dead_code)]
1284    pub fn fold_not_bool(a: bool) -> bool {
1285        !a
1286    }
1287    #[allow(dead_code)]
1288    pub fn fold_and_bool(a: bool, b: bool) -> bool {
1289        a && b
1290    }
1291    #[allow(dead_code)]
1292    pub fn fold_or_bool(a: bool, b: bool) -> bool {
1293        a || b
1294    }
1295    #[allow(dead_code)]
1296    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
1297        a.checked_shl(b)
1298    }
1299    #[allow(dead_code)]
1300    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
1301        a.checked_shr(b)
1302    }
1303    #[allow(dead_code)]
1304    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
1305        if b == 0 {
1306            None
1307        } else {
1308            Some(a % b)
1309        }
1310    }
1311    #[allow(dead_code)]
1312    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
1313        a & b
1314    }
1315    #[allow(dead_code)]
1316    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
1317        a | b
1318    }
1319    #[allow(dead_code)]
1320    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
1321        a ^ b
1322    }
1323    #[allow(dead_code)]
1324    pub fn fold_bitnot_i64(a: i64) -> i64 {
1325        !a
1326    }
1327}