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;