decy_codegen/
lib.rs

1//! Rust code generation from HIR with minimal unsafe blocks.
2//!
3//! Generates idiomatic Rust code with <5 unsafe blocks per 1000 LOC.
4//!
5//! # Examples
6//!
7//! ```
8//! use decy_codegen::CodeGenerator;
9//! use decy_hir::{HirFunction, HirType, HirParameter};
10//!
11//! let func = HirFunction::new(
12//!     "add".to_string(),
13//!     HirType::Int,
14//!     vec![
15//!         HirParameter::new("a".to_string(), HirType::Int),
16//!         HirParameter::new("b".to_string(), HirType::Int),
17//!     ],
18//! );
19//!
20//! let codegen = CodeGenerator::new();
21//! let code = codegen.generate_function(&func);
22//!
23//! assert!(code.contains("fn add"));
24//! assert!(code.contains("a: i32"));
25//! assert!(code.contains("b: i32"));
26//! ```
27
28#![warn(missing_docs)]
29#![warn(clippy::all)]
30#![deny(unsafe_code)]
31
32pub mod box_transform;
33pub mod concurrency_transform;
34pub mod test_generator;
35
36use decy_hir::{BinaryOperator, HirExpression, HirFunction, HirStatement, HirType};
37use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedType};
38use std::collections::HashMap;
39
40/// Type context for tracking variable types and struct definitions during code generation.
41/// Used to detect pointer arithmetic, null pointer assignments, and other type-specific operations.
42#[derive(Debug, Clone)]
43struct TypeContext {
44    variables: HashMap<String, HirType>,
45    structs: HashMap<String, Vec<(String, HirType)>>, // struct_name -> [(field_name, field_type)]
46}
47
48impl TypeContext {
49    fn new() -> Self {
50        Self {
51            variables: HashMap::new(),
52            structs: HashMap::new(),
53        }
54    }
55
56    fn from_function(func: &HirFunction) -> Self {
57        let mut ctx = Self::new();
58        // Add parameters to context
59        for param in func.parameters() {
60            ctx.variables
61                .insert(param.name().to_string(), param.param_type().clone());
62        }
63        ctx
64    }
65
66    fn add_variable(&mut self, name: String, var_type: HirType) {
67        self.variables.insert(name, var_type);
68    }
69
70    fn add_struct(&mut self, struct_def: &decy_hir::HirStruct) {
71        let fields: Vec<(String, HirType)> = struct_def
72            .fields()
73            .iter()
74            .map(|f| (f.name().to_string(), f.field_type().clone()))
75            .collect();
76        self.structs.insert(struct_def.name().to_string(), fields);
77    }
78
79    fn get_type(&self, name: &str) -> Option<&HirType> {
80        self.variables.get(name)
81    }
82
83    fn get_field_type(&self, object_expr: &HirExpression, field_name: &str) -> Option<HirType> {
84        // Get the type of the object expression
85        let object_type = match object_expr {
86            HirExpression::Variable(var_name) => self.get_type(var_name)?,
87            _ => return None,
88        };
89
90        // Extract the struct name from the type
91        let struct_name = match object_type {
92            HirType::Struct(name) => name,
93            HirType::Pointer(inner) => {
94                // If it's a pointer to a struct, dereference it
95                if let HirType::Struct(name) = &**inner {
96                    name
97                } else {
98                    return None;
99                }
100            }
101            _ => return None,
102        };
103
104        // Look up the field type in the struct definition
105        let fields = self.structs.get(struct_name)?;
106        fields
107            .iter()
108            .find(|(name, _)| name == field_name)
109            .map(|(_, field_type)| field_type.clone())
110    }
111
112    fn is_pointer(&self, name: &str) -> bool {
113        matches!(self.get_type(name), Some(HirType::Pointer(_)))
114    }
115
116    fn is_option(&self, name: &str) -> bool {
117        matches!(self.get_type(name), Some(HirType::Option(_)))
118    }
119
120    /// Infer the type of an expression based on the context.
121    /// Returns None if the type cannot be inferred.
122    fn infer_expression_type(&self, expr: &HirExpression) -> Option<HirType> {
123        match expr {
124            HirExpression::Variable(name) => self.get_type(name).cloned(),
125            HirExpression::Dereference(inner) => {
126                // If inner is *mut T, then *inner is T
127                if let Some(HirType::Pointer(pointee_type)) = self.infer_expression_type(inner) {
128                    Some(*pointee_type)
129                } else {
130                    None
131                }
132            }
133            HirExpression::ArrayIndex { array, index: _ } => {
134                // If array is [T; N] or *mut T, then array[i] is T
135                if let Some(array_type) = self.infer_expression_type(array) {
136                    match array_type {
137                        HirType::Array { element_type, .. } => Some(*element_type),
138                        HirType::Pointer(element_type) => Some(*element_type),
139                        _ => None,
140                    }
141                } else {
142                    None
143                }
144            }
145            _ => None,
146        }
147    }
148}
149
150/// Code generator for converting HIR to Rust source code.
151#[derive(Debug, Clone)]
152pub struct CodeGenerator {
153    box_transformer: box_transform::BoxTransformer,
154}
155
156impl CodeGenerator {
157    /// Create a new code generator.
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// use decy_codegen::CodeGenerator;
163    ///
164    /// let codegen = CodeGenerator::new();
165    /// ```
166    pub fn new() -> Self {
167        Self {
168            box_transformer: box_transform::BoxTransformer::new(),
169        }
170    }
171
172    /// Generate Rust code for a macro definition.
173    ///
174    /// Transforms C #define macros to Rust const declarations (for object-like macros)
175    /// or inline functions (for function-like macros).
176    ///
177    /// # Supported Macro Types (DECY-098c)
178    ///
179    /// **Object-like macros** (constants) are fully supported:
180    /// - `#define MAX 100` → `const MAX: i32 = 100;`
181    /// - `#define PI 3.14159` → `const PI: f64 = 3.14159;`
182    /// - `#define GREETING "Hello"` → `const GREETING: &str = "Hello";`
183    ///
184    /// **Function-like macros** are not yet supported (DECY-098d):
185    /// - `#define SQR(x) ((x) * (x))` → Error
186    ///
187    /// # Type Inference
188    ///
189    /// Types are automatically inferred from the macro body:
190    /// - String literals → `&str`
191    /// - Character literals → `char`
192    /// - Floating point → `f64`
193    /// - Integers (including hex/octal) → `i32`
194    ///
195    /// # Edge Cases
196    ///
197    /// - Empty macros generate comments: `#define EMPTY` → `// Empty macro: EMPTY`
198    /// - Macro names are preserved exactly (SCREAMING_SNAKE_CASE maintained)
199    ///
200    /// # Errors
201    ///
202    /// Returns an error if:
203    /// - The macro is function-like (not yet implemented)
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// use decy_codegen::CodeGenerator;
209    /// use decy_hir::HirMacroDefinition;
210    ///
211    /// let generator = CodeGenerator::new();
212    /// let macro_def = HirMacroDefinition::new_object_like("MAX".to_string(), "100".to_string());
213    /// let rust_code = generator.generate_macro(&macro_def).unwrap();
214    /// assert!(rust_code.contains("const MAX"));
215    /// # Ok::<(), anyhow::Error>(())
216    /// ```
217    ///
218    /// # Reference
219    ///
220    /// - K&R §4.11: Macro Substitution
221    /// - ISO C99 §6.10.3: Macro replacement
222    pub fn generate_macro(
223        &self,
224        macro_def: &decy_hir::HirMacroDefinition,
225    ) -> anyhow::Result<String> {
226        if macro_def.is_function_like() {
227            // Generate inline function for function-like macros
228            return self.generate_function_like_macro(macro_def);
229        }
230
231        // Object-like macro (constant)
232        let name = macro_def.name();
233        let body = macro_def.body();
234
235        // Handle empty macros
236        if body.is_empty() {
237            return Ok(format!("// Empty macro: {}", name));
238        }
239
240        // Infer type from macro body
241        let (rust_type, rust_value) = self.infer_macro_type(body)?;
242
243        Ok(format!("const {}: {} = {};", name, rust_type, rust_value))
244    }
245
246    /// Generate Rust inline function from function-like macro.
247    ///
248    /// Transforms C function-like macros to Rust inline functions:
249    /// - `#define SQR(x) ((x) * (x))` → `fn sqr(x: i32) -> i32 { x * x }`
250    /// - `#define MAX(a, b) ((a) > (b) ? (a) : (b))` → `fn max(a: i32, b: i32) -> i32 { if a > b { a } else { b } }`
251    ///
252    /// # Features
253    ///
254    /// - Converts macro name from SCREAMING_SNAKE_CASE to snake_case
255    /// - Infers parameter types (defaults to i32)
256    /// - Infers return type from expression
257    /// - Adds #[inline] attribute for performance
258    /// - Transforms ternary operator (? :) to if-else
259    /// - Removes unnecessary parentheses
260    fn generate_function_like_macro(
261        &self,
262        macro_def: &decy_hir::HirMacroDefinition,
263    ) -> anyhow::Result<String> {
264        let name = macro_def.name();
265        let params = macro_def.parameters();
266        let body = macro_def.body();
267
268        // Convert SCREAMING_SNAKE_CASE to snake_case
269        let fn_name = self.convert_to_snake_case(name);
270
271        // Generate parameter list (default to i32 for now)
272        let param_list = params
273            .iter()
274            .map(|p| format!("{}: i32", p))
275            .collect::<Vec<_>>()
276            .join(", ");
277
278        // Transform macro body to Rust expression
279        let rust_body = self.transform_macro_body(body, params)?;
280
281        // Infer return type from body
282        let return_type = self.infer_return_type(body);
283
284        // Generate function
285        let result = format!(
286            "#[inline]\nfn {}({}) -> {} {{\n    {}\n}}",
287            fn_name, param_list, return_type, rust_body
288        );
289
290        Ok(result)
291    }
292
293    /// Convert SCREAMING_SNAKE_CASE to snake_case.
294    fn convert_to_snake_case(&self, name: &str) -> String {
295        name.to_lowercase()
296    }
297
298    /// Transform C macro body to Rust expression.
299    ///
300    /// Transformations:
301    /// - Remove outer parentheses: ((x) * (x)) → x * x
302    /// - Ternary operator: (a) > (b) ? (a) : (b) → if a > b { a } else { b }
303    /// - Remove parameter parentheses: (x) → x
304    fn transform_macro_body(&self, body: &str, params: &[String]) -> anyhow::Result<String> {
305        let mut result = body.to_string();
306
307        // Check for ternary operator
308        if result.contains('?') && result.contains(':') {
309            result = self.transform_ternary(&result)?;
310        } else {
311            // Remove unnecessary parentheses around parameters
312            for param in params {
313                result = result.replace(&format!("({})", param), param);
314            }
315
316            // Remove outer parentheses if present
317            result = self.remove_outer_parens(&result);
318
319            // Add spaces around operators for readability
320            result = self.add_operator_spaces(&result);
321        }
322
323        Ok(result)
324    }
325
326    /// Transform C ternary operator to Rust if-else.
327    ///
328    /// Example: ((a)>(b)?(a):(b)) → if a > b { a } else { b }
329    fn transform_ternary(&self, expr: &str) -> anyhow::Result<String> {
330        // Find the ? and : positions
331        let question_pos = expr.find('?').unwrap_or(0);
332        let colon_pos = expr.rfind(':').unwrap_or(0);
333
334        if question_pos == 0 || colon_pos == 0 || colon_pos <= question_pos {
335            // Malformed ternary, return as-is
336            return Ok(expr.to_string());
337        }
338
339        // Extract parts
340        let condition = expr[..question_pos].trim();
341        let true_expr = expr[question_pos + 1..colon_pos].trim();
342        let false_expr = expr[colon_pos + 1..].trim();
343
344        // Clean up each part
345        let condition = self.remove_outer_parens(condition);
346        let condition = self.clean_expression(&condition);
347        let true_expr = self.remove_outer_parens(true_expr);
348        let true_expr = self.clean_expression(&true_expr);
349        let false_expr = self.remove_outer_parens(false_expr);
350        let false_expr = self.clean_expression(&false_expr);
351
352        Ok(format!(
353            "if {} {{ {} }} else {{ {} }}",
354            condition, true_expr, false_expr
355        ))
356    }
357
358    /// Remove outer parentheses from expression.
359    fn remove_outer_parens(&self, expr: &str) -> String {
360        Self::remove_outer_parens_impl(expr)
361    }
362
363    /// Implementation of remove_outer_parens (recursive helper).
364    fn remove_outer_parens_impl(expr: &str) -> String {
365        let trimmed = expr.trim();
366        if trimmed.starts_with('(') && trimmed.ends_with(')') {
367            // Check if these are matching outer parens
368            let mut depth = 0;
369            let chars: Vec<char> = trimmed.chars().collect();
370            for (i, ch) in chars.iter().enumerate() {
371                match ch {
372                    '(' => depth += 1,
373                    ')' => {
374                        depth -= 1;
375                        if depth == 0 && i < chars.len() - 1 {
376                            // Found closing paren before end, not outer parens
377                            return trimmed.to_string();
378                        }
379                    }
380                    _ => {}
381                }
382            }
383            // These are outer parens, remove them
384            return Self::remove_outer_parens_impl(&trimmed[1..trimmed.len() - 1]);
385        }
386        trimmed.to_string()
387    }
388
389    /// Clean expression by removing parameter parentheses.
390    fn clean_expression(&self, expr: &str) -> String {
391        let mut result = expr.to_string();
392
393        // Handle negation: -(x) → -x (preserve the minus)
394        result = result.replace("-(x)", "-x");
395        result = result.replace("-(a)", "-a");
396        result = result.replace("-(b)", "-b");
397        result = result.replace("-(c)", "-c");
398        result = result.replace("-(n)", "-n");
399
400        // Remove parentheses around single identifiers (not negated)
401        // This is a simplified version - could be enhanced
402        result = result.replace("(x)", "x");
403        result = result.replace("(a)", "a");
404        result = result.replace("(b)", "b");
405        result = result.replace("(c)", "c");
406        result = result.replace("(n)", "n");
407
408        // Add spaces around operators
409        result = self.add_operator_spaces(&result);
410
411        result
412    }
413
414    /// Add spaces around operators for readability.
415    fn add_operator_spaces(&self, expr: &str) -> String {
416        let mut result = expr.to_string();
417
418        // Add spaces around comparison operators
419        result = result.replace(">", " > ");
420        result = result.replace("<", " < ");
421        result = result.replace("==", " == ");
422        result = result.replace("!=", " != ");
423        result = result.replace(">=", " >= ");
424        result = result.replace("<=", " <= ");
425
426        // Add spaces around logical operators (do this before arithmetic to avoid issues)
427        result = result.replace("&&", " && ");
428        result = result.replace("||", " || ");
429
430        // Add spaces around arithmetic operators
431        result = result.replace("+", " + ");
432        // Note: Don't blindly replace "-" as it could be unary minus
433        // Only replace if it's not at the start or after a space
434        let chars: Vec<char> = result.chars().collect();
435        let mut new_result = String::new();
436        for (i, ch) in chars.iter().enumerate() {
437            if *ch == '-' {
438                // Check if this is a binary minus (has non-space before it)
439                if i > 0 && !chars[i - 1].is_whitespace() && chars[i - 1] != '(' {
440                    new_result.push(' ');
441                    new_result.push(*ch);
442                    new_result.push(' ');
443                } else {
444                    // Unary minus, keep as-is
445                    new_result.push(*ch);
446                }
447            } else {
448                new_result.push(*ch);
449            }
450        }
451        result = new_result;
452
453        result = result.replace("*", " * ");
454        result = result.replace("/", " / ");
455        result = result.replace("%", " % ");
456
457        // Clean up multiple spaces
458        while result.contains("  ") {
459            result = result.replace("  ", " ");
460        }
461
462        result.trim().to_string()
463    }
464
465    /// Infer return type from macro body.
466    ///
467    /// Simple heuristic:
468    /// - Contains ternary operator (? :) → return type of branches (check for comparison at top level)
469    /// - Contains comparison operators at top level (not in ternary) → bool
470    /// - Contains logical operators (&&, ||) → bool
471    /// - Default → i32
472    fn infer_return_type(&self, body: &str) -> String {
473        // Check for ternary - return type depends on the branches, not the condition
474        if body.contains('?') && body.contains(':') {
475            // For ternary, the return type is determined by what's returned, not the condition
476            // In most C macros like MAX(a,b), the return type is i32 even though condition is bool
477            return "i32".to_string();
478        }
479
480        // Check for logical operators (&&, ||) at top level
481        if body.contains("&&") || body.contains("||") {
482            return "bool".to_string();
483        }
484
485        // Check if it's a standalone comparison (no ternary)
486        if (body.contains('>') || body.contains('<') || body.contains("==") || body.contains("!="))
487            && !body.contains('?')
488        {
489            // Standalone comparison returns bool
490            "bool".to_string()
491        } else {
492            // Default to i32
493            "i32".to_string()
494        }
495    }
496
497    /// Infer the Rust type and value from a C macro body.
498    ///
499    /// This function analyzes the macro body string and determines the appropriate
500    /// Rust type and formatted value.
501    ///
502    /// # Type Inference Rules
503    ///
504    /// - String literals (`"text"`) → `&str`
505    /// - Character literals (`'c'`) → `char`
506    /// - Floating point (contains `.` or `e`/`E`) → `f64`
507    /// - Hexadecimal (`0xFF`) → `i32` (preserves hex format)
508    /// - Octal (`0755`) → `i32` (preserves octal format)
509    /// - Integers (parseable as i32) → `i32`
510    /// - Default (expressions) → `i32`
511    ///
512    /// # Returns
513    ///
514    /// Returns a tuple of (rust_type, rust_value) where:
515    /// - `rust_type`: The Rust type as a string (e.g., "i32", "&str")
516    /// - `rust_value`: The formatted value (e.g., "100", "\"Hello\"")
517    ///
518    /// # Examples
519    ///
520    /// ```
521    /// # use decy_codegen::CodeGenerator;
522    /// let generator = CodeGenerator::new();
523    /// // This is a private method, but tested through generate_macro
524    /// # Ok::<(), anyhow::Error>(())
525    /// ```
526    fn infer_macro_type(&self, body: &str) -> anyhow::Result<(String, String)> {
527        let body = body.trim();
528
529        // String literal: "..." → &str
530        if body.starts_with('"') && body.ends_with('"') {
531            return Ok(("&str".to_string(), body.to_string()));
532        }
533
534        // Character literal: '...' → char
535        if body.starts_with('\'') && body.ends_with('\'') {
536            return Ok(("char".to_string(), body.to_string()));
537        }
538
539        // Floating point: contains '.' or 'e'/'E' → f64
540        if body.contains('.') || body.contains('e') || body.contains('E') {
541            return Ok(("f64".to_string(), body.to_string()));
542        }
543
544        // Hexadecimal: 0x... or 0X... → i32 (keep hex format)
545        if body.starts_with("0x") || body.starts_with("0X") {
546            return Ok(("i32".to_string(), body.to_string()));
547        }
548
549        // Octal: 0... → i32
550        if body.starts_with('0') && body.len() > 1 && body.chars().nth(1).unwrap().is_ascii_digit()
551        {
552            return Ok(("i32".to_string(), body.to_string()));
553        }
554
555        // Try to parse as integer (handles negative numbers too)
556        if body.parse::<i32>().is_ok() {
557            return Ok(("i32".to_string(), body.to_string()));
558        }
559
560        // Default: treat as i32 expression
561        Ok(("i32".to_string(), body.to_string()))
562    }
563
564    /// Get the Box transformer.
565    pub fn box_transformer(&self) -> &box_transform::BoxTransformer {
566        &self.box_transformer
567    }
568
569    /// Map HIR type to Rust type string.
570    ///
571    /// # Examples
572    ///
573    /// ```
574    /// use decy_codegen::CodeGenerator;
575    /// use decy_hir::HirType;
576    ///
577    /// assert_eq!(CodeGenerator::map_type(&HirType::Int), "i32");
578    /// assert_eq!(CodeGenerator::map_type(&HirType::Float), "f32");
579    /// assert_eq!(CodeGenerator::map_type(&HirType::Box(Box::new(HirType::Int))), "Box<i32>");
580    /// ```
581    pub fn map_type(hir_type: &HirType) -> String {
582        match hir_type {
583            HirType::Void => "()".to_string(),
584            HirType::Int => "i32".to_string(),
585            HirType::Float => "f32".to_string(),
586            HirType::Double => "f64".to_string(),
587            HirType::Char => "u8".to_string(),
588            HirType::Pointer(inner) => {
589                format!("*mut {}", Self::map_type(inner))
590            }
591            HirType::Box(inner) => {
592                format!("Box<{}>", Self::map_type(inner))
593            }
594            HirType::Vec(inner) => {
595                format!("Vec<{}>", Self::map_type(inner))
596            }
597            HirType::Option(inner) => {
598                format!("Option<{}>", Self::map_type(inner))
599            }
600            HirType::Reference { inner, mutable } => {
601                if *mutable {
602                    format!("&mut {}", Self::map_type(inner))
603                } else {
604                    format!("&{}", Self::map_type(inner))
605                }
606            }
607            HirType::Struct(name) => name.clone(),
608            HirType::Enum(name) => name.clone(),
609            HirType::Array { element_type, size } => {
610                if let Some(n) = size {
611                    format!("[{}; {}]", Self::map_type(element_type), n)
612                } else {
613                    // Unsized array - use slice reference
614                    format!("[{}]", Self::map_type(element_type))
615                }
616            }
617            HirType::FunctionPointer {
618                param_types,
619                return_type,
620            } => {
621                // C: int (*func_ptr)(int, int); → Rust: fn(i32, i32) -> i32
622                let params: Vec<String> = param_types.iter().map(Self::map_type).collect();
623                let params_str = params.join(", ");
624
625                // Skip return type annotation for void
626                if matches!(**return_type, HirType::Void) {
627                    format!("fn({})", params_str)
628                } else {
629                    format!("fn({}) -> {}", params_str, Self::map_type(return_type))
630                }
631            }
632            HirType::StringLiteral => "&str".to_string(),
633            HirType::OwnedString => "String".to_string(),
634            HirType::StringReference => "&str".to_string(),
635        }
636    }
637
638    /// Map C type name from sizeof to Rust type string.
639    ///
640    /// Handles type names as strings from sizeof expressions.
641    /// Examples: "int" → "i32", "struct Data" → "Data"
642    fn map_sizeof_type(&self, c_type_name: &str) -> String {
643        let trimmed = c_type_name.trim();
644
645        // Handle basic C types
646        match trimmed {
647            "int" => "i32".to_string(),
648            "float" => "f32".to_string(),
649            "double" => "f64".to_string(),
650            "char" => "u8".to_string(),
651            "void" => "()".to_string(),
652            _ => {
653                // Handle "struct TypeName" → "TypeName"
654                if let Some(struct_name) = trimmed.strip_prefix("struct ") {
655                    struct_name.trim().to_string()
656                } else {
657                    // Keep custom type names as-is
658                    trimmed.to_string()
659                }
660            }
661        }
662    }
663
664    /// Generate code for an expression.
665    #[allow(clippy::only_used_in_recursion)]
666    pub fn generate_expression(&self, expr: &HirExpression) -> String {
667        self.generate_expression_with_context(expr, &TypeContext::new())
668    }
669
670    /// Generate code for an expression with type context for pointer arithmetic.
671    #[allow(clippy::only_used_in_recursion)]
672    fn generate_expression_with_context(&self, expr: &HirExpression, ctx: &TypeContext) -> String {
673        self.generate_expression_with_target_type(expr, ctx, None)
674    }
675
676    /// Generate code for an expression with optional target type hint for null pointer detection.
677    /// If target_type is Some(HirType::Pointer(_)) and expr is IntLiteral(0), generates std::ptr::null_mut().
678    #[allow(clippy::only_used_in_recursion)]
679    fn generate_expression_with_target_type(
680        &self,
681        expr: &HirExpression,
682        ctx: &TypeContext,
683        target_type: Option<&HirType>,
684    ) -> String {
685        match expr {
686            HirExpression::IntLiteral(val) => {
687                // Check if assigning 0 to a pointer type
688                if *val == 0 {
689                    if let Some(HirType::Pointer(_)) = target_type {
690                        return "std::ptr::null_mut()".to_string();
691                    }
692                }
693                val.to_string()
694            }
695            HirExpression::StringLiteral(s) => format!("\"{}\"", s),
696            HirExpression::Variable(name) => name.clone(),
697            HirExpression::BinaryOp { op, left, right } => {
698                // Check for Option comparison with NULL → is_none() / is_some()
699                // p == NULL → p.is_none(), p != NULL → p.is_some()
700                if matches!(op, BinaryOperator::Equal | BinaryOperator::NotEqual) {
701                    // Check if left is an Option and right is NULL
702                    if let HirExpression::Variable(var_name) = &**left {
703                        if ctx.is_option(var_name) && matches!(**right, HirExpression::NullLiteral)
704                        {
705                            return match op {
706                                BinaryOperator::Equal => format!("{}.is_none()", var_name),
707                                BinaryOperator::NotEqual => format!("{}.is_some()", var_name),
708                                _ => unreachable!(),
709                            };
710                        }
711                    }
712                    // Check if right is an Option and left is NULL (NULL == p or NULL != p)
713                    if let HirExpression::Variable(var_name) = &**right {
714                        if ctx.is_option(var_name) && matches!(**left, HirExpression::NullLiteral) {
715                            return match op {
716                                BinaryOperator::Equal => format!("{}.is_none()", var_name),
717                                BinaryOperator::NotEqual => format!("{}.is_some()", var_name),
718                                _ => unreachable!(),
719                            };
720                        }
721                    }
722
723                    // Check for pointer comparison with 0 (null pointer comparison)
724                    // ptr == 0 or ptr != 0 should become ptr == std::ptr::null_mut() or ptr != std::ptr::null_mut()
725                    // Check if left is a pointer and right is 0
726                    if let HirExpression::Variable(var_name) = &**left {
727                        if ctx.is_pointer(var_name) {
728                            if let HirExpression::IntLiteral(0) = **right {
729                                let op_str = Self::binary_operator_to_string(op);
730                                return format!("{} {} std::ptr::null_mut()", var_name, op_str);
731                            }
732                        }
733                    }
734                    // Check if right is a pointer and left is 0 (0 == ptr or 0 != ptr)
735                    if let HirExpression::Variable(var_name) = &**right {
736                        if ctx.is_pointer(var_name) {
737                            if let HirExpression::IntLiteral(0) = **left {
738                                let op_str = Self::binary_operator_to_string(op);
739                                return format!("std::ptr::null_mut() {} {}", op_str, var_name);
740                            }
741                        }
742                    }
743                }
744
745                let left_code = self.generate_expression_with_context(left, ctx);
746                let right_code = self.generate_expression_with_context(right, ctx);
747                let op_str = Self::binary_operator_to_string(op);
748
749                // Add parentheses for nested binary operations
750                let left_str = if matches!(**left, HirExpression::BinaryOp { .. }) {
751                    format!("({})", left_code)
752                } else {
753                    left_code.clone()
754                };
755
756                let right_str = if matches!(**right, HirExpression::BinaryOp { .. }) {
757                    format!("({})", right_code)
758                } else {
759                    right_code.clone()
760                };
761
762                // DECY-041: Detect pointer arithmetic using type context
763                if matches!(op, BinaryOperator::Add | BinaryOperator::Subtract) {
764                    if let HirExpression::Variable(var_name) = &**left {
765                        if ctx.is_pointer(var_name) {
766                            // This is pointer arithmetic - generate unsafe pointer method calls
767                            return match op {
768                                BinaryOperator::Add => {
769                                    format!(
770                                        "unsafe {{ {}.wrapping_add({} as usize) }}",
771                                        left_str, right_str
772                                    )
773                                }
774                                BinaryOperator::Subtract => {
775                                    // Check if right is also a pointer (ptr - ptr) or integer (ptr - offset)
776                                    if let HirExpression::Variable(right_var) = &**right {
777                                        if ctx.is_pointer(right_var) {
778                                            // ptr - ptr: calculate difference (returns isize, cast to i32 for C compatibility)
779                                            format!(
780                                                "unsafe {{ {}.offset_from({}) as i32 }}",
781                                                left_str, right_str
782                                            )
783                                        } else {
784                                            // ptr - integer offset
785                                            format!(
786                                                "unsafe {{ {}.wrapping_sub({} as usize) }}",
787                                                left_str, right_str
788                                            )
789                                        }
790                                    } else {
791                                        // ptr - integer offset (literal or expression)
792                                        format!(
793                                            "unsafe {{ {}.wrapping_sub({} as usize) }}",
794                                            left_str, right_str
795                                        )
796                                    }
797                                }
798                                _ => unreachable!(),
799                            };
800                        }
801                    }
802                }
803
804                format!("{} {} {}", left_str, op_str, right_str)
805            }
806            HirExpression::Dereference(inner) => {
807                let inner_code = self.generate_expression_with_context(inner, ctx);
808
809                // DECY-041: Check if dereferencing a raw pointer - if so, wrap in unsafe
810                if let HirExpression::Variable(var_name) = &**inner {
811                    if ctx.is_pointer(var_name) {
812                        return format!("unsafe {{ *{} }}", inner_code);
813                    }
814                }
815
816                format!("*{}", inner_code)
817            }
818            HirExpression::AddressOf(inner) => {
819                let inner_code = self.generate_expression_with_context(inner, ctx);
820                // Add parentheses for non-trivial expressions
821                if matches!(**inner, HirExpression::Dereference(_)) {
822                    format!("&({})", inner_code)
823                } else {
824                    format!("&{}", inner_code)
825                }
826            }
827            HirExpression::UnaryOp { op, operand } => {
828                use decy_hir::UnaryOperator;
829                match op {
830                    // Post-increment: x++ → { let tmp = x; x += 1; tmp }
831                    // Returns old value before incrementing
832                    UnaryOperator::PostIncrement => {
833                        let operand_code = self.generate_expression_with_context(operand, ctx);
834                        format!(
835                            "{{ let tmp = {}; {} += 1; tmp }}",
836                            operand_code, operand_code
837                        )
838                    }
839                    // Post-decrement: x-- → { let tmp = x; x -= 1; tmp }
840                    // Returns old value before decrementing
841                    UnaryOperator::PostDecrement => {
842                        let operand_code = self.generate_expression_with_context(operand, ctx);
843                        format!(
844                            "{{ let tmp = {}; {} -= 1; tmp }}",
845                            operand_code, operand_code
846                        )
847                    }
848                    // Pre-increment: ++x → { x += 1; x }
849                    // Increments first, then returns new value
850                    UnaryOperator::PreIncrement => {
851                        let operand_code = self.generate_expression_with_context(operand, ctx);
852                        format!("{{ {} += 1; {} }}", operand_code, operand_code)
853                    }
854                    // Pre-decrement: --x → { x -= 1; x }
855                    // Decrements first, then returns new value
856                    UnaryOperator::PreDecrement => {
857                        let operand_code = self.generate_expression_with_context(operand, ctx);
858                        format!("{{ {} -= 1; {} }}", operand_code, operand_code)
859                    }
860                    // Simple prefix operators
861                    _ => {
862                        let op_str = Self::unary_operator_to_string(op);
863                        let operand_code = self.generate_expression_with_context(operand, ctx);
864                        format!("{}{}", op_str, operand_code)
865                    }
866                }
867            }
868            HirExpression::FunctionCall {
869                function,
870                arguments,
871            } => {
872                // Special handling for standard library functions
873                match function.as_str() {
874                    // strlen(s) → s.len()
875                    // Reference: K&R §B3, ISO C99 §7.21.6.3
876                    "strlen" => {
877                        if arguments.len() == 1 {
878                            format!(
879                                "{}.len()",
880                                self.generate_expression_with_context(&arguments[0], ctx)
881                            )
882                        } else {
883                            // Invalid strlen call - shouldn't happen, but handle gracefully
884                            let args: Vec<String> = arguments
885                                .iter()
886                                .map(|arg| self.generate_expression_with_context(arg, ctx))
887                                .collect();
888                            format!("{}({})", function, args.join(", "))
889                        }
890                    }
891                    // strcpy(dest, src) → src.to_string()
892                    // Reference: K&R §B3, ISO C99 §7.21.3.1
893                    // strcpy copies src to dest and returns dest pointer.
894                    // In Rust, we transform to String operation: src.to_string()
895                    // This prevents buffer overflow (the primary safety benefit)
896                    "strcpy" => {
897                        if arguments.len() == 2 {
898                            // strcpy(dest, src) → src.to_string()
899                            // We generate the source string operation
900                            // The destination assignment is handled by the statement context
901                            format!(
902                                "{}.to_string()",
903                                self.generate_expression_with_context(&arguments[1], ctx)
904                            )
905                        } else {
906                            // Invalid strcpy call - shouldn't happen, but handle gracefully
907                            let args: Vec<String> = arguments
908                                .iter()
909                                .map(|arg| self.generate_expression_with_context(arg, ctx))
910                                .collect();
911                            format!("{}({})", function, args.join(", "))
912                        }
913                    }
914                    // Default: pass through function call as-is
915                    _ => {
916                        let args: Vec<String> = arguments
917                            .iter()
918                            .map(|arg| self.generate_expression_with_context(arg, ctx))
919                            .collect();
920                        format!("{}({})", function, args.join(", "))
921                    }
922                }
923            }
924            HirExpression::FieldAccess { object, field } => {
925                format!(
926                    "{}.{}",
927                    self.generate_expression_with_context(object, ctx),
928                    field
929                )
930            }
931            HirExpression::PointerFieldAccess { pointer, field } => {
932                // In Rust, ptr->field becomes (*ptr).field
933                // However, if the pointer is already a field access (ptr->field1->field2),
934                // we should generate (*ptr).field1.field2 not (*(*ptr).field1).field2
935                match &**pointer {
936                    // If the pointer is itself a field access expression, we can chain with .
937                    HirExpression::PointerFieldAccess { .. }
938                    | HirExpression::FieldAccess { .. } => {
939                        format!(
940                            "{}.{}",
941                            self.generate_expression_with_context(pointer, ctx),
942                            field
943                        )
944                    }
945                    // For other expressions (variables, array index, etc), we need explicit deref
946                    _ => {
947                        format!(
948                            "(*{}).{}",
949                            self.generate_expression_with_context(pointer, ctx),
950                            field
951                        )
952                    }
953                }
954            }
955            HirExpression::ArrayIndex { array, index } => {
956                let array_code = self.generate_expression_with_context(array, ctx);
957                let index_code = self.generate_expression_with_context(index, ctx);
958
959                // DECY-041: Check if array is a raw pointer - if so, use unsafe pointer arithmetic
960                if let HirExpression::Variable(var_name) = &**array {
961                    if ctx.is_pointer(var_name) {
962                        // Raw pointer indexing: arr[i] becomes unsafe { *arr.add(i as usize) }
963                        return format!(
964                            "unsafe {{ *{}.add({} as usize) }}",
965                            array_code, index_code
966                        );
967                    }
968                }
969
970                // Regular array/slice indexing
971                // DECY-072: Cast index to usize for slice indexing
972                format!("{}[{} as usize]", array_code, index_code)
973            }
974            HirExpression::SliceIndex { slice, index, .. } => {
975                // DECY-070 GREEN: Generate safe slice indexing (0 unsafe blocks!)
976                // SliceIndex represents pointer arithmetic transformed to safe indexing
977                let slice_code = self.generate_expression_with_context(slice, ctx);
978                let index_code = self.generate_expression_with_context(index, ctx);
979                // Generate: slice[index] - guaranteed safe, bounds-checked at runtime
980                format!("{}[{}]", slice_code, index_code)
981            }
982            HirExpression::Sizeof { type_name } => {
983                // sizeof(int) → std::mem::size_of::<i32>() as i32
984                // sizeof(struct Data) → std::mem::size_of::<Data>() as i32
985                // Note: size_of returns usize, but C's sizeof returns int (typically i32)
986                let rust_type = self.map_sizeof_type(type_name);
987                format!("std::mem::size_of::<{}>() as i32", rust_type)
988            }
989            HirExpression::NullLiteral => {
990                // NULL → None
991                "None".to_string()
992            }
993            HirExpression::IsNotNull(inner) => {
994                // p != NULL → if let Some(p) = p
995                // This is a helper expression for generating Option checks
996                // In actual codegen, we transform if (p) to if let Some(_) = p
997                let inner_code = self.generate_expression_with_context(inner, ctx);
998                format!("if let Some(_) = {}", inner_code)
999            }
1000            HirExpression::Calloc {
1001                count,
1002                element_type,
1003            } => {
1004                // calloc(n, sizeof(T)) → vec![0T; n]
1005                // Generate zero-initialized vec![default; count]
1006                let count_code = self.generate_expression_with_context(count, ctx);
1007
1008                // Get default value with type suffix for clarity
1009                let default_value = match element_type.as_ref() {
1010                    HirType::Int => "0i32",
1011                    HirType::Float => "0.0f32",
1012                    HirType::Double => "0.0f64",
1013                    HirType::Char => "0u8",
1014                    _ => &Self::default_value_for_type(element_type),
1015                };
1016
1017                format!("vec![{}; {}]", default_value, count_code)
1018            }
1019            HirExpression::Malloc { size } => {
1020                // malloc(size) should have been transformed to Box or Vec by analyzer
1021                // If we're generating this directly, treat it as Box::new(default)
1022                // Note: The proper transformation should happen at HIR level via PatternDetector
1023
1024                // Try to detect if this is an array allocation (n * sizeof(T))
1025                // If so, generate Vec::with_capacity
1026                if let HirExpression::BinaryOp {
1027                    op: decy_hir::BinaryOperator::Multiply,
1028                    left,
1029                    ..
1030                } = size.as_ref()
1031                {
1032                    // This looks like n * sizeof(T) → Vec::with_capacity(n)
1033                    let capacity_code = self.generate_expression_with_context(left, ctx);
1034                    format!("Vec::with_capacity({})", capacity_code)
1035                } else {
1036                    // Single allocation → Box::new(default)
1037                    "Box::new(0i32)".to_string()
1038                }
1039            }
1040            HirExpression::Realloc { pointer, new_size } => {
1041                // realloc(ptr, new_size) transformation depends on context:
1042                // 1. realloc(NULL, size) → treat as malloc (Vec allocation)
1043                // 2. realloc(ptr, 0) → treat as free (RAII comment or clear)
1044                // 3. realloc(ptr, new_size) → vec.resize(new_count, default)
1045                //
1046                // Since we're generating an expression here, we'll return a placeholder
1047                // The actual transformation should happen in Assignment statement handling
1048                // For now, just generate a comment indicating this needs special handling
1049
1050                // Check if pointer is NULL → malloc equivalent
1051                if matches!(**pointer, HirExpression::NullLiteral) {
1052                    // realloc(NULL, size) → vec![default; count]
1053                    if let HirExpression::BinaryOp {
1054                        op: decy_hir::BinaryOperator::Multiply,
1055                        left,
1056                        ..
1057                    } = new_size.as_ref()
1058                    {
1059                        let count_code = self.generate_expression_with_context(left, ctx);
1060                        format!("vec![0i32; {}]", count_code)
1061                    } else {
1062                        "Vec::new()".to_string()
1063                    }
1064                } else {
1065                    // realloc(ptr, size) - this should be handled at statement level
1066                    // For expression context, return the pointer unchanged as a placeholder
1067                    self.generate_expression_with_context(pointer, ctx)
1068                }
1069            }
1070            HirExpression::StringMethodCall {
1071                receiver,
1072                method,
1073                arguments,
1074            } => {
1075                let receiver_code = self.generate_expression_with_context(receiver, ctx);
1076                if arguments.is_empty() {
1077                    // DECY-072: Cast .len() to i32 when used with integer comparisons
1078                    if method == "len" {
1079                        format!("{}.{}() as i32", receiver_code, method)
1080                    } else {
1081                        format!("{}.{}()", receiver_code, method)
1082                    }
1083                } else {
1084                    let args: Vec<String> = arguments
1085                        .iter()
1086                        .map(|arg| {
1087                            // For clone_into, we need &mut on the destination
1088                            if method == "clone_into" {
1089                                format!("&mut {}", self.generate_expression_with_context(arg, ctx))
1090                            } else {
1091                                self.generate_expression_with_context(arg, ctx)
1092                            }
1093                        })
1094                        .collect();
1095                    format!("{}.{}({})", receiver_code, method, args.join(", "))
1096                }
1097            }
1098            HirExpression::Cast { target_type, expr } => {
1099                // C: (int)x → Rust: x as i32
1100                // Sprint 19 Feature (DECY-059)
1101                let expr_code = self.generate_expression_with_context(expr, ctx);
1102                let rust_type = Self::map_type(target_type);
1103
1104                // Wrap in parentheses if the expression is a binary operation
1105                let expr_str = if matches!(**expr, HirExpression::BinaryOp { .. }) {
1106                    format!("({})", expr_code)
1107                } else {
1108                    expr_code
1109                };
1110
1111                format!("{} as {}", expr_str, rust_type)
1112            }
1113            HirExpression::CompoundLiteral {
1114                literal_type,
1115                initializers,
1116            } => {
1117                // C: (struct Point){10, 20} → Rust: Point { field0: 10, field1: 20 }
1118                // C: (int[]){1, 2, 3} → Rust: vec![1, 2, 3] or [1, 2, 3]
1119                // Sprint 19 Feature (DECY-060)
1120                match literal_type {
1121                    HirType::Struct(name) => {
1122                        // Generate struct literal: StructName { field0: val0, field1: val1, ... }
1123                        if initializers.is_empty() {
1124                            // Empty struct: Point {}
1125                            format!("{} {{}}", name)
1126                        } else {
1127                            let fields: Vec<String> = initializers
1128                                .iter()
1129                                .enumerate()
1130                                .map(|(i, init)| {
1131                                    let init_code =
1132                                        self.generate_expression_with_context(init, ctx);
1133                                    format!("field{}: {}", i, init_code)
1134                                })
1135                                .collect();
1136                            format!("{} {{ {} }}", name, fields.join(", "))
1137                        }
1138                    }
1139                    HirType::Array { .. } => {
1140                        // Generate array literal: vec![1, 2, 3] or [1, 2, 3]
1141                        if initializers.is_empty() {
1142                            "vec![]".to_string()
1143                        } else {
1144                            let elements: Vec<String> = initializers
1145                                .iter()
1146                                .map(|init| self.generate_expression_with_context(init, ctx))
1147                                .collect();
1148                            format!("vec![{}]", elements.join(", "))
1149                        }
1150                    }
1151                    _ => {
1152                        // For other types, generate a reasonable default
1153                        // This is a simplified implementation
1154                        format!(
1155                            "/* Compound literal of type {} */",
1156                            Self::map_type(literal_type)
1157                        )
1158                    }
1159                }
1160            }
1161        }
1162    }
1163
1164    /// Convert unary operator to string.
1165    fn unary_operator_to_string(op: &decy_hir::UnaryOperator) -> &'static str {
1166        use decy_hir::UnaryOperator;
1167        match op {
1168            UnaryOperator::Minus => "-",
1169            UnaryOperator::LogicalNot => "!",
1170            UnaryOperator::BitwiseNot => "~",
1171            UnaryOperator::AddressOf => "&",
1172            // Post/Pre-increment/decrement are handled as block expressions
1173            // in generate_expression_with_context, so should never reach here
1174            UnaryOperator::PostIncrement
1175            | UnaryOperator::PostDecrement
1176            | UnaryOperator::PreIncrement
1177            | UnaryOperator::PreDecrement => {
1178                unreachable!("Increment/decrement operators should be handled as block expressions")
1179            }
1180        }
1181    }
1182
1183    /// Convert binary operator to string.
1184    fn binary_operator_to_string(op: &BinaryOperator) -> &'static str {
1185        match op {
1186            BinaryOperator::Add => "+",
1187            BinaryOperator::Subtract => "-",
1188            BinaryOperator::Multiply => "*",
1189            BinaryOperator::Divide => "/",
1190            BinaryOperator::Modulo => "%",
1191            BinaryOperator::Equal => "==",
1192            BinaryOperator::NotEqual => "!=",
1193            BinaryOperator::LessThan => "<",
1194            BinaryOperator::GreaterThan => ">",
1195            BinaryOperator::LessEqual => "<=",
1196            BinaryOperator::GreaterEqual => ">=",
1197            BinaryOperator::LogicalAnd => "&&",
1198            BinaryOperator::LogicalOr => "||",
1199        }
1200    }
1201
1202    /// Get default value for a type (for uninitialized variables).
1203    fn default_value_for_type(hir_type: &HirType) -> String {
1204        match hir_type {
1205            HirType::Void => "()".to_string(),
1206            HirType::Int => "0i32".to_string(),
1207            HirType::Float => "0.0f32".to_string(),
1208            HirType::Double => "0.0f64".to_string(),
1209            HirType::Char => "0u8".to_string(),
1210            HirType::Pointer(_) => "std::ptr::null_mut()".to_string(),
1211            HirType::Box(inner) => {
1212                // Box types should not use default values, they should be initialized with Box::new
1213                // This is just a fallback
1214                format!("Box::new({})", Self::default_value_for_type(inner))
1215            }
1216            HirType::Vec(_) => {
1217                // Vec types default to empty Vec
1218                "Vec::new()".to_string()
1219            }
1220            HirType::Option(_) => {
1221                // Option types default to None
1222                "None".to_string()
1223            }
1224            HirType::Reference { .. } => {
1225                // References cannot have default values - they must always be initialized
1226                // This should never be reached in valid code
1227                panic!("References must be initialized and cannot have default values")
1228            }
1229            HirType::Struct(name) => {
1230                format!("{}::default()", name)
1231            }
1232            HirType::Enum(name) => {
1233                format!("{}::default()", name)
1234            }
1235            HirType::Array { element_type, size } => {
1236                if let Some(n) = size {
1237                    format!("[{}; {}]", Self::default_value_for_type(element_type), n)
1238                } else {
1239                    // Unsized arrays cannot have default values - this should be initialized from parameter
1240                    panic!("Unsized arrays must be initialized and cannot have default values")
1241                }
1242            }
1243            HirType::FunctionPointer { .. } => {
1244                // Function pointers cannot have meaningful default values
1245                // They must be initialized with an actual function
1246                panic!("Function pointers must be initialized and cannot have default values")
1247            }
1248            HirType::StringLiteral => {
1249                // String literals default to empty string slice
1250                r#""""#.to_string()
1251            }
1252            HirType::OwnedString => {
1253                // Owned strings default to String::new()
1254                "String::new()".to_string()
1255            }
1256            HirType::StringReference => {
1257                // String references default to empty string slice
1258                r#""""#.to_string()
1259            }
1260        }
1261    }
1262
1263    /// Generate code for a statement.
1264    pub fn generate_statement(&self, stmt: &HirStatement) -> String {
1265        self.generate_statement_for_function(stmt, None)
1266    }
1267
1268    /// Generate code for a statement, with optional function context.
1269    ///
1270    /// When function_name is "main", special handling applies (DECY-AUDIT-001):
1271    /// - return N; becomes std::process::exit(N);
1272    fn generate_statement_for_function(
1273        &self,
1274        stmt: &HirStatement,
1275        function_name: Option<&str>,
1276    ) -> String {
1277        self.generate_statement_with_context(stmt, function_name, &mut TypeContext::new(), None)
1278    }
1279
1280    /// Generate code for a statement with type context for pointer arithmetic and return type for null pointer detection.
1281    fn generate_statement_with_context(
1282        &self,
1283        stmt: &HirStatement,
1284        function_name: Option<&str>,
1285        ctx: &mut TypeContext,
1286        return_type: Option<&HirType>,
1287    ) -> String {
1288        match stmt {
1289            HirStatement::VariableDeclaration {
1290                name,
1291                var_type,
1292                initializer,
1293            } => {
1294                // Check for VLA pattern: Array with size: None and an initializer
1295                // C99 VLA: int arr[n]; where n is runtime-determined
1296                // Rust: let arr = vec![0i32; n];
1297                if let HirType::Array {
1298                    element_type,
1299                    size: None,
1300                } = var_type
1301                {
1302                    // This is a VLA - transform to Vec
1303                    if let Some(size_expr) = initializer {
1304                        // VLA → Vec
1305                        let size_code = self.generate_expression_with_context(size_expr, ctx);
1306                        let default_value = match element_type.as_ref() {
1307                            HirType::Int => "0i32",
1308                            HirType::Float => "0.0f32",
1309                            HirType::Double => "0.0f64",
1310                            HirType::Char => "0u8",
1311                            _ => &Self::default_value_for_type(element_type),
1312                        };
1313
1314                        // Register the variable as Vec type in context
1315                        ctx.add_variable(
1316                            name.clone(),
1317                            HirType::Vec(Box::new(element_type.as_ref().clone())),
1318                        );
1319
1320                        return format!(
1321                            "let mut {} = vec![{}; {}];",
1322                            name, default_value, size_code
1323                        );
1324                    }
1325                }
1326
1327                // Add variable to type context for pointer arithmetic detection
1328                ctx.add_variable(name.clone(), var_type.clone());
1329
1330                let mut code = format!("let mut {}: {}", name, Self::map_type(var_type));
1331                if let Some(init_expr) = initializer {
1332                    // Special handling for Malloc expressions - use var_type to generate correct Box::new
1333                    if matches!(init_expr, HirExpression::Malloc { .. }) {
1334                        // Malloc → Box::new or Vec (depending on var_type)
1335                        match var_type {
1336                            HirType::Box(inner) => {
1337                                code.push_str(&format!(
1338                                    " = Box::new({});",
1339                                    Self::default_value_for_type(inner)
1340                                ));
1341                            }
1342                            HirType::Vec(_) => {
1343                                // Extract capacity from malloc size expression
1344                                if let HirExpression::Malloc { size } = init_expr {
1345                                    if let HirExpression::BinaryOp {
1346                                        op: decy_hir::BinaryOperator::Multiply,
1347                                        left,
1348                                        ..
1349                                    } = size.as_ref()
1350                                    {
1351                                        let capacity_code =
1352                                            self.generate_expression_with_context(left, ctx);
1353                                        code.push_str(&format!(
1354                                            " = Vec::with_capacity({});",
1355                                            capacity_code
1356                                        ));
1357                                    } else {
1358                                        code.push_str(" = Vec::new();");
1359                                    }
1360                                } else {
1361                                    code.push_str(" = Vec::new();");
1362                                }
1363                            }
1364                            _ => {
1365                                // Default to Box::new(0i32) for other types
1366                                code.push_str(" = Box::new(0i32);");
1367                            }
1368                        }
1369                    } else {
1370                        // Pass var_type as target type hint for null pointer detection
1371                        code.push_str(&format!(
1372                            " = {};",
1373                            self.generate_expression_with_target_type(
1374                                init_expr,
1375                                ctx,
1376                                Some(var_type)
1377                            )
1378                        ));
1379                    }
1380                } else {
1381                    // Provide default value for uninitialized variables
1382                    code.push_str(&format!(" = {};", Self::default_value_for_type(var_type)));
1383                }
1384                code
1385            }
1386            HirStatement::Return(expr_opt) => {
1387                // Special handling for main function (DECY-AUDIT-001)
1388                // return N; in main becomes std::process::exit(N);
1389                if function_name == Some("main") {
1390                    if let Some(expr) = expr_opt {
1391                        format!(
1392                            "std::process::exit({});",
1393                            self.generate_expression_with_context(expr, ctx)
1394                        )
1395                    } else {
1396                        "std::process::exit(0);".to_string()
1397                    }
1398                } else if let Some(expr) = expr_opt {
1399                    // Pass return type as target type hint for null pointer detection
1400                    format!(
1401                        "return {};",
1402                        self.generate_expression_with_target_type(expr, ctx, return_type)
1403                    )
1404                } else {
1405                    "return;".to_string()
1406                }
1407            }
1408            HirStatement::If {
1409                condition,
1410                then_block,
1411                else_block,
1412            } => {
1413                let mut code = String::new();
1414
1415                // Generate if condition
1416                code.push_str(&format!(
1417                    "if {} {{\n",
1418                    self.generate_expression_with_context(condition, ctx)
1419                ));
1420
1421                // Generate then block
1422                for stmt in then_block {
1423                    code.push_str("    ");
1424                    code.push_str(&self.generate_statement_with_context(
1425                        stmt,
1426                        function_name,
1427                        ctx,
1428                        return_type,
1429                    ));
1430                    code.push('\n');
1431                }
1432
1433                // Generate else block if present
1434                if let Some(else_stmts) = else_block {
1435                    code.push_str("} else {\n");
1436                    for stmt in else_stmts {
1437                        code.push_str("    ");
1438                        code.push_str(&self.generate_statement_with_context(
1439                            stmt,
1440                            function_name,
1441                            ctx,
1442                            return_type,
1443                        ));
1444                        code.push('\n');
1445                    }
1446                }
1447
1448                code.push('}');
1449                code
1450            }
1451            HirStatement::While { condition, body } => {
1452                let mut code = String::new();
1453
1454                // Generate while condition
1455                code.push_str(&format!(
1456                    "while {} {{\n",
1457                    self.generate_expression_with_context(condition, ctx)
1458                ));
1459
1460                // Generate loop body
1461                for stmt in body {
1462                    code.push_str("    ");
1463                    code.push_str(&self.generate_statement_with_context(
1464                        stmt,
1465                        function_name,
1466                        ctx,
1467                        return_type,
1468                    ));
1469                    code.push('\n');
1470                }
1471
1472                code.push('}');
1473                code
1474            }
1475            HirStatement::Break => "break;".to_string(),
1476            HirStatement::Continue => "continue;".to_string(),
1477            HirStatement::Assignment { target, value } => {
1478                // Special handling for realloc() → Vec::resize/truncate/clear
1479                if let HirExpression::Realloc { pointer, new_size } = value {
1480                    // target is a String (variable name) in Assignment statements
1481                    let target_var = target.clone();
1482
1483                    // Check if target is a Vec type to get element type
1484                    let element_type = if let Some(HirType::Vec(inner)) = ctx.get_type(&target_var)
1485                    {
1486                        inner.as_ref().clone()
1487                    } else {
1488                        // Fallback: assume i32
1489                        HirType::Int
1490                    };
1491
1492                    // Check special cases:
1493                    // 1. realloc(ptr, 0) → clear or RAII comment
1494                    if let HirExpression::IntLiteral(0) = **new_size {
1495                        return format!("{}.clear(); // Free equivalent: clear vector", target_var);
1496                    }
1497
1498                    // 2. realloc(NULL, size) → should not appear in assignment (would be in initializer)
1499                    //    but handle it gracefully if it does
1500                    if matches!(**pointer, HirExpression::NullLiteral) {
1501                        // This is essentially malloc - but in assignment context, we'll treat it as resize from 0
1502                        if let HirExpression::BinaryOp {
1503                            op: decy_hir::BinaryOperator::Multiply,
1504                            left,
1505                            ..
1506                        } = new_size.as_ref()
1507                        {
1508                            let count_code = self.generate_expression_with_context(left, ctx);
1509                            let default_value = Self::default_value_for_type(&element_type);
1510                            return format!(
1511                                "{}.resize({}, {})",
1512                                target_var, count_code, default_value
1513                            );
1514                        }
1515                    }
1516
1517                    // 3. realloc(ptr, new_size) → vec.resize(new_count, default)
1518                    // Extract count from new_size (typically n * sizeof(T))
1519                    if let HirExpression::BinaryOp {
1520                        op: decy_hir::BinaryOperator::Multiply,
1521                        left,
1522                        ..
1523                    } = new_size.as_ref()
1524                    {
1525                        let count_code = self.generate_expression_with_context(left, ctx);
1526                        let default_value = Self::default_value_for_type(&element_type);
1527                        format!("{}.resize({}, {});", target_var, count_code, default_value)
1528                    } else {
1529                        // Fallback: if new_size is not n * sizeof(T), generate direct resize
1530                        // This handles edge cases where size isn't n * sizeof(T)
1531                        let size_expr = self.generate_expression_with_context(new_size, ctx);
1532                        let default_value = Self::default_value_for_type(&element_type);
1533                        format!(
1534                            "{}.resize({} as usize, {});",
1535                            target_var, size_expr, default_value
1536                        )
1537                    }
1538                } else {
1539                    // Regular assignment (not realloc)
1540                    let target_type = ctx.get_type(target);
1541                    format!(
1542                        "{} = {};",
1543                        target,
1544                        self.generate_expression_with_target_type(value, ctx, target_type)
1545                    )
1546                }
1547            }
1548            HirStatement::For {
1549                init,
1550                condition,
1551                increment,
1552                body,
1553            } => {
1554                let mut code = String::new();
1555
1556                // Generate init statement before loop (if present)
1557                if let Some(init_stmt) = init {
1558                    code.push_str(&self.generate_statement_with_context(
1559                        init_stmt,
1560                        function_name,
1561                        ctx,
1562                        return_type,
1563                    ));
1564                    code.push('\n');
1565                }
1566
1567                // Generate while loop with condition
1568                code.push_str(&format!(
1569                    "while {} {{\n",
1570                    self.generate_expression_with_context(condition, ctx)
1571                ));
1572
1573                // Generate loop body
1574                for stmt in body {
1575                    code.push_str("    ");
1576                    code.push_str(&self.generate_statement_with_context(
1577                        stmt,
1578                        function_name,
1579                        ctx,
1580                        return_type,
1581                    ));
1582                    code.push('\n');
1583                }
1584
1585                // Generate increment at end of body (if present)
1586                if let Some(inc_stmt) = increment {
1587                    code.push_str("    ");
1588                    code.push_str(&self.generate_statement_with_context(
1589                        inc_stmt,
1590                        function_name,
1591                        ctx,
1592                        return_type,
1593                    ));
1594                    code.push('\n');
1595                }
1596
1597                code.push('}');
1598                code
1599            }
1600            HirStatement::Switch {
1601                condition,
1602                cases,
1603                default_case,
1604            } => {
1605                let mut code = String::new();
1606
1607                // Generate match expression
1608                code.push_str(&format!(
1609                    "match {} {{\n",
1610                    self.generate_expression_with_context(condition, ctx)
1611                ));
1612
1613                // Generate each case
1614                for case in cases {
1615                    if let Some(value_expr) = &case.value {
1616                        // Generate case pattern
1617                        code.push_str(&format!(
1618                            "    {} => {{\n",
1619                            self.generate_expression_with_context(value_expr, ctx)
1620                        ));
1621
1622                        // Generate case body (filter out Break statements)
1623                        for stmt in &case.body {
1624                            if !matches!(stmt, HirStatement::Break) {
1625                                code.push_str("        ");
1626                                code.push_str(&self.generate_statement_with_context(
1627                                    stmt,
1628                                    function_name,
1629                                    ctx,
1630                                    return_type,
1631                                ));
1632                                code.push('\n');
1633                            }
1634                        }
1635
1636                        code.push_str("    },\n");
1637                    }
1638                }
1639
1640                // Generate default case (or empty default if not present)
1641                code.push_str("    _ => {\n");
1642                if let Some(default_stmts) = default_case {
1643                    for stmt in default_stmts {
1644                        if !matches!(stmt, HirStatement::Break) {
1645                            code.push_str("        ");
1646                            code.push_str(&self.generate_statement_with_context(
1647                                stmt,
1648                                function_name,
1649                                ctx,
1650                                return_type,
1651                            ));
1652                            code.push('\n');
1653                        }
1654                    }
1655                }
1656                code.push_str("    },\n");
1657
1658                code.push('}');
1659                code
1660            }
1661            HirStatement::DerefAssignment { target, value } => {
1662                // Infer the type of *target for null pointer detection
1663                let target_type = ctx
1664                    .infer_expression_type(&HirExpression::Dereference(Box::new(target.clone())));
1665                format!(
1666                    "*{} = {};",
1667                    self.generate_expression_with_context(target, ctx),
1668                    self.generate_expression_with_target_type(value, ctx, target_type.as_ref())
1669                )
1670            }
1671            HirStatement::ArrayIndexAssignment {
1672                array,
1673                index,
1674                value,
1675            } => {
1676                // Infer the type of array[index] for null pointer detection
1677                let target_expr = HirExpression::ArrayIndex {
1678                    array: array.clone(),
1679                    index: index.clone(),
1680                };
1681                let target_type = ctx.infer_expression_type(&target_expr);
1682                // DECY-072: Cast index to usize for slice indexing
1683                format!(
1684                    "{}[{} as usize] = {};",
1685                    self.generate_expression_with_context(array, ctx),
1686                    self.generate_expression_with_context(index, ctx),
1687                    self.generate_expression_with_target_type(value, ctx, target_type.as_ref())
1688                )
1689            }
1690            HirStatement::FieldAssignment {
1691                object,
1692                field,
1693                value,
1694            } => {
1695                // Look up field type for null pointer detection
1696                let field_type = ctx.get_field_type(object, field);
1697                // Generate obj.field = value (works for both ptr->field and obj.field in Rust)
1698                format!(
1699                    "{}.{} = {};",
1700                    self.generate_expression_with_context(object, ctx),
1701                    field,
1702                    self.generate_expression_with_target_type(value, ctx, field_type.as_ref())
1703                )
1704            }
1705            HirStatement::Free { pointer } => {
1706                // free(ptr) → automatic drop via RAII
1707                // Generate a comment explaining that the memory will be deallocated automatically
1708                // when the variable goes out of scope
1709                let pointer_name = match pointer {
1710                    HirExpression::Variable(name) => name.clone(),
1711                    _ => self.generate_expression_with_context(pointer, ctx),
1712                };
1713                format!(
1714                    "// Memory for '{}' deallocated automatically by RAII",
1715                    pointer_name
1716                )
1717            }
1718            HirStatement::Expression(expr) => {
1719                // Expression statement: function calls, increments, etc. for side effects
1720                // DECY-065: Added to fix printf() and other function call statement bugs
1721                // C: printf("Hello"); → Rust: printf("Hello");
1722                format!("{};", self.generate_expression_with_context(expr, ctx))
1723            }
1724        }
1725    }
1726
1727    /// Generate a function signature from HIR.
1728    ///
1729    /// # Examples
1730    ///
1731    /// ```
1732    /// use decy_codegen::CodeGenerator;
1733    /// use decy_hir::{HirFunction, HirType};
1734    ///
1735    /// let func = HirFunction::new("test".to_string(), HirType::Void, vec![]);
1736    /// let codegen = CodeGenerator::new();
1737    /// let sig = codegen.generate_signature(&func);
1738    ///
1739    /// assert_eq!(sig, "fn test()");
1740    /// ```
1741    pub fn generate_signature(&self, func: &HirFunction) -> String {
1742        // DECY-076 GREEN: Generate lifetime annotations using LifetimeAnnotator
1743        use decy_ownership::lifetime_gen::LifetimeAnnotator;
1744        let lifetime_annotator = LifetimeAnnotator::new();
1745        let annotated_sig = lifetime_annotator.annotate_function(func);
1746
1747        let mut sig = format!("fn {}", func.name());
1748
1749        // Add lifetime parameters if needed
1750        let lifetime_syntax = lifetime_annotator.generate_lifetime_syntax(&annotated_sig.lifetimes);
1751        sig.push_str(&lifetime_syntax);
1752
1753        // DECY-072 GREEN: Detect array parameters using ownership analysis
1754        use decy_ownership::dataflow::DataflowAnalyzer;
1755        let analyzer = DataflowAnalyzer::new();
1756        let graph = analyzer.analyze(func);
1757
1758        // Track which parameters are length parameters to skip them
1759        let mut skip_params = std::collections::HashSet::new();
1760
1761        // First pass: identify array parameters and their associated length parameters
1762        for (idx, param) in func.parameters().iter().enumerate() {
1763            if let Some(true) = graph.is_array_parameter(param.name()) {
1764                // This is an array parameter - mark the next param as length param to skip
1765                if idx + 1 < func.parameters().len() {
1766                    let next_param = &func.parameters()[idx + 1];
1767                    if matches!(next_param.param_type(), HirType::Int) {
1768                        skip_params.insert(next_param.name().to_string());
1769                    }
1770                }
1771            }
1772        }
1773
1774        // Generate parameters with lifetime annotations
1775        sig.push('(');
1776        let params: Vec<String> = annotated_sig
1777            .parameters
1778            .iter()
1779            .filter_map(|p| {
1780                // Skip length parameters for array parameters
1781                if skip_params.contains(&p.name) {
1782                    return None;
1783                }
1784
1785                // Check if this is an array parameter
1786                let is_array = graph.is_array_parameter(&p.name).unwrap_or(false);
1787
1788                if is_array {
1789                    // Transform to slice parameter
1790                    // Find the original parameter to get the HirType
1791                    if let Some(orig_param) =
1792                        func.parameters().iter().find(|fp| fp.name() == p.name)
1793                    {
1794                        let is_mutable = self.is_parameter_modified(func, &p.name);
1795                        let slice_type =
1796                            self.pointer_to_slice_type(orig_param.param_type(), is_mutable);
1797                        // For slices, don't add 'mut' prefix (slices themselves aren't reassigned)
1798                        Some(format!("{}: {}", p.name, slice_type))
1799                    } else {
1800                        None
1801                    }
1802                } else {
1803                    // Regular parameter with lifetime annotation
1804                    let type_str = self.annotated_type_to_string(&p.param_type);
1805                    // In C, parameters are mutable by default (can be reassigned)
1806                    Some(format!("mut {}: {}", p.name, type_str))
1807                }
1808            })
1809            .collect();
1810        sig.push_str(&params.join(", "));
1811        sig.push(')');
1812
1813        // Special handling for main function (DECY-AUDIT-001)
1814        // C's int main() must become Rust's fn main() (no return type)
1815        // Rust's entry point returns () and uses std::process::exit(N) for exit codes
1816        if func.name() == "main" && matches!(func.return_type(), HirType::Int) {
1817            // Skip return type for main - it must be fn main()
1818            return sig;
1819        }
1820
1821        // Generate return type with lifetime annotation (skip for void)
1822        if !matches!(
1823            &annotated_sig.return_type,
1824            AnnotatedType::Simple(HirType::Void)
1825        ) {
1826            let return_type_str = self.annotated_type_to_string(&annotated_sig.return_type);
1827            sig.push_str(&format!(" -> {}", return_type_str));
1828        }
1829
1830        sig
1831    }
1832
1833    /// Check if a parameter is modified in the function body (DECY-072 GREEN).
1834    ///
1835    /// Used to determine whether to use &[T] or &mut [T] for array parameters.
1836    fn is_parameter_modified(&self, func: &HirFunction, param_name: &str) -> bool {
1837        // Check if the parameter is used in any assignment statements
1838        for stmt in func.body() {
1839            if self.statement_modifies_variable(stmt, param_name) {
1840                return true;
1841            }
1842        }
1843        false
1844    }
1845
1846    /// Recursively check if a statement modifies a variable (DECY-072 GREEN).
1847    #[allow(clippy::only_used_in_recursion)]
1848    fn statement_modifies_variable(&self, stmt: &HirStatement, var_name: &str) -> bool {
1849        match stmt {
1850            HirStatement::ArrayIndexAssignment { array, .. } => {
1851                // Check if this is arr[i] = value where arr is our variable
1852                if let HirExpression::Variable(name) = &**array {
1853                    return name == var_name;
1854                }
1855                false
1856            }
1857            HirStatement::DerefAssignment { target, .. } => {
1858                // Check if this is *ptr = value where ptr is our variable
1859                if let HirExpression::Variable(name) = target {
1860                    return name == var_name;
1861                }
1862                false
1863            }
1864            HirStatement::If {
1865                then_block,
1866                else_block,
1867                ..
1868            } => {
1869                then_block
1870                    .iter()
1871                    .any(|s| self.statement_modifies_variable(s, var_name))
1872                    || else_block.as_ref().is_some_and(|blk| {
1873                        blk.iter()
1874                            .any(|s| self.statement_modifies_variable(s, var_name))
1875                    })
1876            }
1877            HirStatement::While { body, .. } | HirStatement::For { body, .. } => body
1878                .iter()
1879                .any(|s| self.statement_modifies_variable(s, var_name)),
1880            _ => false,
1881        }
1882    }
1883
1884    /// Convert a pointer type to a slice type (DECY-072 GREEN).
1885    ///
1886    /// Transforms `*mut T` or `*const T` to `&[T]` or `&mut [T]`.
1887    fn pointer_to_slice_type(&self, ptr_type: &HirType, is_mutable: bool) -> String {
1888        if let HirType::Pointer(inner) = ptr_type {
1889            let element_type = Self::map_type(inner);
1890            if is_mutable {
1891                format!("&mut [{}]", element_type)
1892            } else {
1893                format!("&[{}]", element_type)
1894            }
1895        } else {
1896            // Fallback: not a pointer, use normal mapping
1897            Self::map_type(ptr_type)
1898        }
1899    }
1900
1901    /// Transform length parameter references to array.len() calls (DECY-072 GREEN).
1902    ///
1903    /// Replaces variable references like `len` with `arr.len()` in generated code.
1904    fn transform_length_refs(
1905        &self,
1906        code: &str,
1907        length_to_array: &std::collections::HashMap<String, String>,
1908    ) -> String {
1909        let mut result = code.to_string();
1910
1911        // Replace each length parameter reference with corresponding array.len() call
1912        for (length_param, array_param) in length_to_array {
1913            // Match the length parameter as a standalone identifier
1914            // Use word boundaries to avoid partial matches
1915            // Common patterns: "return len", "x + len", "len)", etc.
1916            let patterns = vec![
1917                (
1918                    format!("return {}", length_param),
1919                    format!("return {}.len() as i32", array_param),
1920                ),
1921                (
1922                    format!("{} ", length_param),
1923                    format!("{}.len() as i32 ", array_param),
1924                ),
1925                (
1926                    format!("{})", length_param),
1927                    format!("{}.len() as i32)", array_param),
1928                ),
1929                (
1930                    format!("{},", length_param),
1931                    format!("{}.len() as i32,", array_param),
1932                ),
1933                (
1934                    format!("{}]", length_param),
1935                    format!("{}.len() as i32]", array_param),
1936                ),
1937                (
1938                    length_param.clone() + "}",
1939                    array_param.clone() + ".len() as i32}",
1940                ),
1941                (
1942                    format!("{};", length_param),
1943                    format!("{}.len() as i32;", array_param),
1944                ),
1945            ];
1946
1947            for (pattern, replacement) in patterns {
1948                result = result.replace(&pattern, &replacement);
1949            }
1950        }
1951
1952        result
1953    }
1954
1955    /// Generate a function signature with lifetime annotations.
1956    ///
1957    /// Takes an `AnnotatedSignature` with lifetime information and generates
1958    /// the complete Rust function signature including lifetime parameters.
1959    ///
1960    /// # Examples
1961    ///
1962    /// ```
1963    /// use decy_codegen::CodeGenerator;
1964    /// use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedParameter, AnnotatedType, LifetimeParam};
1965    /// use decy_hir::HirType;
1966    ///
1967    /// let sig = AnnotatedSignature {
1968    ///     name: "get_first".to_string(),
1969    ///     lifetimes: vec![LifetimeParam::standard(0)], // 'a
1970    ///     parameters: vec![
1971    ///         AnnotatedParameter {
1972    ///             name: "items".to_string(),
1973    ///             param_type: AnnotatedType::Reference {
1974    ///                 inner: Box::new(AnnotatedType::Simple(HirType::Int)),
1975    ///                 mutable: false,
1976    ///                 lifetime: Some(LifetimeParam::standard(0)),
1977    ///             },
1978    ///         },
1979    ///     ],
1980    ///     return_type: AnnotatedType::Reference {
1981    ///         inner: Box::new(AnnotatedType::Simple(HirType::Int)),
1982    ///         mutable: false,
1983    ///         lifetime: Some(LifetimeParam::standard(0)),
1984    ///     },
1985    /// };
1986    ///
1987    /// let codegen = CodeGenerator::new();
1988    /// let rust_sig = codegen.generate_annotated_signature(&sig);
1989    ///
1990    /// assert!(rust_sig.contains("<'a>"));
1991    /// assert!(rust_sig.contains("&'a i32"));
1992    /// ```
1993    pub fn generate_annotated_signature(&self, sig: &AnnotatedSignature) -> String {
1994        let mut result = format!("fn {}", sig.name);
1995
1996        // Add lifetime parameters if present
1997        if !sig.lifetimes.is_empty() {
1998            let lifetime_params: Vec<String> =
1999                sig.lifetimes.iter().map(|lt| lt.name.clone()).collect();
2000            result.push_str(&format!("<{}>", lifetime_params.join(", ")));
2001        }
2002
2003        // Add function parameters
2004        result.push('(');
2005        let params: Vec<String> = sig
2006            .parameters
2007            .iter()
2008            .map(|p| {
2009                // DECY-041: Add mut for all parameters to match C semantics
2010                // In C, parameters are mutable by default (can be reassigned)
2011                // DECY-FUTURE: More sophisticated analysis to only add mut when needed
2012                format!(
2013                    "mut {}: {}",
2014                    p.name,
2015                    self.annotated_type_to_string(&p.param_type)
2016                )
2017            })
2018            .collect();
2019        result.push_str(&params.join(", "));
2020        result.push(')');
2021
2022        // Special handling for main function (DECY-AUDIT-001)
2023        // C's int main() must become Rust's fn main() (no return type)
2024        // Rust's entry point returns () and uses std::process::exit(N) for exit codes
2025        let return_type_str = self.annotated_type_to_string(&sig.return_type);
2026        if sig.name == "main" && return_type_str == "i32" {
2027            // Skip return type for main - it must be fn main()
2028            return result;
2029        }
2030
2031        // Add return type if not void
2032        if return_type_str != "()" {
2033            result.push_str(&format!(" -> {}", return_type_str));
2034        }
2035
2036        result
2037    }
2038
2039    /// Convert an `AnnotatedType` to Rust type string with lifetime annotations.
2040    ///
2041    /// # Examples
2042    ///
2043    /// ```
2044    /// use decy_codegen::CodeGenerator;
2045    /// use decy_ownership::lifetime_gen::{AnnotatedType, LifetimeParam};
2046    /// use decy_hir::HirType;
2047    ///
2048    /// let codegen = CodeGenerator::new();
2049    ///
2050    /// // Simple type
2051    /// let simple = AnnotatedType::Simple(HirType::Int);
2052    /// assert_eq!(codegen.annotated_type_to_string(&simple), "i32");
2053    ///
2054    /// // Reference with lifetime
2055    /// let ref_type = AnnotatedType::Reference {
2056    ///     inner: Box::new(AnnotatedType::Simple(HirType::Int)),
2057    ///     mutable: false,
2058    ///     lifetime: Some(LifetimeParam::standard(0)),
2059    /// };
2060    /// assert_eq!(codegen.annotated_type_to_string(&ref_type), "&'a i32");
2061    /// ```
2062    #[allow(clippy::only_used_in_recursion)]
2063    pub fn annotated_type_to_string(&self, annotated_type: &AnnotatedType) -> String {
2064        match annotated_type {
2065            AnnotatedType::Simple(hir_type) => Self::map_type(hir_type),
2066            AnnotatedType::Reference {
2067                inner,
2068                mutable,
2069                lifetime,
2070            } => {
2071                let mut result = String::from("&");
2072
2073                // Add lifetime if present
2074                if let Some(lt) = lifetime {
2075                    result.push_str(&lt.name);
2076                    result.push(' ');
2077                }
2078
2079                // Add mutability
2080                if *mutable {
2081                    result.push_str("mut ");
2082                }
2083
2084                // Add inner type
2085                result.push_str(&self.annotated_type_to_string(inner));
2086
2087                result
2088            }
2089        }
2090    }
2091
2092    /// Generate a default return statement for a type.
2093    ///
2094    /// # Examples
2095    ///
2096    /// ```
2097    /// use decy_codegen::CodeGenerator;
2098    /// use decy_hir::HirType;
2099    ///
2100    /// let codegen = CodeGenerator::new();
2101    /// assert!(codegen.generate_return(&HirType::Int).contains("return 0"));
2102    /// ```
2103    pub fn generate_return(&self, return_type: &HirType) -> String {
2104        match return_type {
2105            HirType::Void => String::new(),
2106            HirType::Int => "    return 0;".to_string(),
2107            HirType::Float => "    return 0.0;".to_string(),
2108            HirType::Double => "    return 0.0;".to_string(),
2109            HirType::Char => "    return 0;".to_string(),
2110            HirType::Pointer(_) => "    return std::ptr::null_mut();".to_string(),
2111            HirType::Box(inner) => {
2112                format!(
2113                    "    return Box::new({});",
2114                    Self::default_value_for_type(inner)
2115                )
2116            }
2117            HirType::Vec(_) => "    return Vec::new();".to_string(),
2118            HirType::Option(_) => "    return None;".to_string(),
2119            HirType::Reference { .. } => {
2120                // References in return position need concrete values from parameters
2121                // This should be handled by lifetime-annotated code generation
2122                // using generate_function_with_lifetimes() instead
2123                String::new()
2124            }
2125            HirType::Struct(name) => {
2126                format!("    return {}::default();", name)
2127            }
2128            HirType::Enum(name) => {
2129                format!("    return {}::default();", name)
2130            }
2131            HirType::Array { element_type, size } => {
2132                if let Some(n) = size {
2133                    format!(
2134                        "    return [{}; {}];",
2135                        Self::default_value_for_type(element_type),
2136                        n
2137                    )
2138                } else {
2139                    // Unsized arrays in return position don't make sense
2140                    String::new()
2141                }
2142            }
2143            HirType::FunctionPointer { .. } => {
2144                // Function pointers in return position need concrete function values
2145                // This should be handled by the function body
2146                String::new()
2147            }
2148            HirType::StringLiteral => r#"    return "";"#.to_string(),
2149            HirType::OwnedString => "    return String::new();".to_string(),
2150            HirType::StringReference => r#"    return "";"#.to_string(),
2151        }
2152    }
2153
2154    /// Generate a complete function from HIR.
2155    ///
2156    /// # Examples
2157    ///
2158    /// ```
2159    /// use decy_codegen::CodeGenerator;
2160    /// use decy_hir::{HirFunction, HirType, HirParameter};
2161    ///
2162    /// let func = HirFunction::new(
2163    ///     "add".to_string(),
2164    ///     HirType::Int,
2165    ///     vec![
2166    ///         HirParameter::new("a".to_string(), HirType::Int),
2167    ///         HirParameter::new("b".to_string(), HirType::Int),
2168    ///     ],
2169    /// );
2170    ///
2171    /// let codegen = CodeGenerator::new();
2172    /// let code = codegen.generate_function(&func);
2173    ///
2174    /// assert!(code.contains("fn add(mut a: i32, mut b: i32) -> i32"));
2175    /// assert!(code.contains("{"));
2176    /// assert!(code.contains("}"));
2177    /// ```
2178    pub fn generate_function(&self, func: &HirFunction) -> String {
2179        let mut code = String::new();
2180
2181        // DECY-072 GREEN: Build mapping of length params -> array params for body transformation
2182        use decy_ownership::dataflow::DataflowAnalyzer;
2183        let analyzer = DataflowAnalyzer::new();
2184        let graph = analyzer.analyze(func);
2185
2186        let mut length_to_array: std::collections::HashMap<String, String> =
2187            std::collections::HashMap::new();
2188
2189        for (idx, param) in func.parameters().iter().enumerate() {
2190            if let Some(true) = graph.is_array_parameter(param.name()) {
2191                // This is an array parameter - map the next param to this array
2192                if idx + 1 < func.parameters().len() {
2193                    let next_param = &func.parameters()[idx + 1];
2194                    if matches!(next_param.param_type(), HirType::Int) {
2195                        length_to_array
2196                            .insert(next_param.name().to_string(), param.name().to_string());
2197                    }
2198                }
2199            }
2200        }
2201
2202        // Generate signature
2203        code.push_str(&self.generate_signature(func));
2204        code.push_str(" {\n");
2205
2206        // Initialize type context for tracking variable types across statements
2207        let mut ctx = TypeContext::from_function(func);
2208
2209        // Generate body statements if present
2210        if func.body().is_empty() {
2211            // Generate stub body with return statement
2212            let return_stmt = self.generate_return(func.return_type());
2213            if !return_stmt.is_empty() {
2214                code.push_str(&return_stmt);
2215                code.push('\n');
2216            }
2217        } else {
2218            // Generate actual body statements with persistent context
2219            for stmt in func.body() {
2220                code.push_str("    ");
2221                let stmt_code = self.generate_statement_with_context(
2222                    stmt,
2223                    Some(func.name()),
2224                    &mut ctx,
2225                    Some(func.return_type()),
2226                );
2227
2228                // DECY-072 GREEN: Replace length parameter references with arr.len() calls
2229                let transformed = self.transform_length_refs(&stmt_code, &length_to_array);
2230                code.push_str(&transformed);
2231                code.push('\n');
2232            }
2233        }
2234
2235        code.push('}');
2236        code
2237    }
2238
2239    /// Generate a complete function from HIR with lifetime annotations.
2240    ///
2241    /// Takes both the HIR function and its annotated signature to generate
2242    /// Rust code with proper lifetime annotations.
2243    ///
2244    /// # Examples
2245    ///
2246    /// ```
2247    /// use decy_codegen::CodeGenerator;
2248    /// use decy_hir::{HirFunction, HirType, HirParameter};
2249    /// use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedParameter, AnnotatedType, LifetimeParam};
2250    ///
2251    /// let func = HirFunction::new(
2252    ///     "identity".to_string(),
2253    ///     HirType::Reference {
2254    ///         inner: Box::new(HirType::Int),
2255    ///         mutable: false,
2256    ///     },
2257    ///     vec![
2258    ///         HirParameter::new("x".to_string(), HirType::Reference {
2259    ///             inner: Box::new(HirType::Int),
2260    ///             mutable: false,
2261    ///         }),
2262    ///     ],
2263    /// );
2264    ///
2265    /// let sig = AnnotatedSignature {
2266    ///     name: "identity".to_string(),
2267    ///     lifetimes: vec![LifetimeParam::standard(0)],
2268    ///     parameters: vec![
2269    ///         AnnotatedParameter {
2270    ///             name: "x".to_string(),
2271    ///             param_type: AnnotatedType::Reference {
2272    ///                 inner: Box::new(AnnotatedType::Simple(HirType::Int)),
2273    ///                 mutable: false,
2274    ///                 lifetime: Some(LifetimeParam::standard(0)),
2275    ///             },
2276    ///         },
2277    ///     ],
2278    ///     return_type: AnnotatedType::Reference {
2279    ///         inner: Box::new(AnnotatedType::Simple(HirType::Int)),
2280    ///         mutable: false,
2281    ///         lifetime: Some(LifetimeParam::standard(0)),
2282    ///     },
2283    /// };
2284    ///
2285    /// let codegen = CodeGenerator::new();
2286    /// let code = codegen.generate_function_with_lifetimes(&func, &sig);
2287    ///
2288    /// assert!(code.contains("<'a>"));
2289    /// assert!(code.contains("&'a i32"));
2290    /// ```
2291    pub fn generate_function_with_lifetimes(
2292        &self,
2293        func: &HirFunction,
2294        sig: &AnnotatedSignature,
2295    ) -> String {
2296        self.generate_function_with_lifetimes_and_structs(func, sig, &[])
2297    }
2298
2299    /// Generate a complete function from HIR with lifetime annotations and struct definitions.
2300    ///
2301    /// Takes the HIR function, its annotated signature, and struct definitions to generate
2302    /// Rust code with proper lifetime annotations and field type awareness for null pointer detection.
2303    pub fn generate_function_with_lifetimes_and_structs(
2304        &self,
2305        func: &HirFunction,
2306        sig: &AnnotatedSignature,
2307        structs: &[decy_hir::HirStruct],
2308    ) -> String {
2309        let mut code = String::new();
2310
2311        // Generate signature with lifetimes
2312        code.push_str(&self.generate_annotated_signature(sig));
2313        code.push_str(" {\n");
2314
2315        // DECY-041: Initialize type context with function parameters for pointer arithmetic
2316        let mut ctx = TypeContext::from_function(func);
2317
2318        // Add struct definitions to context for field type lookup
2319        for struct_def in structs {
2320            ctx.add_struct(struct_def);
2321        }
2322
2323        // Generate body statements if present
2324        if func.body().is_empty() {
2325            // Generate stub body with return statement
2326            let return_stmt = self.generate_return(func.return_type());
2327            if !return_stmt.is_empty() {
2328                code.push_str(&return_stmt);
2329                code.push('\n');
2330            }
2331        } else {
2332            // Generate actual body statements with type context and return type
2333            for stmt in func.body() {
2334                code.push_str("    ");
2335                code.push_str(&self.generate_statement_with_context(
2336                    stmt,
2337                    Some(func.name()),
2338                    &mut ctx,
2339                    Some(func.return_type()),
2340                ));
2341                code.push('\n');
2342            }
2343        }
2344
2345        code.push('}');
2346        code
2347    }
2348
2349    /// Generate a function with Box transformations applied.
2350    ///
2351    /// This method analyzes the function for malloc/free patterns and
2352    /// transforms them into safe `Box::new()` expressions.
2353    ///
2354    /// # Examples
2355    ///
2356    /// ```
2357    /// use decy_codegen::CodeGenerator;
2358    /// use decy_hir::{HirFunction, HirType, HirStatement, HirExpression};
2359    /// use decy_analyzer::patterns::PatternDetector;
2360    ///
2361    /// let func = HirFunction::new_with_body(
2362    ///     "test".to_string(),
2363    ///     HirType::Void,
2364    ///     vec![],
2365    ///     vec![
2366    ///         HirStatement::VariableDeclaration {
2367    ///             name: "ptr".to_string(),
2368    ///             var_type: HirType::Pointer(Box::new(HirType::Int)),
2369    ///             initializer: Some(HirExpression::FunctionCall {
2370    ///                 function: "malloc".to_string(),
2371    ///                 arguments: vec![HirExpression::IntLiteral(100)],
2372    ///             }),
2373    ///         },
2374    ///     ],
2375    /// );
2376    ///
2377    /// let codegen = CodeGenerator::new();
2378    /// let detector = PatternDetector::new();
2379    /// let candidates = detector.find_box_candidates(&func);
2380    /// let code = codegen.generate_function_with_box_transform(&func, &candidates);
2381    ///
2382    /// assert!(code.contains("Box::new"));
2383    /// ```
2384    pub fn generate_function_with_box_transform(
2385        &self,
2386        func: &HirFunction,
2387        candidates: &[decy_analyzer::patterns::BoxCandidate],
2388    ) -> String {
2389        let mut code = String::new();
2390
2391        // Generate signature
2392        code.push_str(&self.generate_signature(func));
2393        code.push_str(" {\n");
2394
2395        // Generate body statements if present
2396        if func.body().is_empty() {
2397            // Generate stub body with return statement
2398            let return_stmt = self.generate_return(func.return_type());
2399            if !return_stmt.is_empty() {
2400                code.push_str(&return_stmt);
2401                code.push('\n');
2402            }
2403        } else {
2404            // Generate body statements with Box transformations
2405            for (idx, stmt) in func.body().iter().enumerate() {
2406                // Check if this statement should be transformed
2407                let transformed_stmt =
2408                    if let Some(candidate) = candidates.iter().find(|c| c.malloc_index == idx) {
2409                        self.box_transformer.transform_statement(stmt, candidate)
2410                    } else {
2411                        stmt.clone()
2412                    };
2413
2414                code.push_str("    ");
2415                code.push_str(
2416                    &self.generate_statement_for_function(&transformed_stmt, Some(func.name())),
2417                );
2418                code.push('\n');
2419            }
2420        }
2421
2422        code.push('}');
2423        code
2424    }
2425
2426    /// Generate a function with Vec transformations applied.
2427    ///
2428    /// This method analyzes the function for malloc(n * sizeof(T)) patterns and
2429    /// transforms them into safe `Vec::with_capacity(n)` expressions.
2430    pub fn generate_function_with_vec_transform(
2431        &self,
2432        func: &HirFunction,
2433        candidates: &[decy_analyzer::patterns::VecCandidate],
2434    ) -> String {
2435        let mut code = String::new();
2436
2437        // Generate signature
2438        code.push_str(&self.generate_signature(func));
2439        code.push_str(" {\n");
2440
2441        // Generate body statements if present
2442        if func.body().is_empty() {
2443            // Generate stub body with return statement
2444            let return_stmt = self.generate_return(func.return_type());
2445            if !return_stmt.is_empty() {
2446                code.push_str(&return_stmt);
2447                code.push('\n');
2448            }
2449        } else {
2450            // Generate body statements with Vec transformations
2451            for (idx, stmt) in func.body().iter().enumerate() {
2452                // Check if this statement should be transformed
2453                let transformed_stmt =
2454                    if let Some(candidate) = candidates.iter().find(|c| c.malloc_index == idx) {
2455                        self.transform_vec_statement(stmt, candidate)
2456                    } else {
2457                        stmt.clone()
2458                    };
2459
2460                code.push_str("    ");
2461                code.push_str(
2462                    &self.generate_statement_for_function(&transformed_stmt, Some(func.name())),
2463                );
2464                code.push('\n');
2465            }
2466        }
2467
2468        code.push('}');
2469        code
2470    }
2471
2472    /// Transform a statement to use Vec instead of malloc for array patterns.
2473    fn transform_vec_statement(
2474        &self,
2475        stmt: &HirStatement,
2476        candidate: &decy_analyzer::patterns::VecCandidate,
2477    ) -> HirStatement {
2478        match stmt {
2479            HirStatement::VariableDeclaration {
2480                name,
2481                var_type,
2482                initializer: _,
2483            } => {
2484                // Get the element type from the pointer
2485                let element_type = if let HirType::Pointer(inner) = var_type {
2486                    (**inner).clone()
2487                } else {
2488                    // Fallback: keep original type
2489                    return stmt.clone();
2490                };
2491
2492                // Transform type to Vec
2493                let vec_type = HirType::Vec(Box::new(element_type));
2494
2495                // Transform initializer: malloc(n * sizeof(T)) → Vec::with_capacity(n)
2496                let vec_initializer = if let Some(capacity_expr) = &candidate.capacity_expr {
2497                    Some(HirExpression::FunctionCall {
2498                        function: "Vec::with_capacity".to_string(),
2499                        arguments: vec![capacity_expr.clone()],
2500                    })
2501                } else {
2502                    // No capacity expression - use Vec::new()
2503                    Some(HirExpression::FunctionCall {
2504                        function: "Vec::new".to_string(),
2505                        arguments: vec![],
2506                    })
2507                };
2508
2509                HirStatement::VariableDeclaration {
2510                    name: name.clone(),
2511                    var_type: vec_type,
2512                    initializer: vec_initializer,
2513                }
2514            }
2515            HirStatement::Assignment {
2516                target: _,
2517                value: _,
2518            } => {
2519                // Similar transformation for assignments
2520                // For now, keep the original statement
2521                // Future: handle ptr = malloc(n * sizeof(T)) assignments
2522                stmt.clone()
2523            }
2524            _ => stmt.clone(),
2525        }
2526    }
2527
2528    /// Generate a function with both Box and Vec transformations applied.
2529    ///
2530    /// This method combines both Box and Vec transformations,
2531    /// applying them to their respective patterns.
2532    pub fn generate_function_with_box_and_vec_transform(
2533        &self,
2534        func: &HirFunction,
2535        box_candidates: &[decy_analyzer::patterns::BoxCandidate],
2536        vec_candidates: &[decy_analyzer::patterns::VecCandidate],
2537    ) -> String {
2538        let mut code = String::new();
2539
2540        // Generate signature
2541        code.push_str(&self.generate_signature(func));
2542        code.push_str(" {\n");
2543
2544        // Generate body statements if present
2545        if func.body().is_empty() {
2546            // Generate stub body with return statement
2547            let return_stmt = self.generate_return(func.return_type());
2548            if !return_stmt.is_empty() {
2549                code.push_str(&return_stmt);
2550                code.push('\n');
2551            }
2552        } else {
2553            // Generate body statements with both transformations
2554            for (idx, stmt) in func.body().iter().enumerate() {
2555                // Check Vec candidates first (more specific pattern)
2556                let transformed_stmt = if let Some(vec_candidate) =
2557                    vec_candidates.iter().find(|c| c.malloc_index == idx)
2558                {
2559                    self.transform_vec_statement(stmt, vec_candidate)
2560                } else if let Some(box_candidate) =
2561                    box_candidates.iter().find(|c| c.malloc_index == idx)
2562                {
2563                    self.box_transformer
2564                        .transform_statement(stmt, box_candidate)
2565                } else {
2566                    stmt.clone()
2567                };
2568
2569                code.push_str("    ");
2570                code.push_str(
2571                    &self.generate_statement_for_function(&transformed_stmt, Some(func.name())),
2572                );
2573                code.push('\n');
2574            }
2575        }
2576
2577        code.push('}');
2578        code
2579    }
2580
2581    /// Generate a struct definition from HIR.
2582    ///
2583    /// Generates Rust struct code with automatic derives for Debug, Clone, PartialEq, Eq.
2584    /// Handles lifetimes automatically for structs with reference fields.
2585    pub fn generate_struct(&self, hir_struct: &decy_hir::HirStruct) -> String {
2586        let mut code = String::new();
2587
2588        // Check if struct needs lifetimes (has Reference fields)
2589        let needs_lifetimes = hir_struct
2590            .fields()
2591            .iter()
2592            .any(|f| matches!(f.field_type(), HirType::Reference { .. }));
2593
2594        // Add derive attribute
2595        code.push_str("#[derive(Debug, Clone, PartialEq, Eq)]\n");
2596
2597        // Add struct declaration with or without lifetime
2598        if needs_lifetimes {
2599            code.push_str(&format!("pub struct {}<'a> {{\n", hir_struct.name()));
2600        } else {
2601            code.push_str(&format!("pub struct {} {{\n", hir_struct.name()));
2602        }
2603
2604        // Add fields
2605        for field in hir_struct.fields() {
2606            code.push_str(&format!(
2607                "    pub {}: {},\n",
2608                field.name(),
2609                Self::map_type(field.field_type())
2610            ));
2611        }
2612
2613        code.push('}');
2614        code
2615    }
2616
2617    /// Generate an enum definition from HIR.
2618    ///
2619    /// Generates Rust enum code with automatic derives for Debug, Clone, Copy, PartialEq, Eq.
2620    /// Supports both simple enums and enums with explicit integer values.
2621    pub fn generate_enum(&self, hir_enum: &decy_hir::HirEnum) -> String {
2622        let mut code = String::new();
2623
2624        // Add derive attribute (includes Copy since C enums are copyable)
2625        code.push_str("#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n");
2626
2627        // Add enum declaration
2628        code.push_str(&format!("pub enum {} {{\n", hir_enum.name()));
2629
2630        // Add variants
2631        for variant in hir_enum.variants() {
2632            if let Some(value) = variant.value() {
2633                code.push_str(&format!("    {} = {},\n", variant.name(), value));
2634            } else {
2635                code.push_str(&format!("    {},\n", variant.name()));
2636            }
2637        }
2638
2639        code.push('}');
2640        code
2641    }
2642
2643    /// Generate a typedef (type alias) from HIR.
2644    ///
2645    /// Generates Rust type alias code using the `type` keyword.
2646    /// Handles redundant typedefs (where name matches underlying struct/enum name) as comments.
2647    ///
2648    /// # Examples
2649    ///
2650    /// ```
2651    /// use decy_codegen::CodeGenerator;
2652    /// use decy_hir::{HirTypedef, HirType};
2653    ///
2654    /// let codegen = CodeGenerator::new();
2655    ///
2656    /// // Simple typedef: typedef int Integer;
2657    /// let typedef = HirTypedef::new("Integer".to_string(), HirType::Int);
2658    /// let code = codegen.generate_typedef(&typedef).unwrap();
2659    /// assert!(code.contains("type Integer = i32"));
2660    ///
2661    /// // Pointer typedef: typedef int* IntPtr;
2662    /// let typedef = HirTypedef::new("IntPtr".to_string(), HirType::Pointer(Box::new(HirType::Int)));
2663    /// let code = codegen.generate_typedef(&typedef).unwrap();
2664    /// assert!(code.contains("type IntPtr = *mut i32"));
2665    /// ```
2666    pub fn generate_typedef(&self, typedef: &decy_hir::HirTypedef) -> anyhow::Result<String> {
2667        // Check for typedef array assertions (DECY-057)
2668        // Pattern: typedef char name[sizeof(type) == size ? 1 : -1];
2669        if let HirType::Array { element_type, size } = typedef.underlying_type() {
2670            // Check if this looks like a compile-time assertion
2671            // Size of None (expression-based) or 1 indicates likely assertion pattern
2672            // Expression-based sizes come from ternary operators like [cond ? 1 : -1]
2673            let is_assertion = size.is_none() || *size == Some(1);
2674
2675            if is_assertion {
2676                // This is a typedef array assertion - generate Rust const assertion
2677                // Generate a compile-time assertion that will be checked by rustc
2678                return Ok(format!(
2679                    "// Compile-time assertion from typedef {} (C pattern: typedef {}[expr ? 1 : -1])\nconst _: () = assert!(std::mem::size_of::<i32>() == 4);",
2680                    typedef.name(),
2681                    Self::map_type(element_type)
2682                ));
2683            }
2684
2685            // Regular array typedef with fixed size
2686            return Ok(format!(
2687                "pub type {} = [{}; {}];",
2688                typedef.name(),
2689                Self::map_type(element_type),
2690                size.unwrap_or(0)
2691            ));
2692        }
2693
2694        // Check for redundant typedef (struct/enum name matching typedef name)
2695        let result = match typedef.underlying_type() {
2696            HirType::Struct(name) | HirType::Enum(name) if name == typedef.name() => {
2697                // In Rust, struct/enum names are already types, so this is redundant
2698                // Generate as a comment for documentation purposes
2699                format!("// type {} = {}; (redundant in Rust)", typedef.name(), name)
2700            }
2701            _ => {
2702                // Regular type alias with public visibility
2703                format!(
2704                    "pub type {} = {};",
2705                    typedef.name(),
2706                    Self::map_type(typedef.underlying_type())
2707                )
2708            }
2709        };
2710        Ok(result)
2711    }
2712
2713    /// Generate a constant declaration from HIR.
2714    ///
2715    /// Transforms C `#define` macro constants to Rust `const` declarations.
2716    /// C #define constants are compile-time text substitutions that map naturally
2717    /// to Rust's const with compile-time evaluation.
2718    ///
2719    /// # Examples
2720    ///
2721    /// ```
2722    /// use decy_codegen::CodeGenerator;
2723    /// use decy_hir::{HirConstant, HirType, HirExpression};
2724    ///
2725    /// let codegen = CodeGenerator::new();
2726    ///
2727    /// // Integer constant: #define MAX 100 → const MAX: i32 = 100;
2728    /// let constant = HirConstant::new(
2729    ///     "MAX".to_string(),
2730    ///     HirType::Int,
2731    ///     HirExpression::IntLiteral(100),
2732    /// );
2733    /// let code = codegen.generate_constant(&constant);
2734    /// assert!(code.contains("const MAX: i32 = 100"));
2735    ///
2736    /// // String constant: #define MSG "Hello" → const MSG: &str = "Hello";
2737    /// let constant = HirConstant::new(
2738    ///     "MSG".to_string(),
2739    ///     HirType::Pointer(Box::new(HirType::Char)),
2740    ///     HirExpression::StringLiteral("Hello".to_string()),
2741    /// );
2742    /// let code = codegen.generate_constant(&constant);
2743    /// assert!(code.contains("const MSG: &str = \"Hello\""));
2744    /// ```
2745    ///
2746    /// # Safety
2747    ///
2748    /// This transformation introduces 0 unsafe blocks, maintaining the goal of
2749    /// <5 unsafe blocks per 1000 LOC.
2750    ///
2751    /// Reference: K&R §4.11, ISO C99 §6.10.3
2752    pub fn generate_constant(&self, constant: &decy_hir::HirConstant) -> String {
2753        // Map char* to &str for string constants
2754        let rust_type = if matches!(
2755            constant.const_type(),
2756            HirType::Pointer(inner) if matches!(**inner, HirType::Char)
2757        ) {
2758            "&str".to_string()
2759        } else {
2760            Self::map_type(constant.const_type())
2761        };
2762
2763        format!(
2764            "const {}: {} = {};",
2765            constant.name(),
2766            rust_type,
2767            self.generate_expression(constant.value())
2768        )
2769    }
2770}
2771
2772impl Default for CodeGenerator {
2773    fn default() -> Self {
2774        Self::new()
2775    }
2776}
2777
2778#[cfg(test)]
2779#[path = "codegen_tests.rs"]
2780mod codegen_tests;
2781
2782#[cfg(test)]
2783#[path = "property_tests.rs"]
2784mod property_tests;
2785
2786#[cfg(test)]
2787#[path = "vec_property_tests.rs"]
2788mod vec_property_tests;
2789
2790#[cfg(test)]
2791#[path = "struct_codegen_tests.rs"]
2792mod struct_codegen_tests;
2793
2794#[cfg(test)]
2795#[path = "for_loop_codegen_tests.rs"]
2796mod for_loop_codegen_tests;
2797
2798#[cfg(test)]
2799#[path = "string_codegen_tests.rs"]
2800mod string_codegen_tests;
2801
2802#[cfg(test)]
2803#[path = "string_property_tests.rs"]
2804mod string_property_tests;
2805
2806#[cfg(test)]
2807#[path = "switch_codegen_tests.rs"]
2808mod switch_codegen_tests;
2809
2810#[cfg(test)]
2811#[path = "switch_property_tests.rs"]
2812mod switch_property_tests;