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