Skip to main content

decy_hir/
lib.rs

1//! High-level Intermediate Representation for C-to-Rust transpilation.
2//!
3//! The HIR is a Rust-oriented representation that bridges C AST and Rust code generation.
4//!
5//! # Examples
6//!
7//! ```
8//! use decy_hir::{HirFunction, HirType, HirParameter};
9//!
10//! // Create a simple HIR function
11//! let func = HirFunction::new(
12//!     "main".to_string(),
13//!     HirType::Int,
14//!     vec![],
15//! );
16//!
17//! assert_eq!(func.name(), "main");
18//! assert_eq!(func.return_type(), &HirType::Int);
19//! ```
20
21#![warn(missing_docs)]
22#![warn(clippy::all)]
23#![deny(unsafe_code)]
24
25/// Represents a C type in HIR.
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum HirType {
28    /// void type
29    Void,
30    /// C99 _Bool type (maps to bool in Rust)
31    Bool,
32    /// int type (maps to i32 in Rust)
33    Int,
34    /// unsigned int type (maps to u32 in Rust) - DECY-158
35    UnsignedInt,
36    /// float type (maps to f32 in Rust)
37    Float,
38    /// double type (maps to f64 in Rust)
39    Double,
40    /// char type (maps to u8 in Rust)
41    Char,
42    /// signed char type (maps to i8 in Rust) - DECY-250
43    SignedChar,
44    /// Pointer to another type
45    Pointer(Box<HirType>),
46    /// Boxed type (Rust `Box<T>`)
47    Box(Box<HirType>),
48    /// Vec type (Rust `Vec<T>`)
49    Vec(Box<HirType>),
50    /// Option type (Rust `Option<T>`) - for NULL pointer handling
51    Option(Box<HirType>),
52    /// Reference type (Rust `&T` or `&mut T`)
53    Reference {
54        /// Inner type
55        inner: Box<HirType>,
56        /// Whether the reference is mutable
57        mutable: bool,
58    },
59    /// Struct type (by name)
60    Struct(String),
61    /// Enum type (by name)
62    Enum(String),
63    /// Union type with named fields
64    Union(Vec<(String, HirType)>),
65    /// Array type with optional size (fixed-size or unsized)
66    Array {
67        /// Element type
68        element_type: Box<HirType>,
69        /// Optional size (None for unsized arrays like function parameters)
70        size: Option<usize>,
71    },
72    /// Function pointer type (Rust `fn` type)
73    FunctionPointer {
74        /// Parameter types
75        param_types: Vec<HirType>,
76        /// Return type
77        return_type: Box<HirType>,
78    },
79    /// String literal type (maps to &str in Rust)
80    StringLiteral,
81    /// Owned string type (maps to String in Rust)
82    OwnedString,
83    /// String reference type (maps to &str in Rust)
84    StringReference,
85    /// Type alias (typedef) - preserves the alias name for codegen
86    /// DECY-172: Used for size_t, ssize_t, ptrdiff_t, etc.
87    TypeAlias(String),
88}
89
90impl HirType {
91    /// Convert from parser AST type to HIR type.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use decy_hir::HirType;
97    /// use decy_parser::parser::Type;
98    ///
99    /// let hir_type = HirType::from_ast_type(&Type::Int);
100    /// assert_eq!(hir_type, HirType::Int);
101    /// ```
102    pub fn from_ast_type(ast_type: &decy_parser::parser::Type) -> Self {
103        use decy_parser::parser::Type;
104        match ast_type {
105            Type::Void => HirType::Void,
106            Type::Bool => HirType::Bool,
107            Type::Int => HirType::Int,
108            Type::UnsignedInt => HirType::UnsignedInt, // DECY-158
109            Type::Float => HirType::Float,
110            Type::Double => HirType::Double,
111            Type::Char => HirType::Char,
112            Type::SignedChar => HirType::SignedChar, // DECY-250
113            Type::Pointer(inner) => HirType::Pointer(Box::new(HirType::from_ast_type(inner))),
114            Type::Struct(name) => HirType::Struct(name.clone()),
115            Type::FunctionPointer {
116                param_types,
117                return_type,
118            } => HirType::FunctionPointer {
119                param_types: param_types.iter().map(HirType::from_ast_type).collect(),
120                return_type: Box::new(HirType::from_ast_type(return_type)),
121            },
122            Type::Array { element_type, size } => HirType::Array {
123                element_type: Box::new(HirType::from_ast_type(element_type)),
124                size: size.map(|s| s as usize),
125            },
126            // DECY-172: Preserve type aliases like size_t, ssize_t, ptrdiff_t
127            Type::TypeAlias(name) => HirType::TypeAlias(name.clone()),
128        }
129    }
130}
131
132/// Represents a struct field in HIR.
133#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct HirStructField {
135    name: String,
136    field_type: HirType,
137}
138
139impl HirStructField {
140    /// Create a new struct field.
141    pub fn new(name: String, field_type: HirType) -> Self {
142        Self { name, field_type }
143    }
144
145    /// Get the field name.
146    pub fn name(&self) -> &str {
147        &self.name
148    }
149
150    /// Get the field type.
151    pub fn field_type(&self) -> &HirType {
152        &self.field_type
153    }
154}
155
156/// Represents a struct definition in HIR.
157#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct HirStruct {
159    name: String,
160    fields: Vec<HirStructField>,
161}
162
163impl HirStruct {
164    /// Create a new struct.
165    pub fn new(name: String, fields: Vec<HirStructField>) -> Self {
166        Self { name, fields }
167    }
168
169    /// Get the struct name.
170    pub fn name(&self) -> &str {
171        &self.name
172    }
173
174    /// Get the struct fields.
175    pub fn fields(&self) -> &[HirStructField] {
176        &self.fields
177    }
178}
179
180/// Represents an enum variant in HIR.
181#[derive(Debug, Clone, PartialEq, Eq)]
182pub struct HirEnumVariant {
183    name: String,
184    value: Option<i32>,
185}
186
187impl HirEnumVariant {
188    /// Create a new enum variant.
189    pub fn new(name: String, value: Option<i32>) -> Self {
190        Self { name, value }
191    }
192
193    /// Get the variant name.
194    pub fn name(&self) -> &str {
195        &self.name
196    }
197
198    /// Get the variant value.
199    pub fn value(&self) -> Option<i32> {
200        self.value
201    }
202}
203
204/// Represents an enum definition in HIR.
205#[derive(Debug, Clone, PartialEq, Eq)]
206pub struct HirEnum {
207    name: String,
208    variants: Vec<HirEnumVariant>,
209}
210
211impl HirEnum {
212    /// Create a new enum.
213    pub fn new(name: String, variants: Vec<HirEnumVariant>) -> Self {
214        Self { name, variants }
215    }
216
217    /// Get the enum name.
218    pub fn name(&self) -> &str {
219        &self.name
220    }
221
222    /// Get the enum variants.
223    pub fn variants(&self) -> &[HirEnumVariant] {
224        &self.variants
225    }
226}
227
228/// Represents a typedef (type alias) in HIR.
229#[derive(Debug, Clone, PartialEq, Eq)]
230pub struct HirTypedef {
231    name: String,
232    underlying_type: HirType,
233}
234
235impl HirTypedef {
236    /// Create a new typedef.
237    ///
238    /// # Examples
239    ///
240    /// ```
241    /// use decy_hir::{HirTypedef, HirType};
242    ///
243    /// let typedef = HirTypedef::new("Integer".to_string(), HirType::Int);
244    /// assert_eq!(typedef.name(), "Integer");
245    /// assert_eq!(typedef.underlying_type(), &HirType::Int);
246    /// ```
247    pub fn new(name: String, underlying_type: HirType) -> Self {
248        Self {
249            name,
250            underlying_type,
251        }
252    }
253
254    /// Get the typedef name.
255    pub fn name(&self) -> &str {
256        &self.name
257    }
258
259    /// Get the underlying type.
260    pub fn underlying_type(&self) -> &HirType {
261        &self.underlying_type
262    }
263}
264
265/// Represents a constant declaration in HIR (from C #define or const).
266///
267/// # Examples
268///
269/// ```
270/// use decy_hir::{HirConstant, HirType, HirExpression};
271///
272/// let constant = HirConstant::new(
273///     "MAX".to_string(),
274///     HirType::Int,
275///     HirExpression::IntLiteral(100),
276/// );
277/// assert_eq!(constant.name(), "MAX");
278/// assert_eq!(constant.const_type(), &HirType::Int);
279/// ```
280#[derive(Debug, Clone, PartialEq)]
281pub struct HirConstant {
282    name: String,
283    const_type: HirType,
284    value: HirExpression,
285}
286
287impl HirConstant {
288    /// Create a new constant.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// use decy_hir::{HirConstant, HirType, HirExpression};
294    ///
295    /// let constant = HirConstant::new(
296    ///     "PI".to_string(),
297    ///     HirType::Float,
298    ///     HirExpression::IntLiteral(3), // Simplified for example
299    /// );
300    /// assert_eq!(constant.name(), "PI");
301    /// ```
302    pub fn new(name: String, const_type: HirType, value: HirExpression) -> Self {
303        Self {
304            name,
305            const_type,
306            value,
307        }
308    }
309
310    /// Get the constant name.
311    pub fn name(&self) -> &str {
312        &self.name
313    }
314
315    /// Get the constant type.
316    pub fn const_type(&self) -> &HirType {
317        &self.const_type
318    }
319
320    /// Get the constant value expression.
321    pub fn value(&self) -> &HirExpression {
322        &self.value
323    }
324}
325
326/// Represents a C macro definition in HIR.
327///
328/// C macros come in two forms:
329/// - Object-like: `#define MAX 100` (simple text substitution)
330/// - Function-like: `#define SQR(x) ((x) * (x))` (macro with parameters)
331///
332/// In Rust, these typically become:
333/// - Object-like → `const` declarations
334/// - Function-like → `fn` (inline functions) or `macro_rules!` (if truly necessary)
335///
336/// # Examples
337///
338/// ```
339/// use decy_hir::{HirMacroDefinition, HirType, HirExpression};
340///
341/// // Object-like macro: #define MAX 100
342/// let macro_def = HirMacroDefinition::new_object_like(
343///     "MAX".to_string(),
344///     "100".to_string(),
345/// );
346/// assert_eq!(macro_def.name(), "MAX");
347/// assert!(!macro_def.is_function_like());
348///
349/// // Function-like macro: #define SQR(x) ((x) * (x))
350/// let macro_def2 = HirMacroDefinition::new_function_like(
351///     "SQR".to_string(),
352///     vec!["x".to_string()],
353///     "((x) * (x))".to_string(),
354/// );
355/// assert_eq!(macro_def2.name(), "SQR");
356/// assert!(macro_def2.is_function_like());
357/// assert_eq!(macro_def2.parameters(), &["x"]);
358/// ```
359///
360/// Reference: K&R §4.11, ISO C99 §6.10.3
361#[derive(Debug, Clone, PartialEq, Eq)]
362pub struct HirMacroDefinition {
363    /// Macro name (e.g., "MAX", "SQR")
364    name: String,
365    /// Parameters for function-like macros (empty for object-like macros)
366    parameters: Vec<String>,
367    /// Macro body as a token string (unparsed)
368    /// This will be expanded during codegen
369    body: String,
370}
371
372impl HirMacroDefinition {
373    /// Create a new object-like macro (no parameters).
374    ///
375    /// # Examples
376    ///
377    /// ```
378    /// use decy_hir::HirMacroDefinition;
379    ///
380    /// // #define MAX 100
381    /// let macro_def = HirMacroDefinition::new_object_like(
382    ///     "MAX".to_string(),
383    ///     "100".to_string(),
384    /// );
385    /// assert_eq!(macro_def.name(), "MAX");
386    /// assert!(!macro_def.is_function_like());
387    /// ```
388    pub fn new_object_like(name: String, body: String) -> Self {
389        Self {
390            name,
391            parameters: vec![],
392            body,
393        }
394    }
395
396    /// Create a new function-like macro (with parameters).
397    ///
398    /// # Examples
399    ///
400    /// ```
401    /// use decy_hir::HirMacroDefinition;
402    ///
403    /// // #define SQR(x) ((x) * (x))
404    /// let macro_def = HirMacroDefinition::new_function_like(
405    ///     "SQR".to_string(),
406    ///     vec!["x".to_string()],
407    ///     "((x) * (x))".to_string(),
408    /// );
409    /// assert_eq!(macro_def.name(), "SQR");
410    /// assert!(macro_def.is_function_like());
411    /// assert_eq!(macro_def.parameters(), &["x"]);
412    /// ```
413    pub fn new_function_like(name: String, parameters: Vec<String>, body: String) -> Self {
414        Self {
415            name,
416            parameters,
417            body,
418        }
419    }
420
421    /// Get the macro name.
422    pub fn name(&self) -> &str {
423        &self.name
424    }
425
426    /// Get the macro parameters (empty for object-like macros).
427    pub fn parameters(&self) -> &[String] {
428        &self.parameters
429    }
430
431    /// Get the macro body (unparsed token string).
432    pub fn body(&self) -> &str {
433        &self.body
434    }
435
436    /// Check if this is a function-like macro (has parameters).
437    pub fn is_function_like(&self) -> bool {
438        !self.parameters.is_empty()
439    }
440
441    /// Check if this is an object-like macro (no parameters).
442    pub fn is_object_like(&self) -> bool {
443        self.parameters.is_empty()
444    }
445}
446
447/// Represents a function parameter in HIR.
448#[derive(Debug, Clone, PartialEq, Eq)]
449pub struct HirParameter {
450    name: String,
451    param_type: HirType,
452    /// DECY-135: Whether the pointee type is const (for pointer params like `const char*`)
453    is_pointee_const: bool,
454}
455
456impl HirParameter {
457    /// Create a new HIR parameter.
458    ///
459    /// # Examples
460    ///
461    /// ```
462    /// use decy_hir::{HirParameter, HirType};
463    ///
464    /// let param = HirParameter::new("x".to_string(), HirType::Int);
465    /// assert_eq!(param.name(), "x");
466    /// ```
467    pub fn new(name: String, param_type: HirType) -> Self {
468        Self {
469            name,
470            param_type,
471            is_pointee_const: false,
472        }
473    }
474
475    /// Get the parameter name.
476    pub fn name(&self) -> &str {
477        &self.name
478    }
479
480    /// Get the parameter type.
481    pub fn param_type(&self) -> &HirType {
482        &self.param_type
483    }
484
485    /// DECY-135: Check if this parameter has a const-qualified pointee.
486    pub fn is_pointee_const(&self) -> bool {
487        self.is_pointee_const
488    }
489
490    /// DECY-135: Check if this is a const char* parameter (should become &str).
491    pub fn is_const_char_pointer(&self) -> bool {
492        self.is_pointee_const
493            && matches!(self.param_type, HirType::Pointer(ref inner) if **inner == HirType::Char)
494    }
495
496    /// Convert from parser AST parameter to HIR parameter.
497    pub fn from_ast_parameter(ast_param: &decy_parser::parser::Parameter) -> Self {
498        Self {
499            name: ast_param.name.clone(),
500            param_type: HirType::from_ast_type(&ast_param.param_type),
501            is_pointee_const: ast_param.is_pointee_const,
502        }
503    }
504
505    /// DECY-135: Create a new parameter with a transformed type but preserving is_pointee_const.
506    /// Use this when transforming parameter types (e.g., pointer to reference) to maintain
507    /// const char* → &str transformation capability.
508    pub fn with_type(&self, new_type: HirType) -> Self {
509        Self {
510            name: self.name.clone(),
511            param_type: new_type,
512            is_pointee_const: self.is_pointee_const,
513        }
514    }
515}
516
517/// Represents a function in HIR.
518#[derive(Debug, Clone, PartialEq)]
519pub struct HirFunction {
520    name: String,
521    return_type: HirType,
522    parameters: Vec<HirParameter>,
523    body: Option<Vec<HirStatement>>,
524}
525
526impl HirFunction {
527    /// Create a new HIR function.
528    ///
529    /// # Examples
530    ///
531    /// ```
532    /// use decy_hir::{HirFunction, HirType, HirParameter};
533    ///
534    /// let func = HirFunction::new(
535    ///     "add".to_string(),
536    ///     HirType::Int,
537    ///     vec![
538    ///         HirParameter::new("a".to_string(), HirType::Int),
539    ///         HirParameter::new("b".to_string(), HirType::Int),
540    ///     ],
541    /// );
542    ///
543    /// assert_eq!(func.name(), "add");
544    /// assert_eq!(func.parameters().len(), 2);
545    /// ```
546    pub fn new(name: String, return_type: HirType, parameters: Vec<HirParameter>) -> Self {
547        Self {
548            name,
549            return_type,
550            parameters,
551            body: None,
552        }
553    }
554
555    /// Get the function name.
556    pub fn name(&self) -> &str {
557        &self.name
558    }
559
560    /// Get the return type.
561    pub fn return_type(&self) -> &HirType {
562        &self.return_type
563    }
564
565    /// Get the parameters.
566    pub fn parameters(&self) -> &[HirParameter] {
567        &self.parameters
568    }
569
570    /// Convert from parser AST function to HIR function.
571    ///
572    /// # Examples
573    ///
574    /// ```
575    /// use decy_hir::HirFunction;
576    /// use decy_parser::parser::{Function, Type, Parameter};
577    ///
578    /// let ast_func = Function::new(
579    ///     "test".to_string(),
580    ///     Type::Void,
581    ///     vec![],
582    /// );
583    ///
584    /// let hir_func = HirFunction::from_ast_function(&ast_func);
585    /// assert_eq!(hir_func.name(), "test");
586    /// ```
587    pub fn from_ast_function(ast_func: &decy_parser::parser::Function) -> Self {
588        let body = if ast_func.body.is_empty() {
589            None
590        } else {
591            Some(
592                ast_func
593                    .body
594                    .iter()
595                    .map(HirStatement::from_ast_statement)
596                    .collect(),
597            )
598        };
599
600        Self {
601            name: ast_func.name.clone(),
602            return_type: HirType::from_ast_type(&ast_func.return_type),
603            parameters: ast_func
604                .parameters
605                .iter()
606                .map(HirParameter::from_ast_parameter)
607                .collect(),
608            body,
609        }
610    }
611
612    /// Create a new HIR function with a body.
613    ///
614    /// # Examples
615    ///
616    /// ```
617    /// use decy_hir::{HirFunction, HirType, HirStatement, HirExpression};
618    ///
619    /// let func = HirFunction::new_with_body(
620    ///     "test".to_string(),
621    ///     HirType::Int,
622    ///     vec![],
623    ///     vec![
624    ///         HirStatement::VariableDeclaration {
625    ///             name: "x".to_string(),
626    ///             var_type: HirType::Int,
627    ///             initializer: Some(HirExpression::IntLiteral(5)),
628    ///         },
629    ///         HirStatement::Return(Some(HirExpression::Variable("x".to_string()))),
630    ///     ],
631    /// );
632    ///
633    /// assert_eq!(func.name(), "test");
634    /// assert_eq!(func.body().len(), 2);
635    /// ```
636    pub fn new_with_body(
637        name: String,
638        return_type: HirType,
639        parameters: Vec<HirParameter>,
640        body: Vec<HirStatement>,
641    ) -> Self {
642        Self {
643            name,
644            return_type,
645            parameters,
646            body: Some(body),
647        }
648    }
649
650    /// Get the function body.
651    pub fn body(&self) -> &[HirStatement] {
652        self.body.as_deref().unwrap_or(&[])
653    }
654
655    /// DECY-190: Check if this function has a body (is a definition, not just a declaration).
656    /// Returns true for definitions, false for forward declarations/prototypes.
657    pub fn has_body(&self) -> bool {
658        self.body.is_some()
659    }
660}
661
662/// Unary operators for expressions.
663#[derive(Debug, Clone, Copy, PartialEq, Eq)]
664pub enum UnaryOperator {
665    /// Unary minus (-x)
666    Minus,
667    /// Logical NOT (!x)
668    LogicalNot,
669    /// Bitwise NOT (~x)
670    BitwiseNot,
671    /// Address-of (&x)
672    AddressOf,
673    /// Post-increment (x++)
674    /// Returns old value, then increments
675    /// Reference: ISO C99 §6.5.2.4, K&R §2.8
676    PostIncrement,
677    /// Post-decrement (x--)
678    /// Returns old value, then decrements
679    /// Reference: ISO C99 §6.5.2.4, K&R §2.8
680    PostDecrement,
681    /// Pre-increment (++x)
682    /// Increments first, then returns new value
683    /// Reference: ISO C99 §6.5.3.1, K&R §2.8
684    PreIncrement,
685    /// Pre-decrement (--x)
686    /// Decrements first, then returns new value
687    /// Reference: ISO C99 §6.5.3.1, K&R §2.8
688    PreDecrement,
689}
690
691/// Binary operators for expressions.
692#[derive(Debug, Clone, Copy, PartialEq, Eq)]
693pub enum BinaryOperator {
694    /// Addition (+)
695    Add,
696    /// Subtraction (-)
697    Subtract,
698    /// Multiplication (*)
699    Multiply,
700    /// Division (/)
701    Divide,
702    /// Modulo (%)
703    Modulo,
704    /// Equality (==)
705    Equal,
706    /// Inequality (!=)
707    NotEqual,
708    /// Less than (<)
709    LessThan,
710    /// Greater than (>)
711    GreaterThan,
712    /// Less than or equal (<=)
713    LessEqual,
714    /// Greater than or equal (>=)
715    GreaterEqual,
716    /// Logical AND (&&)
717    LogicalAnd,
718    /// Logical OR (||)
719    LogicalOr,
720    /// Left shift (<<)
721    LeftShift,
722    /// Right shift (>>)
723    RightShift,
724    /// Bitwise AND (&)
725    BitwiseAnd,
726    /// Bitwise OR (|)
727    BitwiseOr,
728    /// Bitwise XOR (^)
729    BitwiseXor,
730    /// Assignment (=) - for embedded assignments like (c=getchar())
731    Assign,
732    /// Comma operator (,) - DECY-224: for multi-expression statements
733    Comma,
734}
735
736/// Represents an expression in HIR.
737#[derive(Debug, Clone, PartialEq)]
738pub enum HirExpression {
739    /// Integer literal
740    IntLiteral(i32),
741    /// Float literal (stored as string to preserve precision)
742    FloatLiteral(String),
743    /// String literal (C: "hello" → Rust: "hello")
744    StringLiteral(String),
745    /// Character literal (C: 'a', '\0', '\n' → Rust: b'a', 0, b'\n')
746    CharLiteral(i8),
747    /// Variable reference
748    Variable(String),
749    /// Binary operation (left op right)
750    BinaryOp {
751        /// The operator
752        op: BinaryOperator,
753        /// Left operand
754        left: Box<HirExpression>,
755        /// Right operand
756        right: Box<HirExpression>,
757    },
758    /// Dereference operation (*ptr)
759    Dereference(Box<HirExpression>),
760    /// Address-of operation (&x)
761    AddressOf(Box<HirExpression>),
762    /// Unary operation (-x, !x)
763    UnaryOp {
764        /// The operator
765        op: UnaryOperator,
766        /// Operand
767        operand: Box<HirExpression>,
768    },
769    /// Post-increment expression (x++)
770    /// C semantics: returns old value, then increments
771    /// Rust: { let tmp = x; x += 1; tmp }
772    PostIncrement {
773        /// The operand to increment
774        operand: Box<HirExpression>,
775    },
776    /// Pre-increment expression (++x)
777    /// C semantics: increments first, then returns new value
778    /// Rust: { x += 1; x }
779    PreIncrement {
780        /// The operand to increment
781        operand: Box<HirExpression>,
782    },
783    /// Post-decrement expression (x--)
784    /// C semantics: returns old value, then decrements
785    /// Rust: { let tmp = x; x -= 1; tmp }
786    PostDecrement {
787        /// The operand to decrement
788        operand: Box<HirExpression>,
789    },
790    /// Pre-decrement expression (--x)
791    /// C semantics: decrements first, then returns new value
792    /// Rust: { x -= 1; x }
793    PreDecrement {
794        /// The operand to decrement
795        operand: Box<HirExpression>,
796    },
797    /// Function call (function_name(args...))
798    FunctionCall {
799        /// Function name
800        function: String,
801        /// Arguments
802        arguments: Vec<HirExpression>,
803    },
804    /// Field access (obj.field)
805    FieldAccess {
806        /// Object expression
807        object: Box<HirExpression>,
808        /// Field name
809        field: String,
810    },
811    /// Pointer field access (ptr->field)
812    PointerFieldAccess {
813        /// Pointer expression
814        pointer: Box<HirExpression>,
815        /// Field name
816        field: String,
817    },
818    /// Array indexing
819    ArrayIndex {
820        /// Array expression
821        array: Box<HirExpression>,
822        /// Index expression
823        index: Box<HirExpression>,
824    },
825    /// Safe slice indexing (DECY-069)
826    /// Represents safe, bounds-checked array access: `arr[index]`
827    /// Generated when pointer arithmetic can be transformed to safe indexing.
828    /// Unlike ArrayIndex (which may use unsafe), SliceIndex guarantees zero unsafe blocks.
829    SliceIndex {
830        /// Slice/array expression
831        slice: Box<HirExpression>,
832        /// Index expression
833        index: Box<HirExpression>,
834        /// Element type (for codegen type inference)
835        element_type: HirType,
836    },
837    /// Sizeof expression (sizeof(T) → `std::mem::size_of::<T>()`)
838    Sizeof {
839        /// Type name as a string (e.g., "int", "struct Data")
840        type_name: String,
841    },
842    /// NULL literal (NULL → None)
843    NullLiteral,
844    /// NULL check expression (p != NULL → is_some(), p == NULL → is_none())
845    IsNotNull(Box<HirExpression>),
846    /// calloc(count, sizeof(T)) → vec![0; count]
847    Calloc {
848        /// Number of elements to allocate
849        count: Box<HirExpression>,
850        /// Element type
851        element_type: Box<HirType>,
852    },
853    /// malloc(size) → Box::new(default) or Vec::with_capacity(n)
854    Malloc {
855        /// Size expression (typically sizeof(T) or n * sizeof(T))
856        size: Box<HirExpression>,
857    },
858    /// realloc(ptr, new_size) → Vec::resize or Vec::reserve
859    Realloc {
860        /// Pointer to reallocate
861        pointer: Box<HirExpression>,
862        /// New size expression (typically n * sizeof(T))
863        new_size: Box<HirExpression>,
864    },
865    /// String method call (e.g., s.len(), s.to_string(), s.clone_into(&mut dst))
866    StringMethodCall {
867        /// Receiver expression (e.g., s in s.len())
868        receiver: Box<HirExpression>,
869        /// Method name (e.g., "len", "to_string", "clone_into")
870        method: String,
871        /// Arguments to the method call
872        arguments: Vec<HirExpression>,
873    },
874    /// Cast expression (C: (int)x → Rust: x as i32)
875    ///
876    /// Represents a C-style cast that converts an expression to a target type.
877    /// Maps to Rust `as` operator for safe casts, or `transmute` for unsafe casts.
878    ///
879    /// # Sprint 19 Feature (DECY-059)
880    ///
881    /// Added in Sprint 19 to support C cast expressions.
882    Cast {
883        /// Target type to cast to
884        target_type: HirType,
885        /// Expression being cast
886        expr: Box<HirExpression>,
887    },
888    /// Compound literal (C: (struct Point){10, 20} → Rust: Point { x: 10, y: 20 })
889    ///
890    /// C99 compound literals create anonymous objects of a specified type.
891    /// Used for inline struct/array initialization.
892    ///
893    /// # Sprint 19 Feature (DECY-060)
894    ///
895    /// Added in Sprint 19 to support C99 compound literals.
896    CompoundLiteral {
897        /// Type of the compound literal (struct Point, int[], etc.)
898        literal_type: HirType,
899        /// Initializer expressions (values for struct fields or array elements)
900        initializers: Vec<HirExpression>,
901    },
902    /// Ternary/Conditional expression (C: cond ? then_val : else_val)
903    ///
904    /// The C ternary operator evaluates the condition and returns either
905    /// the then_val or else_val based on whether condition is truthy.
906    ///
907    /// Maps to Rust's `if cond { then_val } else { else_val }` expression.
908    ///
909    /// # DECY-192
910    ///
911    /// Added to support K&R Chapter 2.11 Conditional Expressions.
912    Ternary {
913        /// Condition expression (evaluated as boolean)
914        condition: Box<HirExpression>,
915        /// Value if condition is true
916        then_expr: Box<HirExpression>,
917        /// Value if condition is false
918        else_expr: Box<HirExpression>,
919    },
920}
921
922/// Represents a single case in a switch statement.
923#[derive(Debug, Clone, PartialEq)]
924pub struct SwitchCase {
925    /// Case value expression (None for default case)
926    pub value: Option<HirExpression>,
927    /// Statements to execute for this case
928    pub body: Vec<HirStatement>,
929}
930
931/// Represents a statement in HIR.
932#[derive(Debug, Clone, PartialEq)]
933pub enum HirStatement {
934    /// Variable declaration with optional initializer
935    VariableDeclaration {
936        /// Variable name
937        name: String,
938        /// Variable type
939        var_type: HirType,
940        /// Optional initializer expression
941        initializer: Option<HirExpression>,
942    },
943    /// Return statement with optional value
944    Return(Option<HirExpression>),
945    /// If statement with condition, then-block, and optional else-block
946    If {
947        /// Condition expression
948        condition: HirExpression,
949        /// Then block (statements to execute if condition is true)
950        then_block: Vec<HirStatement>,
951        /// Else block (optional statements to execute if condition is false)
952        else_block: Option<Vec<HirStatement>>,
953    },
954    /// While loop with condition and body
955    While {
956        /// Loop condition
957        condition: HirExpression,
958        /// Loop body (statements to execute while condition is true)
959        body: Vec<HirStatement>,
960    },
961    /// Break statement (exit loop)
962    Break,
963    /// Continue statement (skip to next iteration)
964    Continue,
965    /// Assignment statement (target = value)
966    Assignment {
967        /// Target variable name
968        target: String,
969        /// Value expression to assign
970        value: HirExpression,
971    },
972    /// For loop with optional init, condition, optional increment, and body
973    For {
974        /// Initialization statements (e.g., int i = 0, j = 10) - DECY-224
975        init: Vec<HirStatement>,
976        /// Loop condition expression (None = infinite loop, e.g. `for(;;)`)
977        condition: Option<HirExpression>,
978        /// Increment statements (e.g., i++, j--) - DECY-224
979        increment: Vec<HirStatement>,
980        /// Loop body (statements to execute while condition is true)
981        body: Vec<HirStatement>,
982    },
983    /// Switch statement with condition, cases, and optional default case
984    Switch {
985        /// Condition expression to match against
986        condition: HirExpression,
987        /// List of case statements
988        cases: Vec<SwitchCase>,
989        /// Optional default case body
990        default_case: Option<Vec<HirStatement>>,
991    },
992    /// Pointer dereference assignment (*ptr = value)
993    DerefAssignment {
994        /// Target expression to dereference
995        target: HirExpression,
996        /// Value expression to assign
997        value: HirExpression,
998    },
999    /// Array index assignment
1000    ArrayIndexAssignment {
1001        /// Array expression
1002        array: Box<HirExpression>,
1003        /// Index expression
1004        index: Box<HirExpression>,
1005        /// Value expression to assign
1006        value: HirExpression,
1007    },
1008    /// Field assignment (ptr->field = value or obj.field = value)
1009    FieldAssignment {
1010        /// Object/pointer expression
1011        object: HirExpression,
1012        /// Field name
1013        field: String,
1014        /// Value expression to assign
1015        value: HirExpression,
1016    },
1017    /// Free statement (free(ptr) → automatic drop via RAII)
1018    Free {
1019        /// Pointer expression to free
1020        pointer: HirExpression,
1021    },
1022    /// Expression statement (e.g., printf("Hello");, free(ptr);, i++;)
1023    ///
1024    /// Represents an expression used as a statement, typically for side effects.
1025    /// Common in C for function calls whose return values are discarded.
1026    ///
1027    /// # DECY-065
1028    ///
1029    /// Added to fix bug where function call statements (like printf) were being
1030    /// converted to Break placeholder, causing them to disappear during transpilation.
1031    Expression(HirExpression),
1032    /// Inline assembly statement (C: asm("...") or __asm__("..."))
1033    ///
1034    /// C inline assembly cannot be automatically transpiled to safe Rust.
1035    /// This variant preserves the assembly text for manual review.
1036    ///
1037    /// # DECY-197
1038    ///
1039    /// Added to handle inline assembly in C code. The codegen emits a
1040    /// review-required comment rather than attempting automatic translation.
1041    InlineAsm {
1042        /// The raw assembly text from the C source
1043        text: String,
1044        /// Whether the assembly might be translatable to Rust intrinsics
1045        translatable: bool,
1046    },
1047}
1048
1049impl HirStatement {
1050    /// Convert from parser AST statement to HIR statement.
1051    pub fn from_ast_statement(ast_stmt: &decy_parser::parser::Statement) -> Self {
1052        use decy_parser::parser::Statement;
1053        match ast_stmt {
1054            Statement::VariableDeclaration {
1055                name,
1056                var_type,
1057                initializer,
1058            } => HirStatement::VariableDeclaration {
1059                name: name.clone(),
1060                var_type: HirType::from_ast_type(var_type),
1061                initializer: initializer.as_ref().map(HirExpression::from_ast_expression),
1062            },
1063            Statement::Return(expr) => {
1064                HirStatement::Return(expr.as_ref().map(HirExpression::from_ast_expression))
1065            }
1066            Statement::Assignment { target, value } => HirStatement::Assignment {
1067                target: target.clone(),
1068                value: HirExpression::from_ast_expression(value),
1069            },
1070            Statement::If {
1071                condition,
1072                then_block,
1073                else_block,
1074            } => HirStatement::If {
1075                condition: HirExpression::from_ast_expression(condition),
1076                then_block: then_block
1077                    .iter()
1078                    .map(HirStatement::from_ast_statement)
1079                    .collect(),
1080                else_block: else_block
1081                    .as_ref()
1082                    .map(|block| block.iter().map(HirStatement::from_ast_statement).collect()),
1083            },
1084            Statement::For {
1085                init,
1086                condition,
1087                increment,
1088                body,
1089            } => HirStatement::For {
1090                // DECY-224: Support multiple init statements
1091                init: init.iter().map(HirStatement::from_ast_statement).collect(),
1092                condition: condition
1093                    .as_ref()
1094                    .map(HirExpression::from_ast_expression),
1095                // DECY-224: Support multiple increment statements
1096                increment: increment
1097                    .iter()
1098                    .map(HirStatement::from_ast_statement)
1099                    .collect(),
1100                body: body.iter().map(HirStatement::from_ast_statement).collect(),
1101            },
1102            Statement::While { condition, body } => HirStatement::While {
1103                condition: HirExpression::from_ast_expression(condition),
1104                body: body.iter().map(HirStatement::from_ast_statement).collect(),
1105            },
1106            Statement::DerefAssignment { target, value } => HirStatement::DerefAssignment {
1107                target: HirExpression::from_ast_expression(target),
1108                value: HirExpression::from_ast_expression(value),
1109            },
1110            Statement::ArrayIndexAssignment {
1111                array,
1112                index,
1113                value,
1114            } => HirStatement::ArrayIndexAssignment {
1115                array: Box::new(HirExpression::from_ast_expression(array)),
1116                index: Box::new(HirExpression::from_ast_expression(index)),
1117                value: HirExpression::from_ast_expression(value),
1118            },
1119            Statement::FieldAssignment {
1120                object,
1121                field,
1122                value,
1123            } => HirStatement::FieldAssignment {
1124                object: HirExpression::from_ast_expression(object),
1125                field: field.clone(),
1126                value: HirExpression::from_ast_expression(value),
1127            },
1128            Statement::Break => HirStatement::Break,
1129            Statement::Continue => HirStatement::Continue,
1130            // Increment/decrement statements are converted to assignments
1131            // ptr++ becomes ptr = ptr + 1
1132            Statement::PostIncrement { target } | Statement::PreIncrement { target } => {
1133                HirStatement::Assignment {
1134                    target: target.clone(),
1135                    value: HirExpression::BinaryOp {
1136                        op: BinaryOperator::Add,
1137                        left: Box::new(HirExpression::Variable(target.clone())),
1138                        right: Box::new(HirExpression::IntLiteral(1)),
1139                    },
1140                }
1141            }
1142            // ptr-- becomes ptr = ptr - 1
1143            Statement::PostDecrement { target } | Statement::PreDecrement { target } => {
1144                HirStatement::Assignment {
1145                    target: target.clone(),
1146                    value: HirExpression::BinaryOp {
1147                        op: BinaryOperator::Subtract,
1148                        left: Box::new(HirExpression::Variable(target.clone())),
1149                        right: Box::new(HirExpression::IntLiteral(1)),
1150                    },
1151                }
1152            }
1153            // Compound assignments like ptr += offset become ptr = ptr + offset
1154            Statement::CompoundAssignment { target, op, value } => HirStatement::Assignment {
1155                target: target.clone(),
1156                value: HirExpression::BinaryOp {
1157                    op: convert_binary_operator(*op),
1158                    left: Box::new(HirExpression::Variable(target.clone())),
1159                    right: Box::new(HirExpression::from_ast_expression(value)),
1160                },
1161            },
1162            // DECY-185: Compound assignments to complex targets like *ptr *= 2, sb->capacity *= 2
1163            // These become DerefAssignment with a BinaryOp value
1164            Statement::DerefCompoundAssignment { target, op, value } => {
1165                let hir_target = HirExpression::from_ast_expression(target);
1166                HirStatement::DerefAssignment {
1167                    target: hir_target.clone(),
1168                    value: HirExpression::BinaryOp {
1169                        op: convert_binary_operator(*op),
1170                        left: Box::new(hir_target),
1171                        right: Box::new(HirExpression::from_ast_expression(value)),
1172                    },
1173                }
1174            }
1175            // Switch statement - convert cases and default
1176            Statement::Switch {
1177                condition,
1178                cases,
1179                default_case,
1180            } => HirStatement::Switch {
1181                condition: HirExpression::from_ast_expression(condition),
1182                cases: cases
1183                    .iter()
1184                    .map(|case| SwitchCase {
1185                        value: case.value.as_ref().map(HirExpression::from_ast_expression),
1186                        body: case
1187                            .body
1188                            .iter()
1189                            .map(HirStatement::from_ast_statement)
1190                            .collect(),
1191                    })
1192                    .collect(),
1193                default_case: default_case
1194                    .as_ref()
1195                    .map(|block| block.iter().map(HirStatement::from_ast_statement).collect()),
1196            },
1197            // Function call statement - convert to expression statement
1198            // DECY-065: Now properly supported with HirStatement::Expression variant
1199            Statement::FunctionCall {
1200                function,
1201                arguments,
1202            } => HirStatement::Expression(HirExpression::FunctionCall {
1203                function: function.clone(),
1204                arguments: arguments
1205                    .iter()
1206                    .map(HirExpression::from_ast_expression)
1207                    .collect(),
1208            }),
1209        }
1210    }
1211}
1212
1213impl HirExpression {
1214    /// Convert from parser AST expression to HIR expression.
1215    pub fn from_ast_expression(ast_expr: &decy_parser::parser::Expression) -> Self {
1216        use decy_parser::parser::Expression;
1217        match ast_expr {
1218            Expression::IntLiteral(value) => HirExpression::IntLiteral(*value),
1219            Expression::FloatLiteral(value) => HirExpression::FloatLiteral(value.clone()),
1220            Expression::StringLiteral(value) => HirExpression::StringLiteral(value.clone()),
1221            Expression::CharLiteral(value) => HirExpression::CharLiteral(*value),
1222            Expression::Variable(name) => HirExpression::Variable(name.clone()),
1223            Expression::BinaryOp { op, left, right } => HirExpression::BinaryOp {
1224                op: convert_binary_operator(*op),
1225                left: Box::new(HirExpression::from_ast_expression(left)),
1226                right: Box::new(HirExpression::from_ast_expression(right)),
1227            },
1228            Expression::FunctionCall {
1229                function,
1230                arguments,
1231            } => HirExpression::FunctionCall {
1232                function: function.clone(),
1233                arguments: arguments
1234                    .iter()
1235                    .map(HirExpression::from_ast_expression)
1236                    .collect(),
1237            },
1238            Expression::Dereference(inner) => {
1239                HirExpression::Dereference(Box::new(HirExpression::from_ast_expression(inner)))
1240            }
1241            Expression::UnaryOp { op, operand } => HirExpression::UnaryOp {
1242                op: convert_unary_operator(*op),
1243                operand: Box::new(HirExpression::from_ast_expression(operand)),
1244            },
1245            Expression::ArrayIndex { array, index } => HirExpression::ArrayIndex {
1246                array: Box::new(HirExpression::from_ast_expression(array)),
1247                index: Box::new(HirExpression::from_ast_expression(index)),
1248            },
1249            Expression::FieldAccess { object, field } => HirExpression::FieldAccess {
1250                object: Box::new(HirExpression::from_ast_expression(object)),
1251                field: field.clone(),
1252            },
1253            Expression::PointerFieldAccess { pointer, field } => {
1254                HirExpression::PointerFieldAccess {
1255                    pointer: Box::new(HirExpression::from_ast_expression(pointer)),
1256                    field: field.clone(),
1257                }
1258            }
1259            // DECY-139: Increment/decrement expressions in expression context
1260            // Properly preserve the increment/decrement for codegen to emit correct Rust
1261            Expression::PostIncrement { operand } => HirExpression::PostIncrement {
1262                operand: Box::new(HirExpression::from_ast_expression(operand)),
1263            },
1264            Expression::PreIncrement { operand } => HirExpression::PreIncrement {
1265                operand: Box::new(HirExpression::from_ast_expression(operand)),
1266            },
1267            Expression::PostDecrement { operand } => HirExpression::PostDecrement {
1268                operand: Box::new(HirExpression::from_ast_expression(operand)),
1269            },
1270            Expression::PreDecrement { operand } => HirExpression::PreDecrement {
1271                operand: Box::new(HirExpression::from_ast_expression(operand)),
1272            },
1273            Expression::Sizeof { type_name } => HirExpression::Sizeof {
1274                type_name: type_name.clone(),
1275            },
1276            Expression::Cast { target_type, expr } => HirExpression::Cast {
1277                target_type: HirType::from_ast_type(target_type),
1278                expr: Box::new(HirExpression::from_ast_expression(expr)),
1279            },
1280            Expression::CompoundLiteral {
1281                literal_type,
1282                initializers,
1283            } => HirExpression::CompoundLiteral {
1284                literal_type: HirType::from_ast_type(literal_type),
1285                initializers: initializers
1286                    .iter()
1287                    .map(HirExpression::from_ast_expression)
1288                    .collect(),
1289            },
1290            // DECY-192: Ternary/conditional expression
1291            Expression::Ternary {
1292                condition,
1293                then_expr,
1294                else_expr,
1295            } => HirExpression::Ternary {
1296                condition: Box::new(HirExpression::from_ast_expression(condition)),
1297                then_expr: Box::new(HirExpression::from_ast_expression(then_expr)),
1298                else_expr: Box::new(HirExpression::from_ast_expression(else_expr)),
1299            },
1300        }
1301    }
1302}
1303
1304/// Convert parser UnaryOperator to HIR UnaryOperator
1305fn convert_unary_operator(op: decy_parser::parser::UnaryOperator) -> UnaryOperator {
1306    use decy_parser::parser::UnaryOperator as ParserOp;
1307    match op {
1308        ParserOp::Minus => UnaryOperator::Minus,
1309        ParserOp::LogicalNot => UnaryOperator::LogicalNot,
1310        ParserOp::BitwiseNot => UnaryOperator::BitwiseNot,
1311        ParserOp::AddressOf => UnaryOperator::AddressOf,
1312    }
1313}
1314
1315/// Convert parser BinaryOperator to HIR BinaryOperator
1316fn convert_binary_operator(op: decy_parser::parser::BinaryOperator) -> BinaryOperator {
1317    use decy_parser::parser::BinaryOperator as ParserOp;
1318    match op {
1319        ParserOp::Add => BinaryOperator::Add,
1320        ParserOp::Subtract => BinaryOperator::Subtract,
1321        ParserOp::Multiply => BinaryOperator::Multiply,
1322        ParserOp::Divide => BinaryOperator::Divide,
1323        ParserOp::Modulo => BinaryOperator::Modulo,
1324        ParserOp::Equal => BinaryOperator::Equal,
1325        ParserOp::NotEqual => BinaryOperator::NotEqual,
1326        ParserOp::LessThan => BinaryOperator::LessThan,
1327        ParserOp::GreaterThan => BinaryOperator::GreaterThan,
1328        ParserOp::LessEqual => BinaryOperator::LessEqual,
1329        ParserOp::GreaterEqual => BinaryOperator::GreaterEqual,
1330        ParserOp::LogicalAnd => BinaryOperator::LogicalAnd,
1331        ParserOp::LogicalOr => BinaryOperator::LogicalOr,
1332        // DECY-137: Bitwise and shift operators
1333        ParserOp::LeftShift => BinaryOperator::LeftShift,
1334        ParserOp::RightShift => BinaryOperator::RightShift,
1335        ParserOp::BitwiseAnd => BinaryOperator::BitwiseAnd,
1336        ParserOp::BitwiseOr => BinaryOperator::BitwiseOr,
1337        ParserOp::BitwiseXor => BinaryOperator::BitwiseXor,
1338        // DECY-195: Assignment operator for embedded assignments
1339        ParserOp::Assign => BinaryOperator::Assign,
1340        // DECY-224: Comma operator for multi-expression statements
1341        ParserOp::Comma => BinaryOperator::Comma,
1342    }
1343}
1344
1345#[cfg(test)]
1346#[path = "hir_tests.rs"]
1347mod hir_tests;
1348
1349#[cfg(test)]
1350#[path = "property_tests.rs"]
1351mod property_tests;
1352
1353#[cfg(test)]
1354#[path = "statement_tests.rs"]
1355mod statement_tests;
1356
1357#[cfg(test)]
1358#[path = "struct_tests.rs"]
1359mod struct_tests;
1360
1361#[cfg(test)]
1362#[path = "array_indexing_tests.rs"]
1363mod array_indexing_tests;
1364
1365#[cfg(test)]
1366#[path = "slice_index_tests.rs"]
1367mod slice_index_tests; // DECY-069
1368
1369#[cfg(test)]
1370#[path = "for_loop_tests.rs"]
1371mod for_loop_tests;
1372
1373#[cfg(test)]
1374#[path = "typedef_tests.rs"]
1375mod typedef_tests;
1376
1377#[cfg(test)]
1378#[path = "typedef_property_tests.rs"]
1379mod typedef_property_tests;
1380
1381#[cfg(test)]
1382#[path = "function_pointer_tests.rs"]
1383mod function_pointer_tests;
1384
1385#[cfg(test)]
1386#[path = "string_tests.rs"]
1387mod string_tests;
1388
1389#[cfg(test)]
1390#[path = "string_property_tests.rs"]
1391mod string_property_tests;
1392
1393#[cfg(test)]
1394#[path = "switch_tests.rs"]
1395mod switch_tests;
1396
1397#[cfg(test)]
1398#[path = "macro_definition_tests.rs"]
1399mod macro_definition_tests;
1400
1401#[cfg(test)]
1402#[path = "coverage_tests.rs"]
1403mod coverage_tests;