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