1use crate::parser::{CppAst, MethodQualifier};
2use petgraph::graph::{DiGraph, NodeIndex};
3use std::collections::HashMap;
4use crate::debug_println;
5
6fn parse_operator_name(func_name: &str) -> Option<&str> {
9 if let Some(pos) = func_name.rfind("operator") {
11 let op = &func_name[pos + "operator".len()..];
12 if !op.is_empty() {
13 return Some(op);
14 }
15 }
16 None
17}
18
19fn is_dereference_operator(func_name: &str) -> bool {
21 if let Some(op) = parse_operator_name(func_name) {
22 op == "*"
23 } else {
24 false
25 }
26}
27
28fn is_assignment_operator(func_name: &str) -> bool {
30 if let Some(op) = parse_operator_name(func_name) {
31 op == "="
32 } else {
33 false
34 }
35}
36
37fn is_member_access_operator(func_name: &str) -> bool {
39 if let Some(op) = parse_operator_name(func_name) {
40 op == "->"
41 } else {
42 false
43 }
44}
45
46fn extract_member_path(expr: &crate::parser::Expression) -> Option<(String, String)> {
51 match expr {
52 crate::parser::Expression::MemberAccess { object, field } => {
53 match object.as_ref() {
54 crate::parser::Expression::Variable(var_name) => {
55 Some((var_name.clone(), field.clone()))
57 }
58 crate::parser::Expression::MemberAccess { .. } => {
59 let object_path = extract_full_member_path(object.as_ref())?;
61 Some((object_path, field.clone()))
62 }
63 _ => None
64 }
65 }
66 _ => None
67 }
68}
69
70fn extract_full_member_path(expr: &crate::parser::Expression) -> Option<String> {
74 match expr {
75 crate::parser::Expression::Variable(name) => Some(name.clone()),
76 crate::parser::Expression::MemberAccess { object, field } => {
77 let obj_path = extract_full_member_path(object.as_ref())?;
78 Some(format!("{}.{}", obj_path, field))
79 }
80 _ => None
81 }
82}
83
84#[derive(Debug, Clone)]
85pub struct IrProgram {
86 pub functions: Vec<IrFunction>,
87 #[allow(dead_code)]
88 pub ownership_graph: OwnershipGraph,
89 pub user_defined_raii_types: std::collections::HashSet<String>,
91}
92
93#[derive(Debug, Clone)]
94pub struct IrFunction {
95 #[allow(dead_code)]
96 pub name: String,
97 pub cfg: ControlFlowGraph,
98 pub variables: HashMap<String, VariableInfo>,
99 pub return_type: String, pub source_file: String, pub is_method: bool,
103 pub method_qualifier: Option<MethodQualifier>,
104 pub class_name: Option<String>,
105 pub template_parameters: Vec<String>, pub lifetime_params: HashMap<String, LifetimeParam>, pub param_lifetimes: Vec<Option<ParameterLifetime>>, pub return_lifetime: Option<ReturnLifetime>, pub lifetime_constraints: Vec<LifetimeConstraint>, }
113
114#[derive(Debug, Clone, PartialEq)]
117pub struct LifetimeParam {
118 pub name: String, }
120
121#[derive(Debug, Clone, PartialEq)]
123pub struct ParameterLifetime {
124 pub lifetime_name: String, pub is_mutable: bool, pub is_owned: bool, }
128
129#[derive(Debug, Clone, PartialEq)]
131pub struct ReturnLifetime {
132 pub lifetime_name: String, pub is_mutable: bool, pub is_owned: bool, }
136
137#[derive(Debug, Clone, PartialEq)]
139pub struct LifetimeConstraint {
140 pub longer: String, pub shorter: String, }
143
144#[derive(Debug, Clone)]
145pub struct VariableInfo {
146 #[allow(dead_code)]
147 pub name: String,
148 #[allow(dead_code)]
149 pub ty: VariableType,
150 pub ownership: OwnershipState,
151 #[allow(dead_code)]
152 pub lifetime: Option<Lifetime>,
153 pub is_parameter: bool, pub is_static: bool, pub scope_level: usize, pub has_destructor: bool, pub declaration_index: usize, }
159
160#[derive(Debug, Clone, PartialEq)]
161#[allow(dead_code)]
162pub enum VariableType {
163 Owned(String), Reference(String), MutableReference(String),
166 UniquePtr(String),
167 SharedPtr(String),
168 Raw(String),
169}
170
171#[derive(Debug, Clone, PartialEq)]
172#[allow(dead_code)]
173pub enum OwnershipState {
174 Owned,
175 Borrowed(BorrowKind),
176 Moved,
177 Uninitialized,
178}
179
180#[derive(Debug, Clone, PartialEq)]
181#[allow(dead_code)]
182pub enum BorrowKind {
183 Immutable,
184 Mutable,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188pub struct Lifetime {
189 pub name: String,
190 pub scope_start: usize,
191 pub scope_end: usize,
192}
193
194pub type ControlFlowGraph = DiGraph<BasicBlock, ()>;
195pub type OwnershipGraph = DiGraph<String, OwnershipEdge>;
196
197#[derive(Debug, Clone)]
198pub struct BasicBlock {
199 #[allow(dead_code)]
200 pub id: usize,
201 pub statements: Vec<IrStatement>,
202 #[allow(dead_code)]
203 pub terminator: Option<Terminator>,
204}
205
206#[derive(Debug, Clone)]
207#[allow(dead_code)]
208pub enum IrStatement {
209 Assign {
210 lhs: String,
211 rhs: IrExpression,
212 },
213 Move {
214 from: String,
215 to: String,
216 },
217 Borrow {
218 from: String,
219 to: String,
220 kind: BorrowKind,
221 },
222 CallExpr {
223 func: String,
224 args: Vec<String>,
225 result: Option<String>,
226 },
227 Return {
228 value: Option<String>,
229 },
230 Drop(String),
231 EnterScope,
233 ExitScope,
234 EnterLoop,
236 ExitLoop,
237 If {
239 then_branch: Vec<IrStatement>,
240 else_branch: Option<Vec<IrStatement>>,
241 },
242 EnterUnsafe,
244 ExitUnsafe,
245 PackExpansion {
247 pack_name: String,
248 operation: String, },
250 UseVariable {
252 var: String,
253 operation: String, },
255 MoveField {
257 object: String, field: String, to: String, },
261 UseField {
262 object: String,
263 field: String,
264 operation: String, },
266 BorrowField {
267 object: String,
268 field: String,
269 to: String,
270 kind: BorrowKind,
271 },
272 ImplicitDrop {
274 var: String,
275 scope_level: usize,
276 has_destructor: bool, },
278 LambdaCapture {
280 captures: Vec<LambdaCaptureInfo>,
281 },
282 VarDecl {
284 name: String,
285 type_name: String,
286 },
287}
288
289#[derive(Debug, Clone)]
291pub struct LambdaCaptureInfo {
292 pub name: String,
293 pub is_ref: bool, pub is_this: bool, }
296
297#[derive(Debug, Clone)]
298#[allow(dead_code)]
299pub enum IrExpression {
300 Variable(String),
301 Move(String),
302 Borrow(String, BorrowKind),
303 New(String), Literal(String), }
306
307#[derive(Debug, Clone)]
308#[allow(dead_code)]
309pub enum Terminator {
310 Return(Option<String>),
311 Jump(NodeIndex),
312 Branch {
313 condition: String,
314 then_block: NodeIndex,
315 else_block: NodeIndex,
316 },
317}
318
319#[derive(Debug, Clone)]
320#[allow(dead_code)]
321pub enum OwnershipEdge {
322 Owns,
323 Borrows,
324 MutBorrows,
325}
326
327fn is_raii_type(type_name: &str) -> bool {
330 is_raii_type_with_user_defined(type_name, &std::collections::HashSet::new())
331}
332
333pub fn is_raii_type_with_user_defined(type_name: &str, user_defined_raii_types: &std::collections::HashSet<String>) -> bool {
335 let trimmed = type_name.trim();
339 if trimmed.ends_with('&') || trimmed.ends_with("& ") {
340 return false; }
342 if trimmed.contains('&') && !trimmed.contains('<') {
344 return false;
346 }
347
348 if type_name.starts_with("rusty::Box<") ||
350 type_name.starts_with("Box<") || type_name.starts_with("rusty::Rc<") ||
352 type_name.starts_with("Rc<") ||
353 type_name.starts_with("rusty::Arc<") ||
354 type_name.starts_with("Arc<") ||
355 type_name.starts_with("rusty::RefCell<") ||
356 type_name.starts_with("RefCell<") ||
357 type_name.starts_with("rusty::Cell<") ||
358 type_name.starts_with("Cell<") {
359 return true;
360 }
361
362 if type_name.starts_with("std::unique_ptr<") ||
364 type_name.starts_with("unique_ptr<") || type_name.starts_with("std::shared_ptr<") ||
366 type_name.starts_with("shared_ptr<") ||
367 type_name.starts_with("std::weak_ptr<") ||
368 type_name.starts_with("weak_ptr<") ||
369 type_name.starts_with("std::vector<") ||
370 type_name.starts_with("vector<") ||
371 type_name.starts_with("std::string") ||
372 type_name.starts_with("string") ||
373 type_name.starts_with("std::fstream") ||
374 type_name.starts_with("fstream") ||
375 type_name.starts_with("std::ifstream") ||
376 type_name.starts_with("ifstream") ||
377 type_name.starts_with("std::ofstream") ||
378 type_name.starts_with("ofstream") ||
379 type_name.starts_with("std::mutex") ||
380 type_name.starts_with("mutex") ||
381 type_name.starts_with("std::lock_guard<") ||
382 type_name.starts_with("lock_guard<") ||
383 type_name.starts_with("std::unique_lock<") ||
384 type_name.starts_with("unique_lock<") {
385 return true;
386 }
387
388 let base_type = type_name
391 .split('<').next().unwrap_or(type_name)
392 .trim_start_matches("const ")
393 .trim_end_matches('&')
394 .trim_end_matches('*')
395 .trim();
396
397 if user_defined_raii_types.contains(base_type) {
398 return true;
399 }
400
401 for raii_type in user_defined_raii_types {
403 if type_name.contains(raii_type) {
405 return true;
406 }
407 }
408
409 false
410}
411
412#[allow(dead_code)]
413pub fn build_ir(ast: CppAst) -> Result<IrProgram, String> {
414 let mut functions = Vec::new();
415 let ownership_graph = DiGraph::new();
416
417 let mut user_defined_raii_types = std::collections::HashSet::new();
419 for class in &ast.classes {
420 if class.has_destructor {
421 user_defined_raii_types.insert(class.name.clone());
422 debug_println!("RAII: Registered user-defined RAII type '{}'", class.name);
423 }
424 }
425
426 for func in ast.functions {
427 let ir_func = convert_function(&func)?;
428 functions.push(ir_func);
429 }
430
431 Ok(IrProgram {
432 functions,
433 ownership_graph,
434 user_defined_raii_types,
435 })
436}
437
438pub fn build_ir_with_safety_context(
439 ast: CppAst,
440 _safety_context: crate::parser::safety_annotations::SafetyContext
441) -> Result<IrProgram, String> {
442 let mut functions = Vec::new();
443 let ownership_graph = DiGraph::new();
444
445 let mut user_defined_raii_types = std::collections::HashSet::new();
447 for class in &ast.classes {
448 if class.has_destructor {
449 user_defined_raii_types.insert(class.name.clone());
450 debug_println!("RAII: Registered user-defined RAII type '{}'", class.name);
451 }
452 }
453
454 for func in ast.functions {
455 let ir_func = convert_function(&func)?;
456 functions.push(ir_func);
457 }
458
459 Ok(IrProgram {
460 functions,
461 ownership_graph,
462 user_defined_raii_types,
463 })
464}
465
466fn convert_function(func: &crate::parser::Function) -> Result<IrFunction, String> {
467 let mut cfg = DiGraph::new();
468 let mut variables = HashMap::new();
469 let mut current_scope_level = 0; let mut statements = Vec::new();
473
474 for stmt in &func.body {
475 if let Some(ir_stmts) = convert_statement(stmt, &mut variables, &mut current_scope_level)? {
477 statements.extend(ir_stmts);
478 }
479 }
480
481 let entry_block = BasicBlock {
482 id: 0,
483 statements,
484 terminator: None,
485 };
486
487 let _entry_node = cfg.add_node(entry_block);
488
489 for param in &func.parameters {
491 let (var_type, ownership) = if param.is_unique_ptr {
492 (VariableType::UniquePtr(param.type_name.clone()), OwnershipState::Owned)
493 } else if param.is_reference {
494 if param.is_const {
495 (VariableType::Reference(param.type_name.clone()),
496 OwnershipState::Borrowed(BorrowKind::Immutable))
497 } else {
498 (VariableType::MutableReference(param.type_name.clone()),
499 OwnershipState::Borrowed(BorrowKind::Mutable))
500 }
501 } else {
502 (VariableType::Owned(param.type_name.clone()), OwnershipState::Owned)
503 };
504
505 let declaration_index = variables.len(); variables.insert(
507 param.name.clone(),
508 VariableInfo {
509 name: param.name.clone(),
510 ty: var_type,
511 ownership,
512 lifetime: None,
513 is_parameter: true, is_static: false, scope_level: 0, has_destructor: is_raii_type(¶m.type_name),
517 declaration_index, },
519 );
520 }
521
522 Ok(IrFunction {
523 name: func.name.clone(),
524 cfg,
525 variables,
526 return_type: func.return_type.clone(),
527 source_file: func.location.file.clone(),
528 is_method: func.is_method,
529 method_qualifier: func.method_qualifier.clone(),
530 class_name: func.class_name.clone(),
531 template_parameters: func.template_parameters.clone(),
532 lifetime_params: HashMap::new(),
534 param_lifetimes: Vec::new(),
535 return_lifetime: None,
536 lifetime_constraints: Vec::new(),
537 })
538}
539
540#[allow(dead_code)]
542fn get_statement_line(stmt: &crate::parser::Statement) -> Option<u32> {
543 use crate::parser::Statement;
544 match stmt {
545 Statement::Assignment { location, .. } => Some(location.line),
546 Statement::ReferenceBinding { location, .. } => Some(location.line),
547 Statement::FunctionCall { location, .. } => Some(location.line),
548 Statement::If { location, .. } => Some(location.line),
549 Statement::ExpressionStatement { location, .. } => Some(location.line),
550 _ => None,
551 }
552}
553
554fn extract_return_source(
558 expr: &crate::parser::Expression,
559 statements: &mut Vec<IrStatement>
560) -> Option<String> {
561 use crate::parser::Expression;
562
563 match expr {
564 Expression::Variable(var) => {
565 Some(var.clone())
567 }
568
569 Expression::Dereference(inner) => {
570 debug_println!("DEBUG IR: Return dereference expression");
573 extract_return_source(inner, statements)
574 }
575
576 Expression::MemberAccess { object, field } => {
577 debug_println!("DEBUG IR: Return member access: {}.{}",
580 if let Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
581 field);
582 extract_return_source(object, statements)
583 }
584
585 Expression::AddressOf(inner) => {
586 debug_println!("DEBUG IR: Return address-of expression");
589 extract_return_source(inner, statements)
590 }
591
592 Expression::Move { inner, .. } => {
593 debug_println!("DEBUG IR: Processing Move in return statement");
595 match inner.as_ref() {
596 Expression::Variable(var) => {
597 debug_println!("DEBUG IR: Return Move(Variable): {}", var);
598 statements.push(IrStatement::Move {
600 from: var.clone(),
601 to: format!("_returned_{}", var),
602 });
603 Some(var.clone())
604 }
605 Expression::MemberAccess { object, field } => {
606 debug_println!("DEBUG IR: Return Move(MemberAccess): {}.{}",
607 if let Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
608 field);
609 if let Expression::Variable(obj_name) = object.as_ref() {
610 statements.push(IrStatement::MoveField {
612 object: obj_name.clone(),
613 field: field.clone(),
614 to: format!("_returned_{}", field),
615 });
616 Some(format!("{}.{}", obj_name, field))
617 } else {
618 None
619 }
620 }
621 _ => {
622 extract_return_source(inner, statements)
624 }
625 }
626 }
627
628 Expression::FunctionCall { name, args } => {
629 debug_println!("DEBUG IR: Return function call: {}", name);
633
634 for arg in args.iter() {
637 if let Expression::Move { .. } = arg {
638 debug_println!("DEBUG IR: Found Move inside function call argument");
639 return extract_return_source(arg, statements);
641 }
642 }
643
644 if let Some(Expression::Variable(var)) = args.first() {
645 Some(var.clone())
646 } else {
647 None }
649 }
650
651 Expression::BinaryOp { left, right, op } => {
652 debug_println!("DEBUG IR: Return binary operation: {:?}", op);
655 None
658 }
659
660 Expression::Literal(_) => {
661 None
664 }
665
666 Expression::StringLiteral(_) => {
667 None
670 }
671
672 Expression::Lambda { .. } => {
673 None
676 }
677
678 Expression::Cast(inner) => {
679 debug_println!("DEBUG IR: Return cast expression");
682 extract_return_source(inner, statements)
683 }
684 }
685}
686
687fn convert_statement(
688 stmt: &crate::parser::Statement,
689 variables: &mut HashMap<String, VariableInfo>,
690 current_scope_level: &mut usize,
691) -> Result<Option<Vec<IrStatement>>, String> {
692 use crate::parser::Statement;
693
694 debug_println!("DEBUG IR: Converting statement: {:?}", match stmt {
695 Statement::VariableDecl(_) => "VariableDecl",
696 Statement::Assignment { .. } => "Assignment",
697 Statement::ReferenceBinding { .. } => "ReferenceBinding",
698 Statement::Return(_) => "Return",
699 Statement::FunctionCall { name, .. } => {
700 debug_println!("DEBUG IR: FunctionCall name: {}", name);
701 "FunctionCall"
702 },
703 Statement::ExpressionStatement { .. } => "ExpressionStatement",
704 Statement::If { condition, .. } => {
705 debug_println!("DEBUG IR: If condition: {:?}", condition);
706 "If"
707 },
708 _ => "Other"
709 });
710
711 match stmt {
712 Statement::VariableDecl(var) => {
713 let (var_type, ownership) = if var.is_unique_ptr {
714 (VariableType::UniquePtr(var.type_name.clone()), OwnershipState::Owned)
715 } else if var.is_reference {
716 if var.is_const {
717 (VariableType::Reference(var.type_name.clone()),
718 OwnershipState::Uninitialized) } else {
720 (VariableType::MutableReference(var.type_name.clone()),
721 OwnershipState::Uninitialized)
722 }
723 } else {
724 (VariableType::Owned(var.type_name.clone()), OwnershipState::Owned)
725 };
726
727 let has_destructor_value = is_raii_type(&var.type_name);
728 let declaration_index = variables.len(); debug_println!("DEBUG IR: VariableDecl '{}': type='{}', has_destructor={}, declaration_index={}",
730 var.name, var.type_name, has_destructor_value, declaration_index);
731
732 variables.insert(
733 var.name.clone(),
734 VariableInfo {
735 name: var.name.clone(),
736 ty: var_type,
737 ownership,
738 lifetime: None,
739 is_parameter: false, is_static: var.is_static, scope_level: *current_scope_level, has_destructor: has_destructor_value,
743 declaration_index, },
745 );
746 Ok(Some(vec![IrStatement::VarDecl {
748 name: var.name.clone(),
749 type_name: var.type_name.clone(),
750 }]))
751 }
752 Statement::ReferenceBinding { name, target, is_mutable, .. } => {
753 let mut statements = Vec::new();
754
755 match target {
756 crate::parser::Expression::Variable(target_var) => {
758 let kind = if *is_mutable {
759 BorrowKind::Mutable
760 } else {
761 BorrowKind::Immutable
762 };
763
764 if let Some(var_info) = variables.get_mut(name) {
766 var_info.ownership = OwnershipState::Borrowed(kind.clone());
767 if *is_mutable {
769 if let VariableType::Owned(type_name) = &var_info.ty {
770 var_info.ty = VariableType::MutableReference(type_name.clone());
771 }
772 } else {
773 if let VariableType::Owned(type_name) = &var_info.ty {
774 var_info.ty = VariableType::Reference(type_name.clone());
775 }
776 }
777 }
778
779 statements.push(IrStatement::Borrow {
780 from: target_var.clone(),
781 to: name.clone(),
782 kind,
783 });
784 },
785
786 crate::parser::Expression::FunctionCall { name: func_name, args } => {
788 let mut arg_names = Vec::new();
789 let mut temp_counter = 0;
790
791 for arg in args {
793 match arg {
794 crate::parser::Expression::Variable(var) => {
795 arg_names.push(var.clone());
796 }
797 crate::parser::Expression::Move { inner, .. } => {
798 if let crate::parser::Expression::Variable(var) = inner.as_ref() {
799 statements.push(IrStatement::Move {
800 from: var.clone(),
801 to: format!("_moved_{}", var),
802 });
803 arg_names.push(var.clone());
804 }
805 }
806 crate::parser::Expression::Literal(lit) => {
808 let temp_name = format!("_temp_literal_{}_{}", temp_counter, lit);
809 temp_counter += 1;
810 arg_names.push(temp_name);
811 }
812 crate::parser::Expression::StringLiteral(lit) => {
814 let temp_name = format!("_temp_string_literal_{}", temp_counter);
815 temp_counter += 1;
816 arg_names.push(temp_name);
817 }
818 crate::parser::Expression::BinaryOp { .. } => {
820 let temp_name = format!("_temp_expr_{}", temp_counter);
821 temp_counter += 1;
822 arg_names.push(temp_name);
823 }
824 _ => {}
825 }
826 }
827
828 if is_dereference_operator(&func_name) {
832 if let Some(first_arg) = arg_names.first() {
833 let kind = if *is_mutable {
834 BorrowKind::Mutable
835 } else {
836 BorrowKind::Immutable
837 };
838
839 debug_println!("DEBUG IR: ReferenceBinding via operator* creates borrow from '{}'", first_arg);
840
841 statements.push(IrStatement::Borrow {
843 from: first_arg.clone(),
844 to: name.clone(),
845 kind: kind.clone(),
846 });
847
848 if let Some(var_info) = variables.get_mut(name) {
850 var_info.ownership = OwnershipState::Borrowed(kind);
851 }
852
853 } else {
855 debug_println!("DEBUG IR: operator* with no arguments");
857 }
858 } else {
859 statements.push(IrStatement::CallExpr {
861 func: func_name.clone(),
862 args: arg_names,
863 result: Some(name.clone()),
864 });
865
866 if let Some(var_info) = variables.get_mut(name) {
868 let kind = if *is_mutable {
869 BorrowKind::Mutable
870 } else {
871 BorrowKind::Immutable
872 };
873 var_info.ownership = OwnershipState::Borrowed(kind);
874 }
875 }
876 },
877
878 crate::parser::Expression::MemberAccess { object, field } => {
881 if let Some((obj_path, final_field)) = extract_member_path(target) {
883 debug_println!("DEBUG IR: ReferenceBinding to field: {}.{}", obj_path, final_field);
884
885 let kind = if *is_mutable {
886 BorrowKind::Mutable
887 } else {
888 BorrowKind::Immutable
889 };
890
891 if let Some(var_info) = variables.get_mut(name) {
893 var_info.ownership = OwnershipState::Borrowed(kind.clone());
894 if *is_mutable {
896 if let VariableType::Owned(type_name) = &var_info.ty {
897 var_info.ty = VariableType::MutableReference(type_name.clone());
898 }
899 } else {
900 if let VariableType::Owned(type_name) = &var_info.ty {
901 var_info.ty = VariableType::Reference(type_name.clone());
902 }
903 }
904 }
905
906 statements.push(IrStatement::BorrowField {
908 object: obj_path,
909 field: final_field,
910 to: name.clone(),
911 kind,
912 });
913 } else if let crate::parser::Expression::Variable(obj_name) = object.as_ref() {
914 debug_println!("DEBUG IR: ReferenceBinding to field (simple): {}.{}", obj_name, field);
916
917 let kind = if *is_mutable {
918 BorrowKind::Mutable
919 } else {
920 BorrowKind::Immutable
921 };
922
923 if let Some(var_info) = variables.get_mut(name) {
924 var_info.ownership = OwnershipState::Borrowed(kind.clone());
925 if *is_mutable {
926 if let VariableType::Owned(type_name) = &var_info.ty {
927 var_info.ty = VariableType::MutableReference(type_name.clone());
928 }
929 } else {
930 if let VariableType::Owned(type_name) = &var_info.ty {
931 var_info.ty = VariableType::Reference(type_name.clone());
932 }
933 }
934 }
935
936 statements.push(IrStatement::BorrowField {
937 object: obj_name.clone(),
938 field: field.clone(),
939 to: name.clone(),
940 kind,
941 });
942 }
943 },
944
945 _ => return Ok(None),
946 }
947
948 Ok(Some(statements))
949 }
950 Statement::Assignment { lhs, rhs, .. } => {
951 if let crate::parser::Expression::Dereference(ptr_expr) = lhs {
953 if let crate::parser::Expression::Variable(ptr_var) = ptr_expr.as_ref() {
955 let _value_var = match rhs {
957 crate::parser::Expression::Variable(v) => v.clone(),
958 _ => return Ok(None), };
960
961 return Ok(Some(vec![IrStatement::UseVariable {
963 var: ptr_var.clone(),
964 operation: "dereference_write".to_string(),
965 }]));
966 }
967 return Ok(None);
968 }
969
970 if let crate::parser::Expression::FunctionCall { name, args } = lhs {
972 debug_println!("DEBUG IR: Assignment LHS is function call: {}", name);
973 if is_dereference_operator(&name) {
975 debug_println!("DEBUG IR: Detected operator* on LHS, args: {:?}", args);
976 if let Some(crate::parser::Expression::Variable(ptr_var)) = args.first() {
979 debug_println!("DEBUG IR: Creating UseVariable for dereference_write on '{}'", ptr_var);
980 return Ok(Some(vec![IrStatement::UseVariable {
982 var: ptr_var.clone(),
983 operation: "dereference_write (via operator*)".to_string(),
984 }]));
985 }
986 }
987 debug_println!("DEBUG IR: Unsupported function call on LHS");
989 return Ok(None);
990 }
991
992 if let crate::parser::Expression::MemberAccess { object, field } = lhs {
994 debug_println!("DEBUG IR: Field write assignment: {}.{} = ...",
995 if let crate::parser::Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
996 field);
997
998 if let crate::parser::Expression::Variable(obj_name) = object.as_ref() {
999 return Ok(Some(vec![
1001 IrStatement::UseField {
1002 object: obj_name.clone(),
1003 field: field.clone(),
1004 operation: "write".to_string(),
1005 }
1006 ]));
1007 } else {
1008 return Ok(None);
1009 }
1010 }
1011
1012 let lhs_var = match lhs {
1014 crate::parser::Expression::Variable(v) => v,
1015 _ => return Ok(None), };
1017
1018 let lhs_is_raii = if let Some(lhs_info) = variables.get(lhs_var) {
1024 match &lhs_info.ty {
1025 VariableType::Owned(type_name) => is_raii_type(type_name),
1026 _ => false,
1027 }
1028 } else {
1029 false
1030 };
1031
1032 let mut prepend_drop = false;
1034
1035 if lhs_is_raii {
1036 debug_println!("DEBUG IR: Assignment to RAII type '{}', this is operator= (drops old value)", lhs_var);
1037
1038 if let crate::parser::Expression::Move { inner, .. } = rhs {
1043 match inner.as_ref() {
1044 crate::parser::Expression::Variable(from_var) => {
1045 debug_println!("DEBUG IR: RAII assignment with std::move: generating Move from '{}' to '{}'", from_var, lhs_var);
1046
1047 return Ok(Some(vec![IrStatement::Move {
1050 from: from_var.clone(),
1051 to: lhs_var.clone(),
1052 }]));
1053 }
1054 _ => {
1055 debug_println!("DEBUG IR: Move of complex expression");
1057 }
1058 }
1059 }
1060
1061 debug_println!("DEBUG IR: Will prepend Drop check for RAII assignment");
1065 prepend_drop = true;
1066 }
1067
1068 let assignment_ir = match rhs {
1069 crate::parser::Expression::Dereference(ptr_expr) => {
1070 if let crate::parser::Expression::Variable(ptr_var) = ptr_expr.as_ref() {
1072 Ok(Some(vec![IrStatement::UseVariable {
1074 var: ptr_var.clone(),
1075 operation: "dereference_read".to_string(),
1076 }]))
1077 } else {
1078 Ok(None)
1079 }
1080 }
1081 crate::parser::Expression::Variable(rhs_var) => {
1082 if let Some(rhs_info) = variables.get(rhs_var) {
1084 match &rhs_info.ty {
1085 VariableType::UniquePtr(_) => {
1086 Ok(Some(vec![IrStatement::Move {
1088 from: rhs_var.clone(),
1089 to: lhs_var.clone(),
1090 }]))
1091 }
1092 _ => {
1093 Ok(Some(vec![IrStatement::Assign {
1095 lhs: lhs_var.clone(),
1096 rhs: IrExpression::Variable(rhs_var.clone()),
1097 }]))
1098 }
1099 }
1100 } else {
1101 Ok(None)
1102 }
1103 }
1104 crate::parser::Expression::MemberAccess { .. } => {
1106 if let Some((obj_path, field_name)) = extract_member_path(rhs) {
1108 debug_println!("DEBUG IR: Processing MemberAccess read from '{}.{}'", obj_path, field_name);
1109 Ok(Some(vec![
1110 IrStatement::UseField {
1111 object: obj_path.clone(),
1112 field: field_name.clone(),
1113 operation: "read".to_string(),
1114 },
1115 IrStatement::Assign {
1116 lhs: lhs_var.clone(),
1117 rhs: IrExpression::Variable(format!("{}.{}", obj_path, field_name)),
1118 }
1119 ]))
1120 } else {
1121 debug_println!("DEBUG IR: MemberAccess could not be parsed");
1122 Ok(None)
1123 }
1124 }
1125 crate::parser::Expression::Move { inner, .. } => {
1126 debug_println!("DEBUG IR: Processing Move expression in assignment");
1127 match inner.as_ref() {
1129 crate::parser::Expression::Variable(var) => {
1130 debug_println!("DEBUG IR: Creating IrStatement::Move from '{}' to '{}'", var, lhs_var);
1131 let source_type = variables.get(var).map(|info| info.ty.clone());
1133 if let Some(var_info) = variables.get_mut(lhs_var) {
1134 if let Some(ty) = source_type {
1135 var_info.ty = ty;
1136 }
1137 }
1138 Ok(Some(vec![IrStatement::Move {
1139 from: var.clone(),
1140 to: lhs_var.clone(),
1141 }]))
1142 }
1143 crate::parser::Expression::MemberAccess { .. } => {
1145 if let Some((obj_path, field_name)) = extract_member_path(inner.as_ref()) {
1147 debug_println!("DEBUG IR: Creating MoveField for field '{}' of object '{}'", field_name, obj_path);
1148 Ok(Some(vec![IrStatement::MoveField {
1149 object: obj_path,
1150 field: field_name,
1151 to: lhs_var.clone(),
1152 }]))
1153 } else {
1154 debug_println!("DEBUG IR: MemberAccess could not be parsed");
1155 Ok(None)
1156 }
1157 }
1158 _ => {
1159 debug_println!("DEBUG IR: Move expression doesn't contain a variable or member access");
1160 Ok(None)
1161 }
1162 }
1163 }
1164 crate::parser::Expression::FunctionCall { name, args } => {
1165 let mut statements = Vec::new();
1167 let mut arg_names = Vec::new();
1168 let mut temp_counter = 0;
1169
1170 let is_method_call = name.contains("::") || name.starts_with("operator");
1173
1174 for (i, arg) in args.iter().enumerate() {
1175 match arg {
1176 crate::parser::Expression::Literal(lit) => {
1178 let temp_name = format!("_temp_literal_{}_{}", temp_counter, lit);
1179 temp_counter += 1;
1180 arg_names.push(temp_name);
1181 }
1182 crate::parser::Expression::StringLiteral(lit) => {
1184 let temp_name = format!("_temp_string_literal_{}", temp_counter);
1185 temp_counter += 1;
1186 arg_names.push(temp_name);
1187 }
1188 crate::parser::Expression::BinaryOp { .. } => {
1190 let temp_name = format!("_temp_expr_{}", temp_counter);
1191 temp_counter += 1;
1192 arg_names.push(temp_name);
1193 }
1194 crate::parser::Expression::Variable(var) => {
1195 if is_method_call && i == 0 {
1197 if is_dereference_operator(&name) {
1199 statements.push(IrStatement::UseVariable {
1200 var: var.clone(),
1201 operation: "dereference_read (via operator*)".to_string(),
1202 });
1203 } else {
1204 statements.push(IrStatement::UseVariable {
1206 var: var.clone(),
1207 operation: format!("call method '{}'", name),
1208 });
1209 }
1210 }
1211 arg_names.push(var.clone());
1212 }
1213 crate::parser::Expression::Move { inner, .. } => {
1214 debug_println!("DEBUG IR: Processing Move in assignment RHS function call");
1216 match inner.as_ref() {
1217 crate::parser::Expression::Variable(var) => {
1218 debug_println!("DEBUG IR: Move(Variable) in assignment: {}", var);
1219
1220 let temp_name = format!("_moved_{}", var);
1224 statements.push(IrStatement::Move {
1225 from: var.clone(),
1226 to: temp_name.clone(),
1227 });
1228
1229 if is_method_call && i == 0 {
1230 debug_println!("DEBUG IR: Move as method receiver - using temporary '{}' instead of '{}'", temp_name, var);
1232 arg_names.push(temp_name);
1233 } else {
1234 arg_names.push(var.clone());
1236 }
1237 }
1238 crate::parser::Expression::MemberAccess { .. } => {
1239 if let Some((obj_path, field_name)) = extract_member_path(inner.as_ref()) {
1241 debug_println!("DEBUG IR: Move(MemberAccess) in assignment: {}.{}", obj_path, field_name);
1242 statements.push(IrStatement::MoveField {
1243 object: obj_path.clone(),
1244 field: field_name.clone(),
1245 to: lhs_var.clone(), });
1247 arg_names.push(format!("{}.{}", obj_path, field_name));
1248 }
1249 }
1250 _ => {}
1251 }
1252 }
1253 crate::parser::Expression::FunctionCall { name: recv_name, args: recv_args } if is_method_call && i == 0 => {
1254 debug_println!("DEBUG IR: Receiver is FunctionCall: {}", recv_name);
1256
1257 if is_member_access_operator(&recv_name) {
1259 for recv_arg in recv_args {
1261 if let crate::parser::Expression::Variable(var) = recv_arg {
1262 debug_println!("DEBUG IR: Found pointer variable in operator->: {}", var);
1263 statements.push(IrStatement::UseVariable {
1264 var: var.clone(),
1265 operation: format!("call method '{}' via operator->", name),
1266 });
1267 }
1268 }
1269 }
1270 arg_names.push(format!("_result_of_{}", recv_name));
1271 }
1272 crate::parser::Expression::Move { inner, .. } => {
1273 if let crate::parser::Expression::Variable(var) = inner.as_ref() {
1274 statements.push(IrStatement::Move {
1276 from: var.clone(),
1277 to: format!("_temp_move_{}", var),
1278 });
1279 arg_names.push(var.clone());
1280 }
1281 }
1282 crate::parser::Expression::MemberAccess { .. } => {
1284 if let Some((obj_path, field_name)) = extract_member_path(arg) {
1286 debug_println!("DEBUG IR: MemberAccess as function argument in assignment: {}.{}", obj_path, field_name);
1287 statements.push(IrStatement::UseField {
1289 object: obj_path.clone(),
1290 field: field_name.clone(),
1291 operation: "use in function call".to_string(),
1292 });
1293 arg_names.push(format!("{}.{}", obj_path, field_name));
1294 }
1295 }
1296 _ => {}
1297 }
1298 }
1299
1300 statements.push(IrStatement::CallExpr {
1301 func: name.clone(),
1302 args: arg_names,
1303 result: Some(lhs_var.clone()),
1304 });
1305
1306 Ok(Some(statements))
1307 }
1308 crate::parser::Expression::Literal(value) => {
1311 debug_println!("DEBUG IR: Literal assignment: {} = {}", lhs_var, value);
1312 Ok(Some(vec![IrStatement::Assign {
1313 lhs: lhs_var.clone(),
1314 rhs: IrExpression::Literal(value.clone()),
1315 }]))
1316 }
1317 crate::parser::Expression::StringLiteral(value) => {
1320 debug_println!("DEBUG IR: String literal assignment: {} = \"{}\"", lhs_var, value);
1321 Ok(Some(vec![IrStatement::Assign {
1322 lhs: lhs_var.clone(),
1323 rhs: IrExpression::Literal(value.clone()), }]))
1325 }
1326 crate::parser::Expression::Lambda { captures } => {
1328 debug_println!("DEBUG IR: Lambda assignment: {} = [captures]", lhs_var);
1329 let capture_infos: Vec<LambdaCaptureInfo> = captures.iter().map(|c| {
1330 use crate::parser::ast_visitor::LambdaCaptureKind;
1331 match c {
1332 LambdaCaptureKind::DefaultRef => LambdaCaptureInfo {
1333 name: "<default>".to_string(),
1334 is_ref: true,
1335 is_this: false,
1336 },
1337 LambdaCaptureKind::DefaultCopy => LambdaCaptureInfo {
1338 name: "<default>".to_string(),
1339 is_ref: false,
1340 is_this: false,
1341 },
1342 LambdaCaptureKind::ByRef(name) => LambdaCaptureInfo {
1343 name: name.clone(),
1344 is_ref: true,
1345 is_this: false,
1346 },
1347 LambdaCaptureKind::ByCopy(name) => LambdaCaptureInfo {
1348 name: name.clone(),
1349 is_ref: false,
1350 is_this: false,
1351 },
1352 LambdaCaptureKind::Init { name, is_move } => LambdaCaptureInfo {
1353 name: name.clone(),
1354 is_ref: false, is_this: false,
1356 },
1357 LambdaCaptureKind::This => LambdaCaptureInfo {
1358 name: "this".to_string(),
1359 is_ref: true, is_this: true,
1361 },
1362 LambdaCaptureKind::ThisCopy => LambdaCaptureInfo {
1363 name: "this".to_string(),
1364 is_ref: false, is_this: true,
1366 },
1367 }
1368 }).collect();
1369
1370 Ok(Some(vec![IrStatement::LambdaCapture {
1371 captures: capture_infos,
1372 }]))
1373 }
1374 _ => Ok(None)
1375 };
1376
1377 if prepend_drop {
1379 debug_println!("DEBUG IR: Prepending Drop check to assignment IR");
1380 match assignment_ir {
1381 Ok(Some(mut stmts)) => {
1382 stmts.insert(0, IrStatement::Drop(lhs_var.clone()));
1384 Ok(Some(stmts))
1385 }
1386 Ok(None) => {
1387 Ok(Some(vec![IrStatement::Drop(lhs_var.clone())]))
1389 }
1390 Err(e) => Err(e)
1391 }
1392 } else {
1393 assignment_ir
1394 }
1395 }
1396 Statement::FunctionCall { name, args, .. } => {
1397 debug_println!("DEBUG IR: Processing FunctionCall statement: {} with {} args", name, args.len());
1398 let mut statements = Vec::new();
1400 let mut arg_names = Vec::new();
1401 let mut temp_counter = 0;
1402
1403 let is_method_call = name.contains("::") || name.starts_with("operator");
1406
1407 if is_assignment_operator(&name) {
1411 debug_println!("DEBUG IR: Detected operator= call");
1412 if args.len() == 2 {
1413 if let crate::parser::Expression::Variable(lhs) = &args[0] {
1415 let lhs_is_raii = if let Some(lhs_info) = variables.get(lhs) {
1417 match &lhs_info.ty {
1418 VariableType::Owned(type_name) => is_raii_type(type_name),
1419 _ => false,
1420 }
1421 } else {
1422 false
1423 };
1424
1425 if let crate::parser::Expression::Move { inner: rhs_inner, .. } = &args[1] {
1427 debug_println!("DEBUG IR: operator= with Move: {} = Move(...)", lhs);
1428 if let crate::parser::Expression::Variable(rhs) = rhs_inner.as_ref() {
1429 debug_println!("DEBUG IR: Creating Move from '{}' to '{}' for operator=", rhs, lhs);
1430 return Ok(Some(vec![IrStatement::Move {
1431 from: rhs.clone(),
1432 to: lhs.clone(),
1433 }]));
1434 }
1435 }
1436
1437 if lhs_is_raii {
1439 debug_println!("DEBUG IR: operator= on RAII type '{}' - generating Drop check", lhs);
1440 statements.push(IrStatement::Drop(lhs.clone()));
1442 }
1443 }
1444 }
1445 }
1446
1447 for (i, arg) in args.iter().enumerate() {
1449 match arg {
1450 crate::parser::Expression::Variable(var) => {
1451 if is_method_call && i == 0 {
1453 let operation = if is_dereference_operator(&name) {
1455 "dereference (via operator*)".to_string()
1456 } else {
1457 format!("call method '{}'", name)
1458 };
1459
1460 statements.push(IrStatement::UseVariable {
1461 var: var.clone(),
1462 operation,
1463 });
1464 }
1465 arg_names.push(var.clone());
1466 }
1467 crate::parser::Expression::Move { inner, .. } => {
1468 match inner.as_ref() {
1470 crate::parser::Expression::Variable(var) => {
1471 debug_println!("DEBUG IR: Move(Variable) as direct argument: {}", var);
1472
1473 let temp_name = format!("_moved_{}", var);
1477 statements.push(IrStatement::Move {
1478 from: var.clone(),
1479 to: temp_name.clone(),
1480 });
1481
1482 if is_method_call && i == 0 {
1483 debug_println!("DEBUG IR: Move as method receiver - using temporary '{}' instead of '{}'", temp_name, var);
1485 arg_names.push(temp_name);
1486 } else {
1487 arg_names.push(var.clone());
1489 }
1490 }
1491 crate::parser::Expression::MemberAccess { .. } => {
1492 if let Some((obj_path, field_name)) = extract_member_path(inner.as_ref()) {
1494 debug_println!("DEBUG IR: Move(MemberAccess) as direct argument: {}.{}", obj_path, field_name);
1495 statements.push(IrStatement::MoveField {
1496 object: obj_path.clone(),
1497 field: field_name.clone(),
1498 to: format!("_moved_{}", field_name),
1499 });
1500 arg_names.push(format!("{}.{}", obj_path, field_name));
1501 }
1502 }
1503 _ => {}
1504 }
1505 }
1506 crate::parser::Expression::FunctionCall { name: inner_name, args: inner_args } => {
1507 debug_println!("DEBUG IR: Nested FunctionCall in argument: {}", inner_name);
1508
1509 if is_method_call && i == 0 {
1511 if is_member_access_operator(&inner_name) {
1513 for inner_arg in inner_args {
1515 if let crate::parser::Expression::Variable(var) = inner_arg {
1516 debug_println!("DEBUG IR: Found pointer variable in operator->: {}", var);
1517 statements.push(IrStatement::UseVariable {
1518 var: var.clone(),
1519 operation: format!("call method '{}' via operator->", name),
1520 });
1521 }
1522 }
1523 }
1524 }
1525
1526 for inner_arg in inner_args {
1528 if let crate::parser::Expression::Move { inner: move_inner, .. } = inner_arg {
1529 match move_inner.as_ref() {
1530 crate::parser::Expression::Variable(var) => {
1531 debug_println!("DEBUG IR: Found Move(Variable) in nested call: {}", var);
1532 statements.push(IrStatement::Move {
1533 from: var.clone(),
1534 to: format!("_moved_{}", var),
1535 });
1536 }
1537 crate::parser::Expression::MemberAccess { .. } => {
1538 if let Some((obj_path, field_name)) = extract_member_path(move_inner.as_ref()) {
1540 debug_println!("DEBUG IR: Found Move(MemberAccess) in nested call: {}.{}", obj_path, field_name);
1541 statements.push(IrStatement::MoveField {
1542 object: obj_path,
1543 field: field_name.clone(),
1544 to: format!("_moved_{}", field_name),
1545 });
1546 }
1547 }
1548 _ => {}
1549 }
1550 }
1551 }
1552 arg_names.push(format!("_result_of_{}", inner_name));
1554 }
1555 crate::parser::Expression::MemberAccess { .. } => {
1557 if let Some((obj_path, field_name)) = extract_member_path(arg) {
1559 debug_println!("DEBUG IR: MemberAccess as function argument: {}.{}", obj_path, field_name);
1560 statements.push(IrStatement::UseField {
1562 object: obj_path.clone(),
1563 field: field_name.clone(),
1564 operation: "use in function call".to_string(),
1565 });
1566 arg_names.push(format!("{}.{}", obj_path, field_name));
1567 }
1568 }
1569 crate::parser::Expression::Literal(lit) => {
1571 let temp_name = format!("_temp_literal_{}_{}", temp_counter, lit);
1572 temp_counter += 1;
1573 arg_names.push(temp_name);
1574 }
1575 crate::parser::Expression::StringLiteral(lit) => {
1577 let temp_name = format!("_temp_string_literal_{}", temp_counter);
1578 temp_counter += 1;
1579 arg_names.push(temp_name);
1580 }
1581 crate::parser::Expression::BinaryOp { .. } => {
1583 let temp_name = format!("_temp_expr_{}", temp_counter);
1584 temp_counter += 1;
1585 arg_names.push(temp_name);
1586 }
1587 _ => {}
1588 }
1589 }
1590
1591 statements.push(IrStatement::CallExpr {
1592 func: name.clone(),
1593 args: arg_names,
1594 result: None,
1595 });
1596
1597 Ok(Some(statements))
1598 }
1599 Statement::Return(expr) => {
1600 let mut statements = Vec::new();
1601
1602 let value = expr.as_ref().and_then(|e| {
1603 extract_return_source(e, &mut statements)
1604 });
1605
1606 statements.push(IrStatement::Return { value });
1607 Ok(Some(statements))
1608 }
1609 Statement::EnterScope => {
1610 *current_scope_level += 1;
1611 debug_println!("DEBUG IR: EnterScope - now at level {}", current_scope_level);
1612 Ok(Some(vec![IrStatement::EnterScope]))
1613 }
1614 Statement::ExitScope => {
1615 debug_println!("DEBUG IR: ExitScope - leaving level {}", current_scope_level);
1616 debug_println!("DEBUG IR: Total variables: {}", variables.len());
1617 for (name, info) in variables.iter() {
1618 debug_println!("DEBUG IR: Variable '{}': scope_level={}, has_destructor={}, is_static={}",
1619 name, info.scope_level, info.has_destructor, info.is_static);
1620 }
1621
1622 let mut vars_to_drop: Vec<(String, usize, bool)> = variables
1625 .iter()
1626 .filter(|(_, info)| {
1627 info.scope_level == *current_scope_level &&
1628 !info.is_static })
1630 .map(|(name, info)| (name.clone(), info.declaration_index, info.has_destructor))
1631 .collect();
1632
1633 vars_to_drop.sort_by(|a, b| b.1.cmp(&a.1));
1636
1637 debug_println!("DROP ORDER: Processing {} variables at scope end in reverse declaration order", vars_to_drop.len());
1638 for (name, decl_idx, has_dest) in &vars_to_drop {
1639 debug_println!("DROP ORDER: '{}' (declaration_index={}, has_destructor={})", name, decl_idx, has_dest);
1640 }
1641
1642 let mut statements = Vec::new();
1645 for (var, _, has_dest) in vars_to_drop {
1646 debug_println!("DEBUG IR: Inserting ImplicitDrop for '{}' at scope level {} (has_destructor={})",
1647 var, current_scope_level, has_dest);
1648 statements.push(IrStatement::ImplicitDrop {
1649 var,
1650 scope_level: *current_scope_level,
1651 has_destructor: has_dest,
1652 });
1653 }
1654
1655 statements.push(IrStatement::ExitScope);
1657
1658 *current_scope_level = current_scope_level.saturating_sub(1);
1659 Ok(Some(statements))
1660 }
1661 Statement::EnterLoop => {
1662 Ok(Some(vec![IrStatement::EnterLoop]))
1663 }
1664 Statement::ExitLoop => {
1665 Ok(Some(vec![IrStatement::ExitLoop]))
1666 }
1667 Statement::EnterUnsafe => {
1668 Ok(Some(vec![IrStatement::EnterUnsafe]))
1669 }
1670 Statement::ExitUnsafe => {
1671 Ok(Some(vec![IrStatement::ExitUnsafe]))
1672 }
1673 Statement::If { condition, then_branch, else_branch, .. } => {
1674 let mut condition_ir = Vec::new();
1677
1678 match condition {
1680 crate::parser::Expression::FunctionCall { name, args } => {
1681 let is_method_call = name.contains("::") || name.starts_with("operator");
1683
1684 for (i, arg) in args.iter().enumerate() {
1685 if let crate::parser::Expression::Variable(var) = arg {
1686 if is_method_call && i == 0 {
1688 debug_println!("DEBUG IR: Creating UseVariable for '{}' in condition (method: {})", var, name);
1689 condition_ir.push(IrStatement::UseVariable {
1690 var: var.clone(),
1691 operation: format!("call method '{}' in condition", name),
1692 });
1693 }
1694 }
1695 }
1696 }
1697 crate::parser::Expression::Variable(var) => {
1698 condition_ir.push(IrStatement::UseVariable {
1700 var: var.clone(),
1701 operation: "use in condition".to_string(),
1702 });
1703 }
1704 _ => {
1705 }
1707 }
1708
1709 let mut then_ir = Vec::new();
1711 for stmt in then_branch {
1712 if let Some(ir_stmts) = convert_statement(stmt, variables, current_scope_level)? {
1713 then_ir.extend(ir_stmts);
1714 }
1715 }
1716
1717 let else_ir = if let Some(else_stmts) = else_branch {
1719 let mut else_ir = Vec::new();
1720 for stmt in else_stmts {
1721 if let Some(ir_stmts) = convert_statement(stmt, variables, current_scope_level)? {
1722 else_ir.extend(ir_stmts);
1723 }
1724 }
1725 Some(else_ir)
1726 } else {
1727 None
1728 };
1729
1730 let mut result = condition_ir;
1732 result.push(IrStatement::If {
1733 then_branch: then_ir,
1734 else_branch: else_ir,
1735 });
1736 Ok(Some(result))
1737 }
1738 Statement::ExpressionStatement { expr, .. } => {
1739 match expr {
1741 crate::parser::Expression::Dereference(inner) => {
1742 if let crate::parser::Expression::Variable(var) = inner.as_ref() {
1744 Ok(Some(vec![IrStatement::UseVariable {
1745 var: var.clone(),
1746 operation: "dereference".to_string(),
1747 }]))
1748 } else {
1749 Ok(None)
1750 }
1751 }
1752 crate::parser::Expression::AddressOf(inner) => {
1753 Ok(None)
1755 }
1756 crate::parser::Expression::BinaryOp { left, op, right } if op == "=" => {
1758 debug_println!("DEBUG IR: ExpressionStatement assignment: op={}", op);
1759
1760 if let crate::parser::Expression::MemberAccess { object, field } = left.as_ref() {
1762 debug_println!("DEBUG IR: ExpressionStatement field write: {}.{} = ...",
1763 if let crate::parser::Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
1764 field);
1765
1766 if let crate::parser::Expression::Variable(obj_name) = object.as_ref() {
1767 return Ok(Some(vec![
1769 IrStatement::UseField {
1770 object: obj_name.clone(),
1771 field: field.clone(),
1772 operation: "write".to_string(),
1773 }
1774 ]));
1775 }
1776 }
1777
1778 Ok(None)
1780 }
1781 _ => Ok(None),
1782 }
1783 }
1784 Statement::PackExpansion { pack_name, operation, .. } => {
1785 debug_println!("DEBUG IR: PackExpansion: pack='{}', operation='{}'", pack_name, operation);
1787 Ok(Some(vec![IrStatement::PackExpansion {
1788 pack_name: pack_name.clone(),
1789 operation: operation.clone(),
1790 }]))
1791 }
1792 _ => Ok(None),
1793 }
1794}
1795
1796#[cfg(test)]
1797mod tests {
1798 use super::*;
1799 use crate::parser::{Function, Variable, SourceLocation};
1800
1801 fn create_test_function(name: &str) -> Function {
1802 Function {
1803 name: name.to_string(),
1804 parameters: vec![],
1805 return_type: "void".to_string(),
1806 body: vec![],
1807 location: SourceLocation {
1808 file: "test.cpp".to_string(),
1809 line: 1,
1810 column: 1,
1811 },
1812 is_method: false,
1813 method_qualifier: None,
1814 class_name: None,
1815 template_parameters: vec![],
1816 safety_annotation: None,
1817 has_explicit_safety_annotation: false,
1818 }
1819 }
1820
1821 fn create_test_variable(name: &str, type_name: &str, is_unique_ptr: bool) -> Variable {
1822 Variable {
1823 name: name.to_string(),
1824 type_name: type_name.to_string(),
1825 is_reference: false,
1826 is_pointer: false,
1827 is_const: false,
1828 is_unique_ptr,
1829 is_shared_ptr: false,
1830 is_static: false,
1831 is_mutable: false,
1832 location: SourceLocation {
1833 file: "test.cpp".to_string(),
1834 line: 1,
1835 column: 1,
1836 },
1837 is_pack: false,
1838 pack_element_type: None,
1839 }
1840 }
1841
1842 #[test]
1843 fn test_build_empty_ir() {
1844 let ast = crate::parser::CppAst::new();
1845 let result = build_ir(ast);
1846
1847 assert!(result.is_ok());
1848 let ir = result.unwrap();
1849 assert_eq!(ir.functions.len(), 0);
1850 }
1851
1852 #[test]
1853 fn test_build_ir_with_function() {
1854 let mut ast = crate::parser::CppAst::new();
1855 ast.functions.push(create_test_function("test_func"));
1856
1857 let result = build_ir(ast);
1858 assert!(result.is_ok());
1859
1860 let ir = result.unwrap();
1861 assert_eq!(ir.functions.len(), 1);
1862 assert_eq!(ir.functions[0].name, "test_func");
1863 }
1864
1865 #[test]
1866 fn test_variable_type_classification() {
1867 let unique_var = create_test_variable("ptr", "std::unique_ptr<int>", true);
1868 let mut ast = crate::parser::CppAst::new();
1869 let mut func = create_test_function("test");
1870 func.parameters.push(unique_var);
1871 ast.functions.push(func);
1872
1873 let result = build_ir(ast);
1874 assert!(result.is_ok());
1875
1876 let ir = result.unwrap();
1877 let var_info = ir.functions[0].variables.get("ptr").unwrap();
1878 assert!(matches!(var_info.ty, VariableType::UniquePtr(_)));
1879 }
1880
1881 #[test]
1882 fn test_ownership_state_initialization() {
1883 let var = create_test_variable("x", "int", false);
1884 let mut ast = crate::parser::CppAst::new();
1885 let mut func = create_test_function("test");
1886 func.parameters.push(var);
1887 ast.functions.push(func);
1888
1889 let result = build_ir(ast);
1890 assert!(result.is_ok());
1891
1892 let ir = result.unwrap();
1893 let var_info = ir.functions[0].variables.get("x").unwrap();
1894 assert_eq!(var_info.ownership, OwnershipState::Owned);
1895 }
1896
1897 #[test]
1898 fn test_lifetime_creation() {
1899 let lifetime = Lifetime {
1900 name: "a".to_string(),
1901 scope_start: 0,
1902 scope_end: 10,
1903 };
1904
1905 assert_eq!(lifetime.name, "a");
1906 assert_eq!(lifetime.scope_start, 0);
1907 assert_eq!(lifetime.scope_end, 10);
1908 }
1909}
1910
1911fn convert_param_lifetime(annotation: &crate::parser::annotations::LifetimeAnnotation) -> Option<ParameterLifetime> {
1915 use crate::parser::annotations::LifetimeAnnotation;
1916
1917 match annotation {
1918 LifetimeAnnotation::Ref(lifetime_name) => {
1919 Some(ParameterLifetime {
1920 lifetime_name: lifetime_name.clone(),
1921 is_mutable: false,
1922 is_owned: false,
1923 })
1924 }
1925 LifetimeAnnotation::MutRef(lifetime_name) => {
1926 Some(ParameterLifetime {
1927 lifetime_name: lifetime_name.clone(),
1928 is_mutable: true,
1929 is_owned: false,
1930 })
1931 }
1932 LifetimeAnnotation::Owned => {
1933 Some(ParameterLifetime {
1934 lifetime_name: String::new(), is_mutable: false,
1936 is_owned: true,
1937 })
1938 }
1939 LifetimeAnnotation::Lifetime(_) => {
1940 None
1942 }
1943 }
1944}
1945
1946fn convert_return_lifetime(annotation: &crate::parser::annotations::LifetimeAnnotation) -> Option<ReturnLifetime> {
1948 use crate::parser::annotations::LifetimeAnnotation;
1949
1950 match annotation {
1951 LifetimeAnnotation::Ref(lifetime_name) => {
1952 Some(ReturnLifetime {
1953 lifetime_name: lifetime_name.clone(),
1954 is_mutable: false,
1955 is_owned: false,
1956 })
1957 }
1958 LifetimeAnnotation::MutRef(lifetime_name) => {
1959 Some(ReturnLifetime {
1960 lifetime_name: lifetime_name.clone(),
1961 is_mutable: true,
1962 is_owned: false,
1963 })
1964 }
1965 LifetimeAnnotation::Owned => {
1966 Some(ReturnLifetime {
1967 lifetime_name: String::new(), is_mutable: false,
1969 is_owned: true,
1970 })
1971 }
1972 LifetimeAnnotation::Lifetime(_) => {
1973 None
1975 }
1976 }
1977}
1978
1979pub fn populate_lifetime_info(
1981 ir_func: &mut IrFunction,
1982 signature: &crate::parser::annotations::FunctionSignature
1983) {
1984 debug_println!("DEBUG IR LIFETIME: Populating lifetime info for function '{}'", ir_func.name);
1985
1986 let mut lifetime_names = std::collections::HashSet::new();
1988
1989 for param_lifetime_opt in &signature.param_lifetimes {
1991 if let Some(param_lifetime) = param_lifetime_opt {
1992 if let Some(name) = extract_lifetime_name_from_annotation(param_lifetime) {
1993 lifetime_names.insert(name);
1994 }
1995 }
1996 }
1997
1998 if let Some(return_lifetime) = &signature.return_lifetime {
2000 if let Some(name) = extract_lifetime_name_from_annotation(return_lifetime) {
2001 lifetime_names.insert(name);
2002 }
2003 }
2004
2005 for bound in &signature.lifetime_bounds {
2007 lifetime_names.insert(bound.longer.clone());
2008 lifetime_names.insert(bound.shorter.clone());
2009 }
2010
2011 for name in lifetime_names {
2013 debug_println!("DEBUG IR LIFETIME: Lifetime parameter: '{}'", name);
2014 ir_func.lifetime_params.insert(
2015 name.clone(),
2016 LifetimeParam { name }
2017 );
2018 }
2019
2020 for param_lifetime_opt in &signature.param_lifetimes {
2022 let converted = param_lifetime_opt.as_ref()
2023 .and_then(|lt| convert_param_lifetime(lt));
2024
2025 if let Some(ref param_lt) = converted {
2026 debug_println!("DEBUG IR LIFETIME: Parameter lifetime: '{}' (mutable={}, owned={})",
2027 param_lt.lifetime_name, param_lt.is_mutable, param_lt.is_owned);
2028 }
2029
2030 ir_func.param_lifetimes.push(converted);
2031 }
2032
2033 ir_func.return_lifetime = signature.return_lifetime.as_ref()
2035 .and_then(|lt| convert_return_lifetime(lt));
2036
2037 if let Some(ref ret_lt) = ir_func.return_lifetime {
2038 debug_println!("DEBUG IR LIFETIME: Return lifetime: '{}' (mutable={}, owned={})",
2039 ret_lt.lifetime_name, ret_lt.is_mutable, ret_lt.is_owned);
2040 }
2041
2042 for bound in &signature.lifetime_bounds {
2044 debug_println!("DEBUG IR LIFETIME: Lifetime constraint: '{}': '{}'", bound.longer, bound.shorter);
2045 ir_func.lifetime_constraints.push(LifetimeConstraint {
2046 longer: bound.longer.clone(),
2047 shorter: bound.shorter.clone(),
2048 });
2049 }
2050
2051 debug_println!("DEBUG IR LIFETIME: Populated {} lifetime params, {} param lifetimes, {} constraints",
2052 ir_func.lifetime_params.len(), ir_func.param_lifetimes.len(), ir_func.lifetime_constraints.len());
2053}
2054
2055fn extract_lifetime_name_from_annotation(annotation: &crate::parser::annotations::LifetimeAnnotation) -> Option<String> {
2057 use crate::parser::annotations::LifetimeAnnotation;
2058
2059 match annotation {
2060 LifetimeAnnotation::Ref(name) => Some(name.clone()),
2061 LifetimeAnnotation::MutRef(name) => Some(name.clone()),
2062 LifetimeAnnotation::Lifetime(name) => Some(name.trim_start_matches('\'').to_string()),
2063 LifetimeAnnotation::Owned => None,
2064 }
2065}