Skip to main content

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
32#[macro_use]
33#[allow(unused_macros)]
34mod generated_contracts;
35
36pub mod box_transform;
37pub mod concurrency_transform;
38pub mod enum_gen;
39pub mod pattern_gen;
40pub mod test_generator;
41mod transform_gen;
42mod type_gen;
43
44use decy_hir::{HirExpression, HirFunction, HirType};
45use std::collections::HashMap;
46
47/// Type context for tracking variable types and struct definitions during code generation.
48/// Used to detect pointer arithmetic, null pointer assignments, and other type-specific operations.
49#[derive(Debug, Clone)]
50struct TypeContext {
51    variables: HashMap<String, HirType>,
52    structs: HashMap<String, Vec<(String, HirType)>>, // struct_name -> [(field_name, field_type)]
53    // DECY-117: Track function signatures for call site reference mutability
54    functions: HashMap<String, Vec<HirType>>, // func_name -> [param_types]
55    // DECY-116: Track which argument indices to skip at call sites (removed length params)
56    // func_name -> [(array_arg_index, len_arg_index_to_skip)]
57    slice_func_args: HashMap<String, Vec<(usize, usize)>>,
58    // DECY-134: Track string iteration params that use index-based access
59    // Maps param_name -> index_var_name (e.g., "dest" -> "dest_idx")
60    string_iter_params: HashMap<String, String>,
61    // DECY-134b: Track which functions have string iteration params (for call site transformation)
62    // Maps func_name -> list of (param_index, is_mutable) for string iter params
63    string_iter_funcs: HashMap<String, Vec<(usize, bool)>>,
64    // DECY-220: Track global variables (static mut) that need unsafe access
65    globals: std::collections::HashSet<String>,
66    // DECY-245: Track locals renamed to avoid shadowing statics (original_name -> renamed_name)
67    renamed_locals: HashMap<String, String>,
68}
69
70impl TypeContext {
71    fn new() -> Self {
72        Self {
73            variables: HashMap::new(),
74            structs: HashMap::new(),
75            functions: HashMap::new(),
76            slice_func_args: HashMap::new(),
77            string_iter_params: HashMap::new(),
78            string_iter_funcs: HashMap::new(),
79            globals: std::collections::HashSet::new(),
80            renamed_locals: HashMap::new(),
81        }
82    }
83
84    /// DECY-245: Register a renamed local variable (for shadowing statics)
85    fn add_renamed_local(&mut self, original: String, renamed: String) {
86        self.renamed_locals.insert(original, renamed);
87    }
88
89    /// DECY-245: Get the renamed name for a local variable (if renamed)
90    fn get_renamed_local(&self, name: &str) -> Option<&String> {
91        self.renamed_locals.get(name)
92    }
93
94    /// DECY-220: Register a global variable (static mut) for unsafe tracking
95    fn add_global(&mut self, name: String) {
96        self.globals.insert(name);
97    }
98
99    /// DECY-220: Check if a variable is a global (static mut) requiring unsafe
100    fn is_global(&self, name: &str) -> bool {
101        self.globals.contains(name)
102    }
103
104    /// DECY-134b: Register a function's string iteration params for call site transformation
105    fn add_string_iter_func(&mut self, func_name: String, params: Vec<(usize, bool)>) {
106        self.string_iter_funcs.insert(func_name, params);
107    }
108
109    /// DECY-134b: Get string iteration param info for a function
110    fn get_string_iter_func(&self, func_name: &str) -> Option<&Vec<(usize, bool)>> {
111        self.string_iter_funcs.get(func_name)
112    }
113
114    /// DECY-134: Register a string iteration param with its index variable name
115    fn add_string_iter_param(&mut self, param_name: String, index_var: String) {
116        self.string_iter_params.insert(param_name, index_var);
117    }
118
119    /// DECY-134: Check if a variable is a string iteration param.
120    #[cfg(test)]
121    fn is_string_iter_param(&self, name: &str) -> bool {
122        self.string_iter_params.contains_key(name)
123    }
124
125    /// DECY-134: Get the index variable name for a string iteration param
126    fn get_string_iter_index(&self, name: &str) -> Option<&String> {
127        self.string_iter_params.get(name)
128    }
129
130    /// DECY-117: Register a function signature for call site reference mutability
131    fn add_function(&mut self, name: String, param_types: Vec<HirType>) {
132        self.functions.insert(name, param_types);
133    }
134
135    /// DECY-116: Register which args to skip at call sites for slice functions
136    fn add_slice_func_args(&mut self, name: String, arg_mappings: Vec<(usize, usize)>) {
137        self.slice_func_args.insert(name, arg_mappings);
138    }
139
140    /// DECY-116: Get the arg indices to skip for a function (length params removed)
141    fn get_slice_func_len_indices(&self, func_name: &str) -> Option<&Vec<(usize, usize)>> {
142        self.slice_func_args.get(func_name)
143    }
144
145    /// DECY-117: Get the expected parameter type for a function call
146    fn get_function_param_type(&self, func_name: &str, param_index: usize) -> Option<&HirType> {
147        self.functions.get(func_name).and_then(|params| params.get(param_index))
148    }
149
150    fn from_function(func: &HirFunction) -> Self {
151        let mut ctx = Self::new();
152        // Add parameters to context
153        for param in func.parameters() {
154            ctx.variables.insert(param.name().to_string(), param.param_type().clone());
155        }
156        ctx
157    }
158
159    fn add_variable(&mut self, name: String, var_type: HirType) {
160        self.variables.insert(name, var_type);
161    }
162
163    fn add_struct(&mut self, struct_def: &decy_hir::HirStruct) {
164        let fields: Vec<(String, HirType)> = struct_def
165            .fields()
166            .iter()
167            .map(|f| (f.name().to_string(), f.field_type().clone()))
168            .collect();
169        self.structs.insert(struct_def.name().to_string(), fields);
170    }
171
172    /// DECY-141: Check if a struct type implements Default (no large arrays)
173    /// Structs with arrays > 32 elements don't derive Default due to trait limitations
174    fn struct_has_default(&self, struct_name: &str) -> bool {
175        if let Some(fields) = self.structs.get(struct_name) {
176            // Check if any field has a large array (> 32 elements)
177            !fields.iter().any(|(_, field_type)| {
178                matches!(
179                    field_type,
180                    HirType::Array { size: Some(n), .. } if *n > 32
181                )
182            })
183        } else {
184            // Unknown struct - assume no Default for safety
185            false
186        }
187    }
188
189    fn get_type(&self, name: &str) -> Option<&HirType> {
190        self.variables.get(name)
191    }
192
193    fn get_field_type(&self, object_expr: &HirExpression, field_name: &str) -> Option<HirType> {
194        // Get the type of the object expression
195        let object_type = match object_expr {
196            HirExpression::Variable(var_name) => self.get_type(var_name)?,
197            _ => return None,
198        };
199
200        // Extract the struct name from the type
201        let struct_name = match object_type {
202            HirType::Struct(name) => name,
203            HirType::Pointer(inner) => {
204                // If it's a pointer to a struct, dereference it
205                if let HirType::Struct(name) = &**inner {
206                    name
207                } else {
208                    return None;
209                }
210            }
211            // DECY-115: Handle Box<Struct> for heap-allocated structs
212            HirType::Box(inner) => {
213                if let HirType::Struct(name) = &**inner {
214                    name
215                } else {
216                    return None;
217                }
218            }
219            // DECY-140: Handle Reference<Struct> for borrowed struct access
220            HirType::Reference { inner, .. } => {
221                if let HirType::Struct(name) = &**inner {
222                    name
223                } else {
224                    return None;
225                }
226            }
227            _ => return None,
228        };
229
230        // Look up the field type in the struct definition
231        let fields = self.structs.get(struct_name)?;
232        fields.iter().find(|(name, _)| name == field_name).map(|(_, field_type)| field_type.clone())
233    }
234
235    fn is_pointer(&self, name: &str) -> bool {
236        matches!(self.get_type(name), Some(HirType::Pointer(_)))
237    }
238
239    fn is_option(&self, name: &str) -> bool {
240        matches!(self.get_type(name), Some(HirType::Option(_)))
241    }
242
243    fn is_vec(&self, name: &str) -> bool {
244        matches!(self.get_type(name), Some(HirType::Vec(_)))
245    }
246
247    /// Infer the type of an expression based on the context.
248    /// Returns None if the type cannot be inferred.
249    fn infer_expression_type(&self, expr: &HirExpression) -> Option<HirType> {
250        match expr {
251            HirExpression::Variable(name) => self.get_type(name).cloned(),
252            // DECY-204: Handle literal types for mixed-type arithmetic
253            HirExpression::IntLiteral(_) => Some(HirType::Int),
254            HirExpression::FloatLiteral(_) => Some(HirType::Double), // C float literals default to double
255            HirExpression::CharLiteral(_) => Some(HirType::Char),
256            HirExpression::Dereference(inner) => {
257                // If inner is *mut T, then *inner is T
258                // DECY-123: Also handle Box<T> and &T/&mut T deref → T
259                // DECY-151: Also handle Vec<T> (slice representation) deref → T
260                match self.infer_expression_type(inner) {
261                    Some(HirType::Pointer(pointee_type)) => Some(*pointee_type),
262                    Some(HirType::Box(inner_type)) => Some(*inner_type),
263                    Some(HirType::Reference { inner: ref_inner, .. }) => Some(*ref_inner),
264                    // DECY-151: Vec<T> represents slices, deref gives element type
265                    Some(HirType::Vec(elem_type)) => Some(*elem_type),
266                    _ => None,
267                }
268            }
269            HirExpression::ArrayIndex { array, index: _ } => {
270                // If array is [T; N], *mut T, or &[T], then array[i] is T
271                if let Some(array_type) = self.infer_expression_type(array) {
272                    match array_type {
273                        HirType::Array { element_type, .. } => Some(*element_type),
274                        HirType::Pointer(element_type) => Some(*element_type),
275                        // DECY-151: Handle slice types (&[T] or &mut [T])
276                        // BorrowGenerator uses Reference { inner: Vec(T) } for slices
277                        HirType::Reference { inner, .. } => match *inner {
278                            HirType::Vec(elem_type) => Some(*elem_type),
279                            HirType::Array { element_type, .. } => Some(*element_type),
280                            _ => None,
281                        },
282                        HirType::Vec(elem_type) => Some(*elem_type),
283                        _ => None,
284                    }
285                } else {
286                    None
287                }
288            }
289            // DECY-123: Handle field access to enable type inference through struct fields
290            HirExpression::FieldAccess { object, field } => {
291                // Get the struct type from the object expression
292                if let Some(obj_type) = self.infer_expression_type(object) {
293                    self.get_field_type_from_type(&obj_type, field)
294                } else {
295                    None
296                }
297            }
298            // DECY-123: Handle pointer field access (ptr->field)
299            HirExpression::PointerFieldAccess { pointer, field } => {
300                // Get the pointee type (struct) from the pointer expression
301                if let Some(ptr_type) = self.infer_expression_type(pointer) {
302                    match ptr_type {
303                        HirType::Pointer(inner) | HirType::Box(inner) => {
304                            self.get_field_type_from_type(&inner, field)
305                        }
306                        // DECY-123: Handle Reference types (&T, &mut T)
307                        HirType::Reference { inner, .. } => {
308                            self.get_field_type_from_type(&inner, field)
309                        }
310                        _ => None,
311                    }
312                } else {
313                    None
314                }
315            }
316            // DECY-210: Infer type for binary operations
317            HirExpression::BinaryOp { left, right, op } => {
318                use decy_hir::BinaryOperator;
319                let left_type = self.infer_expression_type(left);
320                let right_type = self.infer_expression_type(right);
321
322                // For arithmetic operations, follow C promotion rules
323                match op {
324                    BinaryOperator::Add
325                    | BinaryOperator::Subtract
326                    | BinaryOperator::Multiply
327                    | BinaryOperator::Divide
328                    | BinaryOperator::Modulo => {
329                        // If either operand is double, result is double
330                        if matches!(left_type, Some(HirType::Double))
331                            || matches!(right_type, Some(HirType::Double))
332                        {
333                            return Some(HirType::Double);
334                        }
335                        // If either operand is float, result is float
336                        if matches!(left_type, Some(HirType::Float))
337                            || matches!(right_type, Some(HirType::Float))
338                        {
339                            return Some(HirType::Float);
340                        }
341                        // Otherwise, result is int (char promotes to int in C)
342                        Some(HirType::Int)
343                    }
344                    // Comparison operations return bool (which we map to int for C compatibility)
345                    BinaryOperator::Equal
346                    | BinaryOperator::NotEqual
347                    | BinaryOperator::LessThan
348                    | BinaryOperator::GreaterThan
349                    | BinaryOperator::LessEqual
350                    | BinaryOperator::GreaterEqual
351                    | BinaryOperator::LogicalAnd
352                    | BinaryOperator::LogicalOr => Some(HirType::Int),
353                    // Bitwise operations return int
354                    BinaryOperator::BitwiseAnd
355                    | BinaryOperator::BitwiseOr
356                    | BinaryOperator::BitwiseXor
357                    | BinaryOperator::LeftShift
358                    | BinaryOperator::RightShift => Some(HirType::Int),
359                    _ => None,
360                }
361            }
362            _ => None,
363        }
364    }
365
366    /// DECY-123: Helper to get field type from a struct type
367    fn get_field_type_from_type(&self, obj_type: &HirType, field_name: &str) -> Option<HirType> {
368        let struct_name = match obj_type {
369            HirType::Struct(name) => name,
370            _ => return None,
371        };
372        let fields = self.structs.get(struct_name)?;
373        fields.iter().find(|(name, _)| name == field_name).map(|(_, field_type)| field_type.clone())
374    }
375}
376
377/// DECY-227: Escape Rust reserved keywords using raw identifiers (r#keyword).
378/// C code may use identifiers like `type`, `fn`, `match` that are reserved in Rust.
379fn escape_rust_keyword(name: &str) -> String {
380    // Rust strict keywords that cannot be used as identifiers without raw syntax
381    const RUST_KEYWORDS: &[&str] = &[
382        "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum",
383        "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move",
384        "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait",
385        "true", "type", "unsafe", "use", "where", "while",
386        // Reserved keywords for future use
387        "abstract", "become", "box", "do", "final", "macro", "override", "priv", "try", "typeof",
388        "unsized", "virtual", "yield",
389    ];
390
391    if RUST_KEYWORDS.contains(&name) {
392        format!("r#{}", name)
393    } else {
394        name.to_string()
395    }
396}
397
398/// Code generator for converting HIR to Rust source code.
399#[derive(Debug, Clone)]
400pub struct CodeGenerator {
401    box_transformer: box_transform::BoxTransformer,
402}
403
404impl CodeGenerator {
405    /// Create a new code generator.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use decy_codegen::CodeGenerator;
411    ///
412    /// let codegen = CodeGenerator::new();
413    /// ```
414    pub fn new() -> Self {
415        Self { box_transformer: box_transform::BoxTransformer::new() }
416    }
417
418    /// DECY-143: Generate unsafe block with SAFETY comment.
419    /// All unsafe blocks should have a comment explaining why the operation is safe.
420    fn unsafe_block(code: &str, safety_reason: &str) -> String {
421        format!("/* SAFETY: {} */ unsafe {{ {} }}", safety_reason, code)
422    }
423
424    /// DECY-143: Generate unsafe statement with SAFETY comment.
425    /// For statement-level unsafe blocks (ending with semicolon).
426    fn unsafe_stmt(code: &str, safety_reason: &str) -> String {
427        format!("// SAFETY: {}\n    unsafe {{ {}; }}", safety_reason, code)
428    }
429
430    /// Generate Rust code for a macro definition.
431    ///
432    /// Transforms C #define macros to Rust const declarations (for object-like macros)
433    /// or inline functions (for function-like macros).
434    ///
435    /// # Supported Macro Types (DECY-098c)
436    ///
437    /// **Object-like macros** (constants) are fully supported:
438    /// - `#define MAX 100` → `const MAX: i32 = 100;`
439    /// - `#define PI 3.14159` → `const PI: f64 = 3.14159;`
440    /// - `#define GREETING "Hello"` → `const GREETING: &str = "Hello";`
441    ///
442    /// **Function-like macros** are not yet supported (DECY-098d):
443    /// - `#define SQR(x) ((x) * (x))` → Error
444    ///
445    /// # Type Inference
446    ///
447    /// Types are automatically inferred from the macro body:
448    /// - String literals → `&str`
449    /// - Character literals → `char`
450    /// - Floating point → `f64`
451    /// - Integers (including hex/octal) → `i32`
452    ///
453    /// # Edge Cases
454    ///
455    /// - Empty macros generate comments: `#define EMPTY` → `// Empty macro: EMPTY`
456    /// - Macro names are preserved exactly (SCREAMING_SNAKE_CASE maintained)
457    ///
458    /// # Errors
459    ///
460    /// Returns an error if:
461    /// - The macro is function-like (not yet implemented)
462    ///
463    /// # Examples
464    ///
465    /// ```
466    /// use decy_codegen::CodeGenerator;
467    /// use decy_hir::HirMacroDefinition;
468    ///
469    /// let generator = CodeGenerator::new();
470    /// let macro_def = HirMacroDefinition::new_object_like("MAX".to_string(), "100".to_string());
471    /// let rust_code = generator.generate_macro(&macro_def).unwrap();
472    /// assert!(rust_code.contains("const MAX"));
473    /// # Ok::<(), anyhow::Error>(())
474    /// ```
475    ///
476    /// # Reference
477    ///
478    /// - K&R §4.11: Macro Substitution
479    /// - ISO C99 §6.10.3: Macro replacement
480    pub fn generate_macro(
481        &self,
482        macro_def: &decy_hir::HirMacroDefinition,
483    ) -> anyhow::Result<String> {
484        if macro_def.is_function_like() {
485            // Generate inline function for function-like macros
486            return self.generate_function_like_macro(macro_def);
487        }
488
489        // Object-like macro (constant)
490        let name = macro_def.name();
491        let body = macro_def.body();
492
493        // Handle empty macros
494        if body.is_empty() {
495            return Ok(format!("// Empty macro: {}", name));
496        }
497
498        // Infer type from macro body
499        let (rust_type, rust_value) = self.infer_macro_type(body)?;
500
501        Ok(format!("const {}: {} = {};", name, rust_type, rust_value))
502    }
503
504    /// Generate Rust inline function from function-like macro.
505    ///
506    /// Transforms C function-like macros to Rust inline functions:
507    /// - `#define SQR(x) ((x) * (x))` → `fn sqr(x: i32) -> i32 { x * x }`
508    /// - `#define MAX(a, b) ((a) > (b) ? (a) : (b))` → `fn max(a: i32, b: i32) -> i32 { if a > b { a } else { b } }`
509    ///
510    /// # Features
511    ///
512    /// - Converts macro name from SCREAMING_SNAKE_CASE to snake_case
513    /// - Infers parameter types (defaults to i32)
514    /// - Infers return type from expression
515    /// - Adds `#[inline]` attribute for performance
516    /// - Transforms ternary operator (? :) to if-else
517    /// - Removes unnecessary parentheses
518    fn generate_function_like_macro(
519        &self,
520        macro_def: &decy_hir::HirMacroDefinition,
521    ) -> anyhow::Result<String> {
522        let name = macro_def.name();
523        let params = macro_def.parameters();
524        let body = macro_def.body();
525
526        // Convert SCREAMING_SNAKE_CASE to snake_case
527        let fn_name = self.convert_to_snake_case(name);
528
529        // Generate parameter list (default to i32 for now)
530        let param_list =
531            params.iter().map(|p| format!("{}: i32", p)).collect::<Vec<_>>().join(", ");
532
533        // Transform macro body to Rust expression
534        let rust_body = self.transform_macro_body(body, params)?;
535
536        // Infer return type from body
537        let return_type = self.infer_return_type(body);
538
539        // Generate function
540        let result = format!(
541            "#[inline]\nfn {}({}) -> {} {{\n    {}\n}}",
542            fn_name, param_list, return_type, rust_body
543        );
544
545        Ok(result)
546    }
547
548    /// Convert SCREAMING_SNAKE_CASE to snake_case.
549    fn convert_to_snake_case(&self, name: &str) -> String {
550        name.to_lowercase()
551    }
552
553    /// Transform C macro body to Rust expression.
554    ///
555    /// Transformations:
556    /// - Remove outer parentheses: ((x) * (x)) → x * x
557    /// - Ternary operator: (a) > (b) ? (a) : (b) → if a > b { a } else { b }
558    /// - Remove parameter parentheses: (x) → x
559    fn transform_macro_body(&self, body: &str, params: &[String]) -> anyhow::Result<String> {
560        let mut result = body.to_string();
561
562        // Check for ternary operator
563        if result.contains('?') && result.contains(':') {
564            result = self.transform_ternary(&result)?;
565        } else {
566            // Remove unnecessary parentheses around parameters
567            for param in params {
568                result = result.replace(&format!("({})", param), param);
569            }
570
571            // Remove outer parentheses if present
572            result = self.remove_outer_parens(&result);
573
574            // Add spaces around operators for readability
575            result = self.add_operator_spaces(&result);
576        }
577
578        Ok(result)
579    }
580
581    /// Transform C ternary operator to Rust if-else.
582    ///
583    /// Example: ((a)>(b)?(a):(b)) → if a > b { a } else { b }
584    fn transform_ternary(&self, expr: &str) -> anyhow::Result<String> {
585        // Find the ? and : positions
586        let question_pos = expr.find('?').unwrap_or(0);
587        let colon_pos = expr.rfind(':').unwrap_or(0);
588
589        if question_pos == 0 || colon_pos == 0 || colon_pos <= question_pos {
590            // Malformed ternary, return as-is
591            return Ok(expr.to_string());
592        }
593
594        // Extract parts
595        let condition = expr[..question_pos].trim();
596        let true_expr = expr[question_pos + 1..colon_pos].trim();
597        let false_expr = expr[colon_pos + 1..].trim();
598
599        // Clean up each part
600        let condition = self.remove_outer_parens(condition);
601        let condition = self.clean_expression(&condition);
602        let true_expr = self.remove_outer_parens(true_expr);
603        let true_expr = self.clean_expression(&true_expr);
604        let false_expr = self.remove_outer_parens(false_expr);
605        let false_expr = self.clean_expression(&false_expr);
606
607        Ok(format!("if {} {{ {} }} else {{ {} }}", condition, true_expr, false_expr))
608    }
609
610    /// Remove outer parentheses from expression.
611    fn remove_outer_parens(&self, expr: &str) -> String {
612        Self::remove_outer_parens_impl(expr)
613    }
614
615    /// Implementation of remove_outer_parens (recursive helper).
616    fn remove_outer_parens_impl(expr: &str) -> String {
617        let trimmed = expr.trim();
618        if trimmed.starts_with('(') && trimmed.ends_with(')') {
619            // Check if these are matching outer parens
620            let mut depth = 0;
621            let chars: Vec<char> = trimmed.chars().collect();
622            for (i, ch) in chars.iter().enumerate() {
623                match ch {
624                    '(' => depth += 1,
625                    ')' => {
626                        depth -= 1;
627                        if depth == 0 && i < chars.len() - 1 {
628                            // Found closing paren before end, not outer parens
629                            return trimmed.to_string();
630                        }
631                    }
632                    _ => {}
633                }
634            }
635            // These are outer parens, remove them
636            return Self::remove_outer_parens_impl(&trimmed[1..trimmed.len() - 1]);
637        }
638        trimmed.to_string()
639    }
640
641    /// Clean expression by removing parameter parentheses.
642    fn clean_expression(&self, expr: &str) -> String {
643        let mut result = expr.to_string();
644
645        // Handle negation: -(x) → -x (preserve the minus)
646        result = result.replace("-(x)", "-x");
647        result = result.replace("-(a)", "-a");
648        result = result.replace("-(b)", "-b");
649        result = result.replace("-(c)", "-c");
650        result = result.replace("-(n)", "-n");
651
652        // Remove parentheses around single identifiers (not negated)
653        // This is a simplified version - could be enhanced
654        result = result.replace("(x)", "x");
655        result = result.replace("(a)", "a");
656        result = result.replace("(b)", "b");
657        result = result.replace("(c)", "c");
658        result = result.replace("(n)", "n");
659
660        // Add spaces around operators
661        result = self.add_operator_spaces(&result);
662
663        result
664    }
665
666    /// Add spaces around operators for readability.
667    fn add_operator_spaces(&self, expr: &str) -> String {
668        let mut result = expr.to_string();
669
670        // Add spaces around comparison operators
671        result = result.replace(">", " > ");
672        result = result.replace("<", " < ");
673        result = result.replace("==", " == ");
674        result = result.replace("!=", " != ");
675        result = result.replace(">=", " >= ");
676        result = result.replace("<=", " <= ");
677
678        // Add spaces around logical operators (do this before arithmetic to avoid issues)
679        result = result.replace("&&", " && ");
680        result = result.replace("||", " || ");
681
682        // Add spaces around arithmetic operators
683        result = result.replace("+", " + ");
684        // Note: Don't blindly replace "-" as it could be unary minus
685        // Only replace if it's not at the start or after a space
686        let chars: Vec<char> = result.chars().collect();
687        let mut new_result = String::new();
688        for (i, ch) in chars.iter().enumerate() {
689            if *ch == '-' {
690                // Check if this is a binary minus (has non-space before it)
691                if i > 0 && !chars[i - 1].is_whitespace() && chars[i - 1] != '(' {
692                    new_result.push(' ');
693                    new_result.push(*ch);
694                    new_result.push(' ');
695                } else {
696                    // Unary minus, keep as-is
697                    new_result.push(*ch);
698                }
699            } else {
700                new_result.push(*ch);
701            }
702        }
703        result = new_result;
704
705        result = result.replace("*", " * ");
706        result = result.replace("/", " / ");
707        result = result.replace("%", " % ");
708
709        // Clean up multiple spaces
710        while result.contains("  ") {
711            result = result.replace("  ", " ");
712        }
713
714        result.trim().to_string()
715    }
716
717    /// Infer return type from macro body.
718    ///
719    /// Simple heuristic:
720    /// - Contains ternary operator (? :) → return type of branches (check for comparison at top level)
721    /// - Contains comparison operators at top level (not in ternary) → bool
722    /// - Contains logical operators (&&, ||) → bool
723    /// - Default → i32
724    fn infer_return_type(&self, body: &str) -> String {
725        // Check for ternary - return type depends on the branches, not the condition
726        if body.contains('?') && body.contains(':') {
727            // For ternary, the return type is determined by what's returned, not the condition
728            // In most C macros like MAX(a,b), the return type is i32 even though condition is bool
729            return "i32".to_string();
730        }
731
732        // Check for logical operators (&&, ||) at top level
733        if body.contains("&&") || body.contains("||") {
734            return "bool".to_string();
735        }
736
737        // Check if it's a standalone comparison (no ternary)
738        if (body.contains('>') || body.contains('<') || body.contains("==") || body.contains("!="))
739            && !body.contains('?')
740        {
741            // Standalone comparison returns bool
742            "bool".to_string()
743        } else {
744            // Default to i32
745            "i32".to_string()
746        }
747    }
748
749    /// Infer the Rust type and value from a C macro body.
750    ///
751    /// This function analyzes the macro body string and determines the appropriate
752    /// Rust type and formatted value.
753    ///
754    /// # Type Inference Rules
755    ///
756    /// - String literals (`"text"`) → `&str`
757    /// - Character literals (`'c'`) → `char`
758    /// - Floating point (contains `.` or `e`/`E`) → `f64`
759    /// - Hexadecimal (`0xFF`) → `i32` (preserves hex format)
760    /// - Octal (`0755`) → `i32` (preserves octal format)
761    /// - Integers (parseable as i32) → `i32`
762    /// - Default (expressions) → `i32`
763    ///
764    /// # Returns
765    ///
766    /// Returns a tuple of (rust_type, rust_value) where:
767    /// - `rust_type`: The Rust type as a string (e.g., "i32", "&str")
768    /// - `rust_value`: The formatted value (e.g., "100", "\"Hello\"")
769    ///
770    /// # Examples
771    ///
772    /// ```
773    /// # use decy_codegen::CodeGenerator;
774    /// let generator = CodeGenerator::new();
775    /// // This is a private method, but tested through generate_macro
776    /// # Ok::<(), anyhow::Error>(())
777    /// ```
778    fn infer_macro_type(&self, body: &str) -> anyhow::Result<(String, String)> {
779        let body = body.trim();
780
781        // String literal: "..." → &str
782        if body.starts_with('"') && body.ends_with('"') {
783            return Ok(("&str".to_string(), body.to_string()));
784        }
785
786        // Character literal: '...' → char
787        if body.starts_with('\'') && body.ends_with('\'') {
788            return Ok(("char".to_string(), body.to_string()));
789        }
790
791        // Floating point: contains '.' or 'e'/'E' → f64
792        if body.contains('.') || body.contains('e') || body.contains('E') {
793            return Ok(("f64".to_string(), body.to_string()));
794        }
795
796        // Hexadecimal: 0x... or 0X... → i32 (keep hex format)
797        if body.starts_with("0x") || body.starts_with("0X") {
798            return Ok(("i32".to_string(), body.to_string()));
799        }
800
801        // Octal: 0... → i32
802        if body.starts_with('0')
803            && body.len() > 1
804            && body.chars().nth(1).expect("len>1").is_ascii_digit()
805        {
806            return Ok(("i32".to_string(), body.to_string()));
807        }
808
809        // Try to parse as integer (handles negative numbers too)
810        if body.parse::<i32>().is_ok() {
811            return Ok(("i32".to_string(), body.to_string()));
812        }
813
814        // Default: treat as i32 expression
815        Ok(("i32".to_string(), body.to_string()))
816    }
817
818    /// Get the Box transformer.
819    pub fn box_transformer(&self) -> &box_transform::BoxTransformer {
820        &self.box_transformer
821    }
822
823    /// Map HIR type to Rust type string.
824    ///
825    /// # Examples
826    ///
827    /// ```
828    /// use decy_codegen::CodeGenerator;
829    /// use decy_hir::HirType;
830    ///
831    /// assert_eq!(CodeGenerator::map_type(&HirType::Int), "i32");
832    /// assert_eq!(CodeGenerator::map_type(&HirType::Float), "f32");
833    /// assert_eq!(CodeGenerator::map_type(&HirType::Box(Box::new(HirType::Int))), "Box<i32>");
834    /// ```
835    pub fn map_type(hir_type: &HirType) -> String {
836        match hir_type {
837            HirType::Void => "()".to_string(),
838            HirType::Bool => "bool".to_string(),
839            HirType::Int => "i32".to_string(),
840            HirType::UnsignedInt => "u32".to_string(), // DECY-158
841            HirType::Float => "f32".to_string(),
842            HirType::Double => "f64".to_string(),
843            HirType::Char => "u8".to_string(),
844            HirType::SignedChar => "i8".to_string(), // DECY-250
845            HirType::Pointer(inner) => {
846                format!("*mut {}", Self::map_type(inner))
847            }
848            HirType::Box(inner) => {
849                format!("Box<{}>", Self::map_type(inner))
850            }
851            HirType::Vec(inner) => {
852                format!("Vec<{}>", Self::map_type(inner))
853            }
854            HirType::Option(inner) => {
855                format!("Option<{}>", Self::map_type(inner))
856            }
857            HirType::Reference { inner, mutable } => {
858                // DECY-072: Special case for slices: &Vec<T> → &[T]
859                if let HirType::Vec(element_type) = &**inner {
860                    let element_str = Self::map_type(element_type);
861                    if *mutable {
862                        format!("&mut [{}]", element_str)
863                    } else {
864                        format!("&[{}]", element_str)
865                    }
866                } else if *mutable {
867                    format!("&mut {}", Self::map_type(inner))
868                } else {
869                    format!("&{}", Self::map_type(inner))
870                }
871            }
872            HirType::Struct(name) => name.clone(),
873            HirType::Enum(name) => name.clone(),
874            HirType::Array { element_type, size } => {
875                if let Some(n) = size {
876                    format!("[{}; {}]", Self::map_type(element_type), n)
877                } else {
878                    // Unsized array - use slice reference
879                    format!("[{}]", Self::map_type(element_type))
880                }
881            }
882            HirType::FunctionPointer { param_types, return_type } => {
883                // C: int (*func_ptr)(int, int); → Rust: fn(i32, i32) -> i32
884                let params: Vec<String> = param_types.iter().map(Self::map_type).collect();
885                let params_str = params.join(", ");
886
887                // Skip return type annotation for void
888                if matches!(**return_type, HirType::Void) {
889                    format!("fn({})", params_str)
890                } else {
891                    format!("fn({}) -> {}", params_str, Self::map_type(return_type))
892                }
893            }
894            HirType::StringLiteral => "&str".to_string(),
895            HirType::OwnedString => "String".to_string(),
896            HirType::StringReference => "&str".to_string(),
897            HirType::Union(_) => {
898                // Unions will be transformed to Rust enums
899                // For now, return a placeholder
900                "/* Union type */".to_string()
901            }
902            // DECY-172: Preserve typedef names like size_t, ssize_t, ptrdiff_t
903            HirType::TypeAlias(name) => name.clone(),
904        }
905    }
906
907    /// Map C type name from sizeof to Rust type string.
908    ///
909    /// Handles type names as strings from sizeof expressions.
910    /// Examples: "int" → "i32", "struct Data" → "Data"
911    fn map_sizeof_type(&self, c_type_name: &str) -> String {
912        let trimmed = c_type_name.trim();
913
914        // Handle basic C types
915        match trimmed {
916            "int" => "i32".to_string(),
917            "short" | "short int" => "i16".to_string(),
918            "long" | "long int" => "i64".to_string(),
919            "long long" | "long long int" => "i64".to_string(),
920            "unsigned int" | "unsigned" => "u32".to_string(),
921            "unsigned short" | "unsigned short int" => "u16".to_string(),
922            "unsigned long" | "unsigned long int" => "u64".to_string(),
923            "unsigned long long" | "unsigned long long int" => "u64".to_string(),
924            "unsigned char" => "u8".to_string(),
925            "signed char" => "i8".to_string(),
926            "float" => "f32".to_string(),
927            "double" => "f64".to_string(),
928            "char" => "u8".to_string(),
929            "void" => "()".to_string(),
930            // Pointer types
931            "char*" | "char *" => "*mut u8".to_string(),
932            "int*" | "int *" => "*mut i32".to_string(),
933            "void*" | "void *" => "*mut ()".to_string(),
934            _ => {
935                // Handle "struct TypeName" → "TypeName"
936                if let Some(struct_name) = trimmed.strip_prefix("struct ") {
937                    struct_name.trim().to_string()
938                } else {
939                    // Keep custom type names as-is
940                    trimmed.to_string()
941                }
942            }
943        }
944    }
945
946}
947
948mod expr_gen;
949mod func_gen;
950mod stmt_gen;
951
952impl Default for CodeGenerator {
953    fn default() -> Self {
954        Self::new()
955    }
956}
957
958#[cfg(test)]
959#[path = "codegen_tests.rs"]
960mod codegen_tests;
961
962#[cfg(test)]
963#[path = "property_tests.rs"]
964mod property_tests;
965
966#[cfg(test)]
967#[path = "vec_property_tests.rs"]
968mod vec_property_tests;
969
970#[cfg(test)]
971#[path = "struct_codegen_tests.rs"]
972mod struct_codegen_tests;
973
974#[cfg(test)]
975#[path = "class_codegen_tests.rs"]
976mod class_codegen_tests;
977
978#[cfg(test)]
979#[path = "for_loop_codegen_tests.rs"]
980mod for_loop_codegen_tests;
981
982#[cfg(test)]
983#[path = "string_codegen_tests.rs"]
984mod string_codegen_tests;
985
986#[cfg(test)]
987#[path = "string_property_tests.rs"]
988mod string_property_tests;
989
990#[cfg(test)]
991#[path = "switch_codegen_tests.rs"]
992mod switch_codegen_tests;
993
994#[cfg(test)]
995#[path = "switch_property_tests.rs"]
996mod switch_property_tests;
997
998#[cfg(test)]
999#[path = "global_variable_codegen_tests.rs"]
1000mod global_variable_codegen_tests;
1001
1002#[cfg(test)]
1003#[path = "coverage_tests.rs"]
1004mod coverage_tests;
1005
1006#[cfg(test)]
1007#[path = "pattern_gen_tests.rs"]
1008mod pattern_gen_tests;
1009
1010#[cfg(test)]
1011#[path = "format_specifier_tests.rs"]
1012mod format_specifier_tests;
1013
1014#[cfg(test)]
1015#[path = "expression_coverage_tests.rs"]
1016mod expression_coverage_tests;
1017
1018#[cfg(test)]
1019#[path = "codegen_coverage_tests.rs"]
1020mod codegen_coverage_tests;
1021
1022#[cfg(test)]
1023#[path = "statement_coverage_tests.rs"]
1024mod statement_coverage_tests;
1025
1026#[cfg(test)]
1027#[path = "expression_target_type_tests.rs"]
1028mod expression_target_type_tests;
1029
1030#[cfg(test)]
1031#[path = "expression_deep_branch_tests.rs"]
1032mod expression_deep_branch_tests;
1033
1034#[cfg(test)]
1035#[path = "box_transform_coverage_tests.rs"]
1036mod box_transform_coverage_tests;
1037
1038#[cfg(test)]
1039#[path = "format_and_sig_tests.rs"]
1040mod format_and_sig_tests;
1041
1042#[cfg(test)]
1043#[path = "expr_stmt_deep_tests.rs"]
1044mod expr_stmt_deep_tests;
1045
1046#[cfg(test)]
1047#[path = "expr_codegen_deep2_tests.rs"]
1048mod expr_codegen_deep2_tests;
1049
1050#[cfg(test)]
1051#[path = "expr_target_deep_tests.rs"]
1052mod expr_target_deep_tests;
1053
1054#[cfg(test)]
1055#[path = "codegen_remaining_tests.rs"]
1056mod codegen_remaining_tests;
1057
1058// DECY-202: Deep coverage tests disabled — pre-existing import issue
1059// (parts are submodules of index file, `use super::*` resolves to empty module)
1060// #[cfg(test)]
1061// #[path = "codegen_deep_coverage_tests.rs"]
1062// mod codegen_deep_coverage_tests;
1063
1064#[cfg(test)]
1065#[path = "type_context_coverage_tests.rs"]
1066mod type_context_coverage_tests;