1use super::{escape_rust_keyword, CodeGenerator, TypeContext};
8use decy_hir::{BinaryOperator, HirExpression, HirStatement, HirType};
9
10impl CodeGenerator {
11 pub fn generate_statement(&self, stmt: &HirStatement) -> String {
13 self.generate_statement_for_function(stmt, None)
14 }
15
16 pub(crate) fn generate_statement_for_function(
21 &self,
22 stmt: &HirStatement,
23 function_name: Option<&str>,
24 ) -> String {
25 self.generate_statement_with_context(stmt, function_name, &mut TypeContext::new(), None)
26 }
27
28 pub(crate) fn generate_statement_with_context(
30 &self,
31 stmt: &HirStatement,
32 function_name: Option<&str>,
33 ctx: &mut TypeContext,
34 return_type: Option<&HirType>,
35 ) -> String {
36 match stmt {
37 HirStatement::VariableDeclaration { name, var_type, initializer } => {
38 self.generate_declaration_statement(name, var_type, initializer.as_ref(), ctx)
39 }
40 HirStatement::Return(expr_opt) => {
41 self.generate_return_statement(expr_opt.as_ref(), function_name, ctx, return_type)
42 }
43 HirStatement::If { condition, then_block, else_block } => {
44 self.generate_if_statement(
45 condition,
46 then_block,
47 else_block.as_deref(),
48 function_name,
49 ctx,
50 return_type,
51 )
52 }
53 HirStatement::While { condition, body } => {
54 self.generate_while_statement(
55 condition,
56 body,
57 function_name,
58 ctx,
59 return_type,
60 )
61 }
62 HirStatement::Break => "break;".to_string(),
63 HirStatement::Continue => "continue;".to_string(),
64 HirStatement::Assignment { target, value } => {
65 self.generate_assignment_statement(target, value, ctx)
66 }
67 HirStatement::For { init, condition, increment, body } => {
68 self.generate_for_statement(
69 init,
70 condition.as_ref(),
71 increment,
72 body,
73 function_name,
74 ctx,
75 return_type,
76 )
77 }
78 HirStatement::Switch { condition, cases, default_case } => {
79 self.generate_switch_statement(
80 condition,
81 cases,
82 default_case.as_deref(),
83 function_name,
84 ctx,
85 return_type,
86 )
87 }
88 HirStatement::DerefAssignment { target, value } => {
89 self.generate_deref_assignment_statement(target, value, ctx)
90 }
91 HirStatement::ArrayIndexAssignment { array, index, value } => {
92 self.generate_array_index_assignment_statement(array, index, value, ctx)
93 }
94 HirStatement::FieldAssignment { object, field, value } => {
95 self.generate_field_assignment_statement(object, field, value, ctx)
96 }
97 HirStatement::Free { pointer } => {
98 let pointer_name = match pointer {
99 HirExpression::Variable(name) => name.clone(),
100 _ => self.generate_expression_with_context(pointer, ctx),
101 };
102 format!("// Memory for '{}' deallocated automatically by RAII", pointer_name)
103 }
104 HirStatement::Expression(expr) => {
105 format!("{};", self.generate_expression_with_context(expr, ctx))
106 }
107 HirStatement::InlineAsm { text, translatable } => {
108 let mut result = String::new();
109 result.push_str("// DECY: manual review required - inline assembly\n");
110 if *translatable {
111 result.push_str(
112 "// DECY: this assembly may be translatable to Rust intrinsics\n",
113 );
114 }
115 result.push_str(&format!("// Original asm: {}", text.replace('\n', "\n// ")));
116 result
117 }
118 }
119 }
120
121 fn resolve_declaration_type(
123 name: &str,
124 var_type: &HirType,
125 initializer: Option<&HirExpression>,
126 is_malloc_init: bool,
127 ctx: &mut TypeContext,
128 ) -> (HirType, String) {
129 if is_malloc_init {
130 if let HirType::Pointer(inner) = var_type {
131 let is_struct_alloc = matches!(&**inner, HirType::Struct(_));
132 let is_array_pattern = if let Some(init_expr) = initializer {
133 Self::is_malloc_array_pattern(init_expr)
134 } else {
135 false
136 };
137
138 if is_struct_alloc && !is_array_pattern {
139 let box_type = HirType::Box(inner.clone());
140 ctx.add_variable(name.to_string(), box_type.clone());
141 return (box_type.clone(), Self::map_type(&box_type));
142 } else {
143 let vec_type = HirType::Vec(inner.clone());
144 ctx.add_variable(name.to_string(), vec_type.clone());
145 return (vec_type.clone(), Self::map_type(&vec_type));
146 }
147 } else {
148 ctx.add_variable(name.to_string(), var_type.clone());
149 return (var_type.clone(), Self::map_type(var_type));
150 }
151 }
152
153 let is_string_literal_init =
154 matches!(initializer, Some(HirExpression::StringLiteral(_)));
155 let is_char_pointer = matches!(
156 var_type,
157 HirType::Pointer(inner) if matches!(&**inner, HirType::Char)
158 );
159 let is_char_pointer_array = matches!(
160 var_type,
161 HirType::Array { element_type, .. }
162 if matches!(&**element_type, HirType::Pointer(inner) if matches!(&**inner, HirType::Char))
163 );
164 let is_array_of_string_literals = matches!(
165 initializer,
166 Some(HirExpression::CompoundLiteral { initializers, .. })
167 if initializers.iter().all(|e| matches!(e, HirExpression::StringLiteral(_)))
168 );
169
170 if is_char_pointer && is_string_literal_init {
171 ctx.add_variable(name.to_string(), HirType::StringReference);
172 (HirType::StringReference, "&str".to_string())
173 } else if is_char_pointer_array && is_array_of_string_literals {
174 let size =
175 if let HirType::Array { size, .. } = var_type { *size } else { None };
176 let array_type = HirType::Array {
177 element_type: Box::new(HirType::StringReference),
178 size,
179 };
180 ctx.add_variable(name.to_string(), array_type.clone());
181 let type_str = if let Some(n) = size {
182 format!("[&str; {}]", n)
183 } else {
184 "[&str]".to_string()
185 };
186 (array_type, type_str)
187 } else {
188 ctx.add_variable(name.to_string(), var_type.clone());
189 (var_type.clone(), Self::map_type(var_type))
190 }
191 }
192
193 fn generate_malloc_expr_init(
194 &self,
195 code: &mut String,
196 var_type: &HirType,
197 init_expr: &HirExpression,
198 ctx: &TypeContext,
199 ) {
200 match var_type {
201 HirType::Box(inner) => {
202 code.push_str(&format!(
203 " = Box::new({});",
204 Self::default_value_for_type(inner)
205 ));
206 }
207 HirType::Vec(_) => {
208 if let HirExpression::Malloc { size } = init_expr {
209 if let HirExpression::BinaryOp {
210 op: decy_hir::BinaryOperator::Multiply,
211 left,
212 ..
213 } = size.as_ref()
214 {
215 let capacity_code =
216 self.generate_expression_with_context(left, ctx);
217 code.push_str(&format!(
218 " = Vec::with_capacity({});",
219 capacity_code
220 ));
221 } else {
222 code.push_str(" = Vec::new();");
223 }
224 } else {
225 code.push_str(" = Vec::new();");
226 }
227 }
228 _ => {
229 code.push_str(" = Box::new(0i32);");
230 }
231 }
232 }
233
234 fn generate_malloc_funcall_init(
235 &self,
236 code: &mut String,
237 var_type: &HirType,
238 actual_type: &HirType,
239 init_expr: &HirExpression,
240 ctx: &mut TypeContext,
241 ) {
242 match actual_type {
243 HirType::Box(inner) => {
244 let use_default =
245 if let HirType::Struct(struct_name) = inner.as_ref() {
246 ctx.struct_has_default(struct_name)
247 } else {
248 false
249 };
250
251 if use_default {
252 code.push_str(" = Box::default();");
253 } else {
254 let inner_type = Self::map_type(inner);
255 code.push_str(&format!(
256 " = Box::new(/* SAFETY: {} is valid when zero-initialized */ unsafe {{ std::mem::zeroed::<{}>() }});",
257 inner_type, inner_type
258 ));
259 }
260 }
261 HirType::Vec(_) => {
262 code.push_str(&format!(
263 " = {};",
264 self.generate_expression_with_target_type(
265 init_expr,
266 ctx,
267 Some(actual_type)
268 )
269 ));
270 }
271 _ => {
272 code.push_str(&format!(
273 " = {};",
274 self.generate_expression_with_target_type(
275 init_expr,
276 ctx,
277 Some(var_type)
278 )
279 ));
280 }
281 }
282 }
283
284 fn generate_regular_init(
285 &self,
286 code: &mut String,
287 var_type: &HirType,
288 actual_type: &HirType,
289 init_expr: &HirExpression,
290 ctx: &mut TypeContext,
291 ) {
292 let is_char_array = matches!(
293 var_type,
294 HirType::Array { element_type, .. }
295 if matches!(&**element_type, HirType::Char)
296 );
297
298 if is_char_array {
299 if let HirExpression::StringLiteral(s) = init_expr {
300 let escaped: String = s
301 .chars()
302 .map(|c| match c {
303 '"' => "\\\"".to_string(),
304 c => c.to_string(),
305 })
306 .collect();
307 code.push_str(&format!(" = *b\"{}\\0\";", escaped));
308 } else {
309 code.push_str(&format!(
310 " = {};",
311 self.generate_expression_with_target_type(
312 init_expr,
313 ctx,
314 Some(var_type)
315 )
316 ));
317 }
318 } else {
319 code.push_str(&format!(
320 " = {};",
321 self.generate_expression_with_target_type(
322 init_expr,
323 ctx,
324 Some(actual_type)
325 )
326 ));
327 }
328 }
329
330 fn generate_declaration_statement(
331 &self,
332 name: &str,
333 var_type: &HirType,
334 initializer: Option<&HirExpression>,
335 ctx: &mut TypeContext,
336 ) -> String {
337 let escaped_name = escape_rust_keyword(name);
338 let escaped_name = if ctx.is_global(&escaped_name) {
339 let renamed = format!("{}_local", escaped_name);
340 ctx.add_renamed_local(escaped_name.clone(), renamed.clone());
341 renamed
342 } else {
343 escaped_name
344 };
345 if let HirType::Array { element_type, size: None } = var_type {
346 if let Some(size_expr) = initializer {
347 let size_code = self.generate_expression_with_context(size_expr, ctx);
348 let default_value = match element_type.as_ref() {
349 HirType::Int => "0i32",
350 HirType::UnsignedInt => "0u32",
351 HirType::Float => "0.0f32",
352 HirType::Double => "0.0f64",
353 HirType::Char => "0u8",
354 HirType::SignedChar => "0i8",
355 _ => &Self::default_value_for_type(element_type),
356 };
357
358 ctx.add_variable(
359 name.to_string(),
360 HirType::Vec(Box::new(element_type.as_ref().clone())),
361 );
362
363 return format!(
364 "let mut {} = vec![{}; {}];",
365 escaped_name, default_value, size_code
366 );
367 }
368 }
369
370 let is_malloc_init = if let Some(init_expr) = initializer {
371 Self::is_any_malloc_or_calloc(init_expr)
372 } else {
373 false
374 };
375
376 let (actual_type, type_str) =
377 Self::resolve_declaration_type(name, var_type, initializer, is_malloc_init, ctx);
378
379 let mutability = "mut ";
380 let mut code = format!("let {}{}: {}", mutability, escaped_name, type_str);
381 if let Some(init_expr) = initializer {
382 if matches!(init_expr, HirExpression::Malloc { .. }) {
383 self.generate_malloc_expr_init(&mut code, var_type, init_expr, ctx);
384 } else if is_malloc_init {
385 self.generate_malloc_funcall_init(
386 &mut code, var_type, &actual_type, init_expr, ctx,
387 );
388 } else {
389 self.generate_regular_init(
390 &mut code, var_type, &actual_type, init_expr, ctx,
391 );
392 }
393 } else {
394 code.push_str(&format!(" = {};", Self::default_value_for_type(var_type)));
395 }
396 code
397 }
398
399 fn generate_return_statement(
401 &self,
402 expr_opt: Option<&HirExpression>,
403 function_name: Option<&str>,
404 ctx: &mut TypeContext,
405 return_type: Option<&HirType>,
406 ) -> String {
407 if function_name == Some("main") {
410 if let Some(expr) = expr_opt {
411 let expr_code = self.generate_expression_with_context(expr, ctx);
412 let expr_type = ctx.infer_expression_type(expr);
415 let needs_cast = matches!(expr_type, Some(HirType::Char));
416 if needs_cast {
417 format!("std::process::exit({} as i32);", expr_code)
418 } else {
419 format!("std::process::exit({});", expr_code)
420 }
421 } else {
422 "std::process::exit(0);".to_string()
423 }
424 } else if let Some(expr) = expr_opt {
425 format!(
427 "return {};",
428 self.generate_expression_with_target_type(expr, ctx, return_type)
429 )
430 } else {
431 "return;".to_string()
432 }
433 }
434
435 fn generate_if_statement(
437 &self,
438 condition: &HirExpression,
439 then_block: &[HirStatement],
440 else_block: Option<&[HirStatement]>,
441 function_name: Option<&str>,
442 ctx: &mut TypeContext,
443 return_type: Option<&HirType>,
444 ) -> String {
445 let mut code = String::new();
446
447 let cond_code = self.generate_expression_with_context(condition, ctx);
450 let cond_str = if Self::is_boolean_expression(condition) {
451 cond_code
452 } else {
453 if let Some(cond_type) = ctx.infer_expression_type(condition) {
455 if matches!(cond_type, HirType::Pointer(_)) {
456 format!("!{}.is_null()", cond_code)
457 } else {
458 format!("({}) != 0", cond_code)
459 }
460 } else {
461 format!("({}) != 0", cond_code)
462 }
463 };
464 code.push_str(&format!("if {} {{\n", cond_str));
465
466 for stmt in then_block {
468 code.push_str(" ");
469 code.push_str(&self.generate_statement_with_context(
470 stmt,
471 function_name,
472 ctx,
473 return_type,
474 ));
475 code.push('\n');
476 }
477
478 if let Some(else_stmts) = else_block {
480 code.push_str("} else {\n");
481 for stmt in else_stmts {
482 code.push_str(" ");
483 code.push_str(&self.generate_statement_with_context(
484 stmt,
485 function_name,
486 ctx,
487 return_type,
488 ));
489 code.push('\n');
490 }
491 }
492
493 code.push('}');
494 code
495 }
496
497 fn generate_while_statement(
499 &self,
500 condition: &HirExpression,
501 body: &[HirStatement],
502 function_name: Option<&str>,
503 ctx: &mut TypeContext,
504 return_type: Option<&HirType>,
505 ) -> String {
506 let mut code = String::new();
507
508 let cond_str = if let Some(str_var) = Self::get_string_deref_var(condition, ctx) {
511 format!("!{}.is_empty()", str_var)
512 } else {
513 let cond_code = self.generate_expression_with_context(condition, ctx);
515 if Self::is_boolean_expression(condition) {
516 cond_code
517 } else {
518 if let Some(cond_type) = ctx.infer_expression_type(condition) {
520 if matches!(cond_type, HirType::Pointer(_)) {
521 format!("!{}.is_null()", cond_code)
522 } else {
523 format!("({}) != 0", cond_code)
524 }
525 } else {
526 format!("({}) != 0", cond_code)
527 }
528 }
529 };
530 code.push_str(&format!("while {} {{\n", cond_str));
531
532 for stmt in body {
534 code.push_str(" ");
535 code.push_str(&self.generate_statement_with_context(
536 stmt,
537 function_name,
538 ctx,
539 return_type,
540 ));
541 code.push('\n');
542 }
543
544 code.push('}');
545 code
546 }
547
548 fn generate_assignment_statement(
550 &self,
551 target: &str,
552 value: &HirExpression,
553 ctx: &mut TypeContext,
554 ) -> String {
555 if let HirExpression::Realloc { pointer, new_size } = value {
557 let target_var = target.to_string();
559
560 let element_type = if let Some(HirType::Vec(inner)) = ctx.get_type(&target_var)
562 {
563 inner.as_ref().clone()
564 } else {
565 HirType::Int
567 };
568
569 if let HirExpression::IntLiteral(0) = **new_size {
572 return format!("{}.clear(); // Free equivalent: clear vector", target_var);
573 }
574
575 if matches!(**pointer, HirExpression::NullLiteral) {
578 if let HirExpression::BinaryOp {
580 op: decy_hir::BinaryOperator::Multiply,
581 left,
582 ..
583 } = new_size.as_ref()
584 {
585 let count_code = self.generate_expression_with_context(left, ctx);
586 let default_value = Self::default_value_for_type(&element_type);
587 return format!(
588 "{}.resize({}, {})",
589 target_var, count_code, default_value
590 );
591 }
592 }
593
594 if let HirExpression::BinaryOp {
597 op: decy_hir::BinaryOperator::Multiply,
598 left,
599 ..
600 } = new_size.as_ref()
601 {
602 let count_code = self.generate_expression_with_context(left, ctx);
603 let default_value = Self::default_value_for_type(&element_type);
604 format!("{}.resize({}, {});", target_var, count_code, default_value)
605 } else {
606 let size_expr = self.generate_expression_with_context(new_size, ctx);
609 let default_value = Self::default_value_for_type(&element_type);
610 format!("{}.resize({} as usize, {});", target_var, size_expr, default_value)
611 }
612 } else {
613 if let Some(idx_var) = ctx.get_string_iter_index(target) {
616 if let HirExpression::BinaryOp { op, left, right } = value {
618 if let HirExpression::Variable(var_name) = &**left {
619 if var_name == target {
620 let right_code =
621 self.generate_expression_with_context(right, ctx);
622 return match op {
623 BinaryOperator::Add => {
624 format!("{} += {} as usize;", idx_var, right_code)
625 }
626 BinaryOperator::Subtract => {
627 format!("{} -= {} as usize;", idx_var, right_code)
628 }
629 _ => format!(
630 "{} = {};",
631 target,
632 self.generate_expression_with_context(value, ctx)
633 ),
634 };
635 }
636 }
637 }
638 }
639 let target_type = ctx.get_type(target);
641 let value_code =
642 self.generate_expression_with_target_type(value, ctx, target_type);
643
644 fn strip_nested_unsafe(code: &str) -> String {
646 let mut result = code.to_string();
648 while result.contains("unsafe { ") {
649 result = result.replace("unsafe { ", "").replace(" }", "");
650 }
653 result = code.replace("unsafe { ", "").replacen(
655 " }",
656 "",
657 code.matches("unsafe { ").count(),
658 );
659 result
660 }
661
662 if target == "errno" {
664 let clean_value = strip_nested_unsafe(&value_code);
665 return format!("unsafe {{ ERRNO = {}; }}", clean_value);
666 }
667 if ctx.is_global(target) {
670 let clean_value = strip_nested_unsafe(&value_code);
671 format!("unsafe {{ {} = {}; }}", target, clean_value)
672 } else {
673 format!("{} = {};", target, value_code)
674 }
675 }
676 }
677
678 fn generate_for_statement(
680 &self,
681 init: &[HirStatement],
682 condition: Option<&HirExpression>,
683 increment: &[HirStatement],
684 body: &[HirStatement],
685 function_name: Option<&str>,
686 ctx: &mut TypeContext,
687 return_type: Option<&HirType>,
688 ) -> String {
689 let mut code = String::new();
690
691 for init_stmt in init {
693 code.push_str(&self.generate_statement_with_context(
694 init_stmt,
695 function_name,
696 ctx,
697 return_type,
698 ));
699 code.push('\n');
700 }
701
702 if let Some(cond) = condition {
704 code.push_str(&format!(
705 "while {} {{\n",
706 self.generate_expression_with_context(cond, ctx)
707 ));
708 } else {
709 code.push_str("loop {\n");
710 }
711
712 for stmt in body {
714 code.push_str(" ");
715 code.push_str(&self.generate_statement_with_context(
716 stmt,
717 function_name,
718 ctx,
719 return_type,
720 ));
721 code.push('\n');
722 }
723
724 for inc_stmt in increment {
726 code.push_str(" ");
727 code.push_str(&self.generate_statement_with_context(
728 inc_stmt,
729 function_name,
730 ctx,
731 return_type,
732 ));
733 code.push('\n');
734 }
735
736 code.push('}');
737 code
738 }
739
740 fn generate_switch_statement(
742 &self,
743 condition: &HirExpression,
744 cases: &[decy_hir::SwitchCase],
745 default_case: Option<&[HirStatement]>,
746 function_name: Option<&str>,
747 ctx: &mut TypeContext,
748 return_type: Option<&HirType>,
749 ) -> String {
750 let mut code = String::new();
751
752 code.push_str(&format!(
754 "match {} {{\n",
755 self.generate_expression_with_context(condition, ctx)
756 ));
757
758 let condition_type = ctx.infer_expression_type(condition);
760 let condition_is_int = matches!(condition_type, Some(HirType::Int));
761
762 for case in cases {
764 if let Some(value_expr) = &case.value {
765 let case_pattern = if condition_is_int {
771 if let HirExpression::CharLiteral(ch) = value_expr {
772 format!("{}", (*ch) as i32)
774 } else {
775 self.generate_expression_with_context(value_expr, ctx)
776 }
777 } else {
778 self.generate_expression_with_context(value_expr, ctx)
779 };
780 code.push_str(&format!(" {} => {{\n", case_pattern));
781
782 for stmt in &case.body {
784 if !matches!(stmt, HirStatement::Break) {
785 code.push_str(" ");
786 code.push_str(&self.generate_statement_with_context(
787 stmt,
788 function_name,
789 ctx,
790 return_type,
791 ));
792 code.push('\n');
793 }
794 }
795
796 code.push_str(" },\n");
797 }
798 }
799
800 code.push_str(" _ => {\n");
802 if let Some(default_stmts) = default_case {
803 for stmt in default_stmts {
804 if !matches!(stmt, HirStatement::Break) {
805 code.push_str(" ");
806 code.push_str(&self.generate_statement_with_context(
807 stmt,
808 function_name,
809 ctx,
810 return_type,
811 ));
812 code.push('\n');
813 }
814 }
815 }
816 code.push_str(" },\n");
817
818 code.push('}');
819 code
820 }
821
822 fn generate_deref_assignment_statement(
824 &self,
825 target: &HirExpression,
826 value: &HirExpression,
827 ctx: &mut TypeContext,
828 ) -> String {
829 if matches!(
834 target,
835 HirExpression::PointerFieldAccess { .. }
836 | HirExpression::FieldAccess { .. }
837 | HirExpression::ArrayIndex { .. }
838 ) {
839 let target_code = self.generate_expression_with_context(target, ctx);
840 let value_code = self.generate_expression_with_context(value, ctx);
841 return format!("{} = {};", target_code, value_code);
842 }
843
844 if let HirExpression::Variable(var_name) = target {
846 if let Some(idx_var) = ctx.get_string_iter_index(var_name) {
847 let value_code = self.generate_expression_with_context(value, ctx);
849 return format!("{}[{}] = {};", var_name, idx_var, value_code);
850 }
851 }
852
853 let target_type = ctx
855 .infer_expression_type(&HirExpression::Dereference(Box::new(target.clone())));
856 let target_code = self.generate_expression_with_context(target, ctx);
857 let value_code =
858 self.generate_expression_with_target_type(value, ctx, target_type.as_ref());
859
860 fn strip_unsafe(code: &str) -> String {
862 if code.starts_with("unsafe { ") && code.ends_with(" }") {
863 code.strip_prefix("unsafe { ")
864 .and_then(|s| s.strip_suffix(" }"))
865 .unwrap_or(code)
866 .to_string()
867 } else {
868 code.to_string()
869 }
870 }
871
872 if let HirExpression::Variable(var_name) = target {
874 if ctx.is_pointer(var_name) {
875 let clean_value = strip_unsafe(&value_code);
877 return Self::unsafe_stmt(
879 &format!("*{} = {}", target_code, clean_value),
880 "pointer is valid, aligned, and not aliased during write",
881 );
882 }
883 }
884
885 if let HirExpression::Dereference(inner) = target {
889 if let HirExpression::Variable(var_name) = &**inner {
890 if let Some(var_type) = ctx.get_type(var_name) {
893 let yields_raw_ptr = match var_type {
894 HirType::Reference { inner: ref_inner, .. } => {
895 matches!(&**ref_inner, HirType::Pointer(_))
896 }
897 HirType::Pointer(ptr_inner) => {
898 matches!(&**ptr_inner, HirType::Pointer(_))
899 }
900 _ => false,
901 };
902 if yields_raw_ptr {
903 let clean_value = strip_unsafe(&value_code);
904 return Self::unsafe_stmt(
906 &format!("*{} = {}", target_code, clean_value),
907 "double pointer dereference - inner pointer is valid and writable",
908 );
909 }
910 }
911 }
912 }
913
914 format!("*{} = {};", target_code, value_code)
915 }
916
917 #[allow(clippy::borrowed_box)]
919 fn generate_array_index_assignment_statement(
920 &self,
921 array: &Box<HirExpression>,
922 index: &Box<HirExpression>,
923 value: &HirExpression,
924 ctx: &mut TypeContext,
925 ) -> String {
926 let target_expr =
928 HirExpression::ArrayIndex { array: array.clone(), index: index.clone() };
929 let target_type = ctx.infer_expression_type(&target_expr);
930
931 let is_raw_pointer = if let HirExpression::Variable(var_name) = &**array {
933 ctx.is_pointer(var_name)
934 } else {
935 matches!(ctx.infer_expression_type(array), Some(HirType::Pointer(_)))
937 };
938
939 let is_global_array = if let HirExpression::Variable(var_name) = &**array {
941 ctx.is_global(var_name)
942 } else {
943 false
944 };
945
946 let array_code = if is_global_array {
948 if let HirExpression::Variable(var_name) = &**array {
949 var_name.clone()
950 } else {
951 self.generate_expression_with_context(array, ctx)
952 }
953 } else {
954 self.generate_expression_with_context(array, ctx)
955 };
956 let index_code = self.generate_expression_with_context(index, ctx);
957 let mut value_code =
958 self.generate_expression_with_target_type(value, ctx, target_type.as_ref());
959
960 if matches!(target_type, Some(HirType::Char)) {
964 let value_type = ctx.infer_expression_type(value);
965 if matches!(value_type, Some(HirType::Int)) {
966 value_code = format!("({}) as u8", value_code);
967 }
968 }
969
970 if is_raw_pointer {
971 Self::unsafe_stmt(
974 &format!("*{}.add(({}) as usize) = {}", array_code, index_code, value_code),
975 "index is within bounds of allocated array",
976 )
977 } else {
978 if is_global_array {
982 format!(
983 "unsafe {{ {}[({}) as usize] = {}; }}",
984 array_code, index_code, value_code
985 )
986 } else {
987 format!("{}[({}) as usize] = {};", array_code, index_code, value_code)
988 }
989 }
990 }
991
992 fn generate_field_assignment_statement(
994 &self,
995 object: &HirExpression,
996 field: &str,
997 value: &HirExpression,
998 ctx: &mut TypeContext,
999 ) -> String {
1000 let escaped_field = escape_rust_keyword(field);
1002 let field_type = ctx.get_field_type(object, field);
1004 let obj_code = self.generate_expression_with_context(object, ctx);
1005 let value_code =
1006 self.generate_expression_with_target_type(value, ctx, field_type.as_ref());
1007
1008 let obj_type = if let HirExpression::Variable(name) = object {
1010 ctx.get_type(name)
1011 } else {
1012 None
1013 };
1014
1015 if matches!(obj_type, Some(HirType::Pointer(_))) {
1016 Self::unsafe_stmt(
1019 &format!("(*{}).{} = {}", obj_code, escaped_field, value_code),
1020 "pointer is non-null and points to valid struct with exclusive access",
1021 )
1022 } else {
1023 if let HirExpression::Variable(name) = object {
1025 if ctx.is_global(name) {
1026 fn strip_nested_unsafe(code: &str) -> String {
1028 code.replace("unsafe { ", "").replacen(
1029 " }",
1030 "",
1031 code.matches("unsafe { ").count(),
1032 )
1033 }
1034 let clean_value = strip_nested_unsafe(&value_code);
1035 return format!(
1036 "unsafe {{ {}.{} = {}; }}",
1037 name, escaped_field, clean_value
1038 );
1039 }
1040 }
1041 format!("{}.{} = {};", obj_code, escaped_field, value_code)
1043 }
1044 }
1045}