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