1use std::collections::HashMap;
2
3use crate::{
4 ir::tac::{CastType, Instruction, IrOp, ScopedMap, Value},
5 parse::parsing::{BinaryOp, Expr, ExprKind, Literal, Parameter, Program, Stmt, Type, UnaryOp},
6 utils::typesafe::type_to_string,
7};
8
9pub struct TempGen {
10 counter: usize,
11}
12impl TempGen {
13 pub fn new() -> Self {
14 Self { counter: 0 }
15 }
16 pub fn next_temp(&mut self) -> String {
17 self.counter += 1;
18 format!("t{}", self.counter)
19 }
20}
21impl Default for TempGen {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27pub struct LabelGen {
28 counter: usize,
29}
30impl LabelGen {
31 pub fn new() -> Self {
32 Self { counter: 0 }
33 }
34 pub fn next_label(&mut self) -> String {
35 self.counter += 1;
36 format!("L{}", self.counter)
37 }
38}
39impl Default for LabelGen {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44pub struct FunctionGen {
45 counter: usize,
46}
47impl FunctionGen {
48 pub fn new() -> Self {
49 Self { counter: 0 }
50 }
51 pub fn next(&mut self, name: String) -> String {
52 self.counter += 1;
53 name
54 }
55}
56impl Default for FunctionGen {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61#[derive(Debug)]
62pub struct StructLayout {
63 pub total_size: i64,
64 pub field_offsets: HashMap<String, (i64, Type)>,
65}
66
67pub struct IRGen {
68 pub code: Vec<Instruction>,
69 temps: TempGen,
70 labels: LabelGen,
71 functions: FunctionGen,
72 loop_exits: Vec<String>,
73 pub analyser_constants: HashMap<String, (Type, Expr)>,
74 pub evaluated_constants: HashMap<String, Value>,
75 pub var_types: ScopedMap,
76 pub struct_defs: HashMap<String, StructLayout>,
77 pub struct_blueprints: HashMap<String, (Vec<String>, Vec<Parameter>)>,
78 pub current_function: String,
79
80 pub fn_blueprints: HashMap<String, Stmt>,
81 pub instantiated_fns: std::collections::HashSet<String>,
82 pub deferred_instantiations: Vec<(String, Vec<Type>)>,
83 pub current_substitutions: HashMap<String, Type>,
84}
85
86impl IRGen {
87 pub fn new() -> Self {
88 Self {
89 code: Vec::new(),
90 temps: TempGen::new(),
91 labels: LabelGen::new(),
92 functions: FunctionGen::new(),
93 loop_exits: Vec::new(),
94 struct_defs: HashMap::new(),
95 struct_blueprints: HashMap::new(),
96 var_types: ScopedMap::new(HashMap::new()),
97 current_function: String::new(),
98
99 analyser_constants: HashMap::new(),
100 evaluated_constants: HashMap::new(),
101
102 fn_blueprints: HashMap::new(),
103 instantiated_fns: std::collections::HashSet::new(),
104 deferred_instantiations: Vec::new(),
105 current_substitutions: HashMap::new(),
106 }
107 }
108
109 pub fn next_temp_with_type(&mut self, ty: Type) -> String {
110 let base_name = self.temps.next_temp();
111 let qualified_name = if self.current_function.is_empty() {
112 base_name
113 } else {
114 format!("{}::{}", self.current_function, base_name)
115 };
116 self.var_types.insert(qualified_name.clone(), ty);
117 qualified_name
118 }
119
120 fn substitute_type(&self, ty: &Type, substitutions: &HashMap<String, Type>) -> Type {
121 match ty {
122 Type::Struct(name) => substitutions
123 .get(name)
124 .cloned()
125 .unwrap_or(Type::Struct(name.clone())),
126
127 Type::Ptr(inner) => Type::Ptr(Box::new(self.substitute_type(inner, substitutions))),
128
129 Type::Array { element_type, size } => Type::Array {
130 element_type: Box::new(self.substitute_type(element_type, substitutions)),
131 size: *size,
132 },
133
134 Type::GenericInstance { name, args } => Type::GenericInstance {
135 name: name.clone(),
136 args: args
137 .iter()
138 .map(|arg| self.substitute_type(arg, substitutions))
139 .collect(),
140 },
141 Type::GenericParam(name) => substitutions
142 .get(name)
143 .cloned()
144 .unwrap_or_else(|| panic!("Unresolved generic parameter: {}", name)),
145
146 Type::Int
147 | Type::UInt
148 | Type::Int8
149 | Type::UInt8
150 | Type::Bool
151 | Type::Str
152 | Type::Char
153 | Type::Void
154 | Type::Any => ty.clone(),
155 }
156 }
157
158 fn mangle_type(&self, ty: &Type) -> String {
159 crate::utils::typesafe::type_to_mangled_string(ty)
160 }
161
162 pub fn resolve_type(&mut self, ty: &Type) -> Type {
163 let substituted = if !self.current_substitutions.is_empty() {
164 self.substitute_type(ty, &self.current_substitutions.clone())
165 } else {
166 ty.clone()
167 };
168
169 if substituted != *ty {
170 return self.resolve_type(&substituted);
171 }
172
173 match substituted {
174 Type::GenericInstance { name, args } => {
175 let resolved_args: Vec<Type> =
176 args.iter().map(|arg| self.resolve_type(arg)).collect();
177
178 let mut mangled_name = name.clone();
179 for arg in &resolved_args {
180 mangled_name.push_str("__");
181 mangled_name.push_str(&self.mangle_type(arg));
182 }
183
184 if !self.struct_defs.contains_key(&mangled_name)
185 && let Some((params, fields)) = self.struct_blueprints.get(&name).cloned()
186 {
187 let substitutions: HashMap<String, Type> =
188 params.into_iter().zip(resolved_args).collect();
189
190 self.instantiate_struct_layout(mangled_name.clone(), &fields, &substitutions);
191 }
192 Type::Struct(mangled_name)
193 }
194 Type::Ptr(inner) => Type::Ptr(Box::new(self.resolve_type(&inner))),
195 Type::Array { element_type, size } => Type::Array {
196 element_type: Box::new(self.resolve_type(&element_type)),
197 size,
198 },
199 _ => substituted,
200 }
201 }
202
203 fn instantiate_struct_layout(
204 &mut self,
205 mangled_name: String,
206 fields: &[Parameter],
207 substitutions: &HashMap<String, Type>,
208 ) {
209 let mut current_offset: i64 = 0;
210 let mut max_alignment: i64 = 1;
211 let mut field_offsets = HashMap::new();
212
213 for field in fields {
214 let field_name = field.name.value.clone();
215 let base_type = field.ptype.clone().unwrap_or(Type::Int);
216
217 let substituted = self.substitute_type(&base_type, substitutions);
218 let field_type = self.resolve_type(&substituted);
219
220 let field_size = self.type_size(&field_type);
221 let field_align = self.type_alignment(&field_type);
222
223 if field_align > max_alignment {
224 max_alignment = field_align;
225 }
226
227 current_offset = (current_offset + field_align - 1) & !(field_align - 1);
228 field_offsets.insert(field_name, (current_offset, field_type));
229 current_offset += field_size;
230 }
231
232 let total_size = (current_offset + max_alignment - 1) & !(max_alignment - 1);
233 self.struct_defs.insert(
234 mangled_name.clone(),
235 StructLayout {
236 total_size,
237 field_offsets,
238 },
239 );
240 }
241
242 fn get_struct_layout(&self, name: &str) -> Option<&StructLayout> {
243 if let Some(layout) = self.struct_defs.get(name) {
244 return Some(layout);
245 }
246 if let Some(base_name) = name.split("__").next() {
247 for (key, layout) in &self.struct_defs {
248 if key == base_name || key.starts_with(&format!("{}__", base_name)) {
249 return Some(layout);
250 }
251 }
252 }
253 None
254 }
255
256 fn get_value_type(&self, value: &Value) -> Type {
257 match value {
258 Value::Temp(name) | Value::Var(name) => {
259 self.var_types.get(name).cloned().unwrap_or(Type::Int)
260 }
261 Value::Const(_) => Type::Int,
262 Value::Bool(_) => Type::Bool,
263 Value::Char(_) => Type::Char,
264 Value::Str(_) => Type::Str,
265 Value::Void => Type::Void,
266 }
267 }
268
269 fn type_size(&self, ty: &Type) -> i64 {
270 match ty {
271 Type::Int | Type::UInt => 8,
272 Type::Int8 | Type::UInt8 => 1,
273 Type::Bool => 1,
274 Type::Str => 8,
275 Type::Ptr(_) => 8,
276 Type::Array { element_type, size } => self.element_size(element_type) * (*size as i64),
277 Type::GenericParam(name) => {
278 panic!("Cannot get size of unresolved generic parameter: {}", name)
279 }
280 Type::Char => 1,
281 Type::Struct(name) => self
282 .get_struct_layout(name)
283 .map(|l| l.total_size)
284 .unwrap_or_else(|| panic!("Failed to find layout for struct: {name}")),
285 Type::GenericInstance { name, args } => {
286 let mut mangled_name = name.clone();
287 for arg in args {
288 mangled_name.push_str("__");
289 mangled_name.push_str(&self.mangle_type(arg));
290 }
291 self.get_struct_layout(&mangled_name)
292 .map(|l| l.total_size)
293 .unwrap_or_else(|| {
294 panic!("Failed to find layout for generic instance: {mangled_name}")
295 })
296 }
297
298 Type::Void => 0,
299 Type::Any => 8, }
301 }
302
303 fn type_alignment(&self, ty: &Type) -> i64 {
304 match ty {
305 Type::Int | Type::UInt => 8,
306 Type::Int8 | Type::UInt8 => 1,
307 Type::Bool => 1,
308 Type::GenericParam(name) => {
309 panic!(
310 "Cannot get alignment of unresolved generic parameter: {}",
311 name
312 )
313 }
314 Type::Char => 1,
315 Type::Str => 8,
316 Type::Ptr(_) => 8,
317 Type::Array { element_type, .. } => self.type_alignment(element_type),
318 Type::Struct(name) => self
319 .get_struct_layout(name)
320 .map(|l| l.total_size)
321 .unwrap_or_else(|| panic!("Failed to find layout for struct: {name}")),
322 Type::GenericInstance { name, args } => {
323 let mut mangled_name = name.clone();
324 for arg in args {
325 mangled_name.push_str("__");
326 mangled_name.push_str(&self.mangle_type(arg));
327 }
328 self.get_struct_layout(&mangled_name)
329 .map(|l| l.total_size)
330 .unwrap_or_else(|| {
331 panic!("Failed to find layout for generic instance: {mangled_name}")
332 })
333 }
334 Type::Void => 0,
335 Type::Any => 8, }
337 }
338
339 fn element_size(&self, ty: &Type) -> i64 {
340 self.type_size(ty)
341 }
342
343 fn emit_binary(&mut self, op: IrOp, lhs: Value, rhs: Value) -> Value {
344 let lhs_ty = self.get_value_type(&lhs);
345 let rhs_ty = self.get_value_type(&rhs);
346
347 let result_ty = match op {
348 IrOp::Add | IrOp::Sub | IrOp::Mul | IrOp::Div | IrOp::Mod => {
349 if lhs_ty == Type::Str || rhs_ty == Type::Str {
350 Type::Str
351 } else {
352 Type::Int
353 }
354 }
355 IrOp::Eq | IrOp::NEq | IrOp::Gt | IrOp::GtE | IrOp::Lt | IrOp::LtE => Type::Bool,
356 _ => Type::Int,
357 };
358
359 let temp = self.next_temp_with_type(result_ty);
360 self.code.push(Instruction::Binary {
361 dst: temp.clone(),
362 op,
363 lhs,
364 rhs,
365 });
366 Value::Temp(temp)
367 }
368
369 fn emit_unary(&mut self, op: IrOp, value: Value) -> Value {
370 let inner_ty = self.get_value_type(&value);
371
372 let result_ty = match op {
373 IrOp::Pos | IrOp::Neg => inner_ty,
374 IrOp::Ref => Type::Ptr(Box::new(inner_ty)),
375 _ => Type::Int,
376 };
377
378 let temp = self.next_temp_with_type(result_ty);
379 self.code.push(Instruction::Unary {
380 dst: temp.clone(),
381 op,
382 value,
383 });
384 Value::Temp(temp)
385 }
386
387 fn is_string_valued(&self, value: &Value) -> bool {
388 matches!(value, Value::Str(_))
389 }
390
391 pub fn expr_type(&mut self, expr: &Expr) -> Option<Type> {
392 match &expr.kind {
393 ExprKind::Cast { left: _, right } => Some(right.clone()),
394 ExprKind::Sizeof { .. } => Some(Type::Int),
395 ExprKind::Literal(Literal::String(_)) => Some(Type::Str),
396 ExprKind::Literal(Literal::Int(_)) => Some(Type::Int),
397 ExprKind::Literal(Literal::Bool(_)) => Some(Type::Bool),
398 ExprKind::Literal(Literal::Char(_)) => Some(Type::Char),
399 ExprKind::Literal(Literal::Arr { elements }) => {
400 if !elements.is_empty() {
401 let element_type = self.expr_type(&elements[0])?;
402 Some(Type::Array {
403 element_type: Box::new(element_type),
404 size: elements.len(),
405 })
406 } else {
407 Some(Type::Array {
408 element_type: Box::new(Type::Int),
409 size: 0,
410 })
411 }
412 }
413 ExprKind::Identifier(name) => {
414 let local_mangled = format!("{}::{}", self.current_function, name);
415 if let Some(ty) = self.var_types.get(&local_mangled).cloned() {
416 return Some(self.resolve_type(&ty));
417 }
418 if let Some((ty, _)) = self.analyser_constants.get(name) {
419 let ty = ty.clone();
420 return Some(self.resolve_type(&ty));
421 }
422 if let Some(ty) = self.var_types.get(name).cloned() {
423 return Some(self.resolve_type(&ty));
424 }
425 None
426 }
427 ExprKind::Binary { left, op, .. } => match op {
428 BinaryOp::Eq
429 | BinaryOp::NEq
430 | BinaryOp::Gt
431 | BinaryOp::GtE
432 | BinaryOp::Lt
433 | BinaryOp::LtE => Some(Type::Bool),
434 _ => self.expr_type(left),
435 },
436 ExprKind::Call { .. } => None,
437
438 ExprKind::Index { base, .. } => match self.expr_type(base)? {
439 Type::Array { element_type, .. } => Some(*element_type),
440 Type::Ptr(inner) => match *inner {
441 Type::Array { element_type, .. } => Some(*element_type),
442 other => Some(other),
443 },
444 _ => None,
445 },
446
447 ExprKind::Unary {
448 op,
449 expr: inner_expr,
450 } => {
451 let inner_type = self.expr_type(inner_expr)?;
452 match op {
453 UnaryOp::AddressOf => Some(Type::Ptr(Box::new(inner_type))),
454 UnaryOp::Deref => match inner_type {
455 Type::Ptr(inner) => Some(*inner),
456 _ => None,
457 },
458 UnaryOp::Positive | UnaryOp::Negative => Some(Type::Int),
459 UnaryOp::Not => Some(Type::Bool),
460 }
461 }
462 ExprKind::Field { base, field } => {
463 if let Some(base_ty) = self.expr_type(base) {
464 let struct_name = match self.resolve_type(&base_ty) {
465 Type::Struct(name) => Some(name),
466 Type::GenericInstance { name, args } => {
467 let mut mangled_name = name;
468 for arg in args {
469 mangled_name.push_str("__");
470 mangled_name.push_str(&self.mangle_type(&arg));
471 }
472 Some(mangled_name)
473 }
474 _ => None,
475 };
476
477 if let Some(name) = struct_name {
478 let found_field_ty = self
479 .get_struct_layout(&name)
480 .and_then(|layout| layout.field_offsets.get(field))
481 .map(|(_, field_ty)| field_ty.clone());
482
483 if let Some(field_ty) = found_field_ty {
484 return Some(self.resolve_type(&field_ty));
485 }
486 }
487 }
488 None
489 }
490 ExprKind::StructLiteral { struct_name, .. } => Some(Type::Struct(struct_name.clone())),
491 }
492 }
493
494 fn gen_lvalue_addr(&mut self, expr: &Expr) -> Value {
495 match &expr.kind {
496 ExprKind::Identifier(name) => {
497 let ty = self.var_types.get(name).cloned().unwrap_or(Type::Int);
498 let temp = self.next_temp_with_type(Type::Ptr(Box::new(ty)));
499 self.code.push(Instruction::Unary {
500 dst: temp.clone(),
501 op: IrOp::Ref,
502 value: Value::Var(name.clone()),
503 });
504 Value::Temp(temp)
505 }
506
507 ExprKind::Unary {
508 op: UnaryOp::Deref,
509 expr: inner,
510 } => self.gen_expr(inner, None),
511
512 ExprKind::Field { base, field } => {
513 let base_addr = self.gen_lvalue_addr(base);
514
515 let base_type = self.expr_type(base).unwrap_or(Type::Int);
516 let resolved_base = self.resolve_type(&base_type);
517
518 let struct_name = match resolved_base {
519 Type::Struct(name) => name,
520 Type::GenericInstance { name, args } => {
521 let mut mangled_name = name;
522 for arg in args {
523 mangled_name.push_str("__");
524 mangled_name.push_str(&self.mangle_type(&arg));
525 }
526 mangled_name
527 }
528 _ => panic!(
529 "Field access on non-struct type: {}",
530 type_to_string(&base_type)
531 ),
532 };
533
534 let (offset, field_type) = {
535 let (offset, unres_field_ty) = self
536 .struct_defs
537 .get(&struct_name)
538 .unwrap_or_else(|| panic!("Struct layout not found: {}", struct_name))
539 .field_offsets
540 .get(field)
541 .map(|(offset, field_ty)| (*offset, field_ty.clone()))
542 .unwrap_or_else(|| {
543 panic!("Field '{}' not found in struct '{}'", field, struct_name)
544 });
545
546 (offset, self.resolve_type(&unres_field_ty))
547 };
548
549 let field_addr_temp = self.next_temp_with_type(Type::Ptr(Box::new(field_type)));
550 self.code.push(Instruction::Binary {
551 dst: field_addr_temp.clone(),
552 op: IrOp::Add,
553 lhs: base_addr,
554 rhs: Value::Const(offset),
555 });
556
557 Value::Temp(field_addr_temp)
558 }
559
560 ExprKind::Index { base, index } => {
561 let base_addr = self.gen_lvalue_addr(base);
562 let index_val = self.gen_expr(index, None);
563
564 let base_type = self.expr_type(base);
565 let element_type = match &base_type {
566 Some(Type::Array { element_type, .. }) => *element_type.clone(),
567 Some(Type::Ptr(inner)) => match &**inner {
568 Type::Array { element_type, .. } => *element_type.clone(),
569 other => other.clone(),
570 },
571 _ => Type::Int,
572 };
573
574 let stride = self.element_size(&element_type);
575
576 let offset_temp = self.next_temp_with_type(Type::Int);
577 self.code.push(Instruction::Binary {
578 dst: offset_temp.clone(),
579 op: IrOp::Mul,
580 lhs: index_val,
581 rhs: Value::Const(stride),
582 });
583
584 let elem_addr_temp = self.next_temp_with_type(Type::Ptr(Box::new(element_type)));
585 self.code.push(Instruction::Binary {
586 dst: elem_addr_temp.clone(),
587 op: IrOp::Add,
588 lhs: base_addr,
589 rhs: Value::Temp(offset_temp),
590 });
591
592 Value::Temp(elem_addr_temp)
593 }
594
595 _ => {
596 panic!("Cannot take address of: {:?}", expr.kind);
597 }
598 }
599 }
600
601 pub fn gen_expr(&mut self, expr: &Expr, target_dest: Option<Value>) -> Value {
602 match &expr.kind {
603 ExprKind::Sizeof { ty } => {
604 let resolved_ty = self.resolve_type(ty);
605 let size = self.type_size(&resolved_ty);
606 Value::Const(size)
607 }
608
609 ExprKind::Cast { left, right } => {
610 let val_to_cast = self.gen_expr(left, None);
611
612 let from_type = self.expr_type(left).unwrap_or(Type::Int);
613 let to_type = self.resolve_type(right);
614
615 let cast_kind = match (&from_type, &to_type) {
616 (Type::Ptr(_), Type::Ptr(_)) => CastType::BitCast,
618
619 (Type::Ptr(_), Type::Str) => CastType::BitCast,
621
622 (
624 Type::Int | Type::UInt | Type::Int8 | Type::UInt8,
625 Type::Int | Type::UInt | Type::Int8 | Type::UInt8,
626 ) => {
627 let from_size = self.type_size(&from_type);
628 let to_size = self.type_size(&to_type);
629 if from_size < to_size {
630 CastType::Extend
631 } else if from_size > to_size {
632 CastType::Truncate
633 } else {
634 CastType::BitCast
635 }
636 }
637
638 _ => CastType::BitCast,
640 };
641
642 let result_temp = self.next_temp_with_type(to_type.clone());
643
644 self.code.push(Instruction::Cast {
645 dst: result_temp.clone(),
646 cast_ty: cast_kind,
647 value: val_to_cast,
648 to_type,
649 });
650
651 Value::Temp(result_temp)
652 }
653
654 ExprKind::Literal(lit) => match lit {
655 Literal::Int(v) => Value::Const(*v),
656 Literal::String(s) => Value::Str(s.clone()),
657 Literal::Bool(b) => Value::Bool(*b),
658 Literal::Char(c) => Value::Char(*c),
659 Literal::Arr { elements } => {
660 let element_type = if !elements.is_empty() {
661 self.expr_type(&elements[0]).unwrap_or(Type::Int)
662 } else {
663 Type::Int
664 };
665 let stride = self.element_size(&element_type);
666
667 let base_val = match target_dest {
668 Some(dest) => dest,
669 None => {
670 let raw_temp = self.temps.next_temp();
671 let anon_name = format!("_anon_{}", raw_temp);
672 self.var_types.insert(
673 anon_name.clone(),
674 Type::Array {
675 element_type: Box::new(element_type.clone()),
676 size: elements.len(),
677 },
678 );
679 Value::Var(anon_name)
680 }
681 };
682
683 for (index, element_expr) in elements.iter().enumerate() {
684 let element_val = self.gen_expr(element_expr, None);
685
686 let offset_temp = self.next_temp_with_type(Type::Int);
687 self.code.push(Instruction::Binary {
688 dst: offset_temp.clone(),
689 op: IrOp::Mul,
690 lhs: Value::Const(index as i64),
691 rhs: Value::Const(stride),
692 });
693
694 let base_addr_temp =
695 self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
696 self.code.push(Instruction::Unary {
697 dst: base_addr_temp.clone(),
698 op: IrOp::Ref,
699 value: base_val.clone(),
700 });
701
702 let slot_addr_temp =
703 self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
704 self.code.push(Instruction::Binary {
705 dst: slot_addr_temp.clone(),
706 op: IrOp::Add,
707 lhs: Value::Temp(base_addr_temp),
708 rhs: Value::Temp(offset_temp),
709 });
710
711 self.code.push(Instruction::Store {
712 ptr: Value::Temp(slot_addr_temp),
713 source: element_val,
714 });
715 }
716
717 base_val
718 }
719 },
720
721 ExprKind::Field { base, field } => {
722 let base_val = self.gen_expr(base, None);
723 let base_type = self.expr_type(base).unwrap_or(Type::Int);
724 let resolved_base = self.resolve_type(&base_type);
725
726 let struct_name = match resolved_base {
727 Type::Struct(name) => name,
728 Type::GenericInstance { name, args } => {
729 let mut mangled_name = name;
730 for arg in args {
731 mangled_name.push_str("__");
732 mangled_name.push_str(&self.mangle_type(&arg));
733 }
734 mangled_name
735 }
736 _ => panic!(
737 "ICE: Attempted field access on non-struct type. Found: {}",
738 type_to_string(&base_type)
739 ),
740 };
741
742 let (offset, field_type) = {
743 let (offset, unres_field_ty) = self
744 .get_struct_layout(&struct_name)
745 .unwrap_or_else(|| {
746 panic!(
747 "ICE: Structural reference layout untracked for '{}'.",
748 struct_name
749 )
750 })
751 .field_offsets
752 .get(field)
753 .map(|(offset, field_ty)| (*offset, field_ty.clone()))
754 .unwrap_or_else(|| {
755 panic!(
756 "ICE: Referenced struct field '{}' does not exist in '{}'.",
757 field, struct_name
758 )
759 });
760
761 (offset, self.resolve_type(&unres_field_ty))
762 };
763
764 let base_addr_temp =
765 self.next_temp_with_type(Type::Ptr(Box::new(Type::Struct(struct_name))));
766 self.code.push(Instruction::Unary {
767 dst: base_addr_temp.clone(),
768 op: IrOp::Ref,
769 value: base_val,
770 });
771
772 let field_addr_temp =
773 self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
774 self.code.push(Instruction::Binary {
775 dst: field_addr_temp.clone(),
776 op: IrOp::Add,
777 lhs: Value::Temp(base_addr_temp),
778 rhs: Value::Const(offset),
779 });
780
781 let result_temp = self.next_temp_with_type(field_type.clone());
782 self.code.push(Instruction::Load {
783 dst: result_temp.clone(),
784 ptr: Value::Temp(field_addr_temp),
785 ty: field_type,
786 });
787
788 Value::Temp(result_temp)
789 }
790
791 ExprKind::StructLiteral {
792 struct_name,
793 generic_args,
794 fields,
795 } => {
796 let concrete_type = if generic_args.is_empty() {
797 Type::Struct(struct_name.clone())
798 } else {
799 let generic_ty = Type::GenericInstance {
800 name: struct_name.clone(),
801 args: generic_args.clone(),
802 };
803 self.resolve_type(&generic_ty)
804 };
805
806 let concrete_struct_name = match &concrete_type {
807 Type::Struct(name) => name.clone(),
808 _ => panic!("Expected concrete struct type after resolution"),
809 };
810
811 let target_val = match target_dest {
812 Some(dest) => dest,
813 None => {
814 let temp_name = self.next_temp_with_type(concrete_type.clone());
815 Value::Temp(temp_name)
816 }
817 };
818
819 let layout_fields = self
820 .struct_defs
821 .get(&concrete_struct_name)
822 .expect("ICE: Structural initialization on untracked layout.")
823 .field_offsets
824 .clone();
825
826 for (field_name, field_expr) in fields {
827 let field_val = self.gen_expr(field_expr, None);
828 let (offset, field_type) = layout_fields
829 .get(field_name)
830 .expect("ICE: Field initialization lookup failure.");
831
832 let base_addr_temp =
833 self.next_temp_with_type(Type::Ptr(Box::new(concrete_type.clone())));
834 self.code.push(Instruction::Unary {
835 dst: base_addr_temp.clone(),
836 op: IrOp::Ref,
837 value: target_val.clone(),
838 });
839
840 let slot_addr_temp =
841 self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
842 self.code.push(Instruction::Binary {
843 dst: slot_addr_temp.clone(),
844 op: IrOp::Add,
845 lhs: Value::Temp(base_addr_temp),
846 rhs: Value::Const(*offset),
847 });
848
849 self.code.push(Instruction::Store {
850 ptr: Value::Temp(slot_addr_temp),
851 source: field_val,
852 });
853 }
854
855 target_val
856 }
857
858 ExprKind::Index { base, index } => {
859 let base_val = self.gen_expr(base, None);
860 let index_val = self.gen_expr(index, None);
861
862 let base_type = self.expr_type(base);
863 let element_type = match &base_type {
864 Some(Type::Array { element_type, .. }) => *element_type.clone(),
865 Some(Type::Ptr(inner)) => match &**inner {
866 Type::Array { element_type, .. } => *element_type.clone(),
867 other => other.clone(),
868 },
869 _ => Type::Int,
870 };
871
872 let stride = self.element_size(&element_type);
873 let offset_temp = self.next_temp_with_type(Type::Int);
874 self.code.push(Instruction::Binary {
875 dst: offset_temp.clone(),
876 op: IrOp::Mul,
877 lhs: index_val,
878 rhs: Value::Const(stride),
879 });
880
881 let target_addr_temp =
882 self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
883 let is_base_variable_a_pointer = match &base_val {
884 Value::Var(name) => matches!(self.var_types.get(name), Some(Type::Ptr(_))),
885 _ => false,
886 };
887
888 if is_base_variable_a_pointer || matches!(base_type, Some(Type::Ptr(_))) {
889 self.code.push(Instruction::Binary {
890 dst: target_addr_temp.clone(),
891 op: IrOp::Add,
892 lhs: base_val,
893 rhs: Value::Temp(offset_temp),
894 });
895 } else {
896 match base_val {
897 Value::Var(_) => {
898 let base_addr_temp =
899 self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
900 self.code.push(Instruction::Unary {
901 dst: base_addr_temp.clone(),
902 op: IrOp::Ref,
903 value: base_val,
904 });
905 self.code.push(Instruction::Binary {
906 dst: target_addr_temp.clone(),
907 op: IrOp::Add,
908 lhs: Value::Temp(base_addr_temp),
909 rhs: Value::Temp(offset_temp),
910 });
911 }
912 _ => {
913 self.code.push(Instruction::Binary {
914 dst: target_addr_temp.clone(),
915 op: IrOp::Add,
916 lhs: base_val,
917 rhs: Value::Temp(offset_temp),
918 });
919 }
920 }
921 }
922
923 let result_temp = self.next_temp_with_type(element_type.clone());
924 self.code.push(Instruction::Load {
925 dst: result_temp.clone(),
926 ptr: Value::Temp(target_addr_temp),
927 ty: element_type,
928 });
929
930 Value::Temp(result_temp)
931 }
932
933 ExprKind::Identifier(name) => {
934 let local_mangled = format!("{}::{}", self.current_function, name);
935 if self.var_types.get(&local_mangled).is_some() {
936 return Value::Var(local_mangled);
937 }
938 let maybe_const_expr = self
939 .analyser_constants
940 .get(name)
941 .map(|(_, expr)| expr.clone());
942 if let Some(expr) = maybe_const_expr {
943 if let Some(val) = self.evaluated_constants.get(name) {
944 return val.clone();
945 }
946 let val = self.gen_expr(&expr, None);
947 self.evaluated_constants.insert(name.clone(), val.clone());
948 return val;
949 }
950 Value::Var(name.clone())
951 }
952
953 ExprKind::Unary { op, expr } => match op {
954 UnaryOp::Positive => {
955 let value = self.gen_expr(expr, None);
956 self.emit_unary(IrOp::Pos, value)
957 }
958 UnaryOp::Negative => {
959 let value = self.gen_expr(expr, None);
960 self.emit_unary(IrOp::Neg, value)
961 }
962 UnaryOp::Deref => {
963 let value = self.gen_expr(expr, None);
964 let inner_type = self.expr_type(expr).unwrap_or(Type::Void);
965 let value_type = match inner_type {
966 Type::Ptr(inner) => *inner,
967 _ => {
968 unreachable!(
969 "non-pointer type dereferenced (this should be handled by analyser)"
970 )
971 }
972 };
973 let result_temp = self.next_temp_with_type(value_type.clone());
974 self.code.push(Instruction::Load {
975 dst: result_temp.clone(),
976 ptr: value,
977 ty: value_type,
978 });
979 Value::Temp(result_temp)
980 }
981 UnaryOp::Not => {
982 let value = self.gen_expr(expr, None);
983 self.emit_unary(IrOp::Not, value)
984 }
985 UnaryOp::AddressOf => {
986 if let ExprKind::Literal(lit) = &expr.kind {
987 let lit_val = match lit {
988 Literal::Int(v) => Value::Const(*v),
989 Literal::Bool(b) => Value::Bool(*b),
990 Literal::Char(c) => Value::Char(*c),
991 Literal::String(s) => Value::Str(s.clone()),
992 Literal::Arr { .. } => self.gen_expr(expr, None),
993 };
994
995 let lit_ty = self.expr_type(expr).unwrap_or(Type::Int);
996 let raw_temp = self.temps.next_temp();
997 let anon_var_name = format!("_anon_lit_{}", raw_temp);
998
999 self.var_types.insert(anon_var_name.clone(), lit_ty.clone());
1000
1001 self.code.push(Instruction::Assign {
1002 dst: anon_var_name.clone(),
1003 src: lit_val,
1004 });
1005
1006 let ref_temp = self.next_temp_with_type(Type::Ptr(Box::new(lit_ty)));
1007 self.code.push(Instruction::Unary {
1008 dst: ref_temp.clone(),
1009 op: IrOp::Ref,
1010 value: Value::Var(anon_var_name),
1011 });
1012
1013 Value::Temp(ref_temp)
1014 } else if matches!(
1015 expr.kind,
1016 ExprKind::Field { .. }
1017 | ExprKind::Index { .. }
1018 | ExprKind::Unary {
1019 op: UnaryOp::Deref,
1020 ..
1021 }
1022 ) {
1023 self.gen_lvalue_addr(expr)
1024 } else {
1025 let value = self.gen_expr(expr, None);
1026 let inner_type = self.get_value_type(&value);
1027 let temp = self.next_temp_with_type(Type::Ptr(Box::new(inner_type)));
1028 self.code.push(Instruction::Unary {
1029 dst: temp.clone(),
1030 op: IrOp::Ref,
1031 value,
1032 });
1033 Value::Temp(temp)
1034 }
1035 }
1036 },
1037
1038 ExprKind::Binary { left, op, right } => {
1039 let lhs = self.gen_expr(left, None);
1040 let rhs = self.gen_expr(right, None);
1041
1042 if matches!(op, BinaryOp::Add)
1043 && (self.is_string_valued(&lhs) || self.expr_type(left) == Some(Type::Str))
1044 && (self.is_string_valued(&rhs) || self.expr_type(right) == Some(Type::Str))
1045 {
1046 self.code.push(Instruction::Arg { value: lhs });
1047 self.code.push(Instruction::Arg { value: rhs });
1048 let dst = self.next_temp_with_type(Type::Str);
1049 self.code.push(Instruction::Call {
1050 dest: Some(dst.clone()),
1051 name: "str_concat".to_string(),
1052 argc: 2,
1053 });
1054 return Value::Temp(dst);
1055 }
1056
1057 let ir_op = match op {
1058 BinaryOp::Add => IrOp::Add,
1059 BinaryOp::Sub => IrOp::Sub,
1060 BinaryOp::Mul => IrOp::Mul,
1061 BinaryOp::Div => IrOp::Div,
1062 BinaryOp::Eq => IrOp::Eq,
1063 BinaryOp::NEq => IrOp::NEq,
1064 BinaryOp::Gt => IrOp::Gt,
1065 BinaryOp::GtE => IrOp::GtE,
1066 BinaryOp::And => IrOp::And,
1067 BinaryOp::Or => IrOp::Or,
1068 BinaryOp::Lt => IrOp::Lt,
1069 BinaryOp::LtE => IrOp::LtE,
1070 BinaryOp::Mod => IrOp::Mod,
1071 };
1072
1073 self.emit_binary(ir_op, lhs, rhs)
1074 }
1075
1076 ExprKind::Call {
1077 callee,
1078 generic_args,
1079 args,
1080 } => {
1081 let arg_values: Vec<Value> =
1082 args.iter().map(|arg| self.gen_expr(arg, None)).collect();
1083
1084 for val in arg_values.iter() {
1085 self.code.push(Instruction::Arg { value: val.clone() });
1086 }
1087
1088 let mut resolved_func_name = callee.value.clone();
1089 let substituted_generic_args: Vec<Type> = generic_args
1090 .iter()
1091 .map(|arg_type| self.substitute_type(arg_type, &self.current_substitutions))
1092 .collect();
1093
1094 if !substituted_generic_args.is_empty() {
1095 for arg_type in &substituted_generic_args {
1096 resolved_func_name.push_str("__");
1097 resolved_func_name.push_str(&self.mangle_type(arg_type));
1098 }
1099 }
1100
1101 if !substituted_generic_args.is_empty()
1102 && !self.instantiated_fns.contains(&resolved_func_name)
1103 {
1104 self.instantiated_fns.insert(resolved_func_name.clone());
1105
1106 self.deferred_instantiations
1107 .push((callee.value.clone(), substituted_generic_args.clone()));
1108
1109 if let Some(Stmt::Function {
1110 generic_params,
1111 rttype,
1112 ..
1113 }) = self.fn_blueprints.get(&callee.value).cloned()
1114 {
1115 let substitutions: HashMap<String, Type> = generic_params
1116 .iter()
1117 .cloned()
1118 .zip(substituted_generic_args.iter().cloned())
1119 .collect();
1120 let unres_ty = rttype.unwrap_or(Type::Void);
1121 let sub_ty = self.substitute_type(&unres_ty, &substitutions);
1122
1123 let old_subs = self.current_substitutions.clone();
1124 self.current_substitutions = substitutions;
1125 let resolved_rttype = self.resolve_type(&sub_ty);
1126 self.current_substitutions = old_subs;
1127
1128 self.var_types
1129 .insert(resolved_func_name.clone(), resolved_rttype);
1130 }
1131 }
1132
1133 let return_ty = self
1134 .var_types
1135 .get(&resolved_func_name)
1136 .cloned()
1137 .unwrap_or(Type::Int);
1138
1139 let dst = self.next_temp_with_type(return_ty);
1140 self.code.push(Instruction::Call {
1141 dest: Some(dst.clone()),
1142 name: resolved_func_name,
1143 argc: arg_values.len(),
1144 });
1145
1146 Value::Temp(dst)
1147 }
1148 }
1149 }
1150
1151 pub fn gen_stmt(&mut self, stmt: &Stmt) {
1152 match stmt {
1153 Stmt::Use { .. } => unreachable!(),
1154
1155 Stmt::Struct {
1156 name,
1157 generic_params,
1158 fields,
1159 } => {
1160 if !generic_params.is_empty() {
1161 self.struct_blueprints
1162 .insert(name.value.clone(), (generic_params.clone(), fields.clone()));
1163 } else {
1164 self.instantiate_struct_layout(name.value.clone(), fields, &HashMap::new());
1165 }
1166 }
1167 Stmt::Constant { .. } => {
1168 }
1170 Stmt::Assignment { ident, vtype, expr } => {
1171 let mangled_name = format!("{}::{}", self.current_function, ident.value);
1172
1173 if let Some(explicit_ty) = vtype {
1174 let resolved = self.resolve_type(explicit_ty);
1175 self.var_types.insert(mangled_name.clone(), resolved);
1176 }
1177
1178 let current_ty = vtype
1179 .clone()
1180 .or_else(|| self.var_types.get(&mangled_name).cloned())
1181 .map(|ty| self.resolve_type(&ty));
1182
1183 let is_array = matches!(current_ty, Some(Type::Array { .. }));
1184
1185 let target_var = Value::Var(mangled_name.clone());
1186
1187 if let Some(expr_node) = expr {
1188 if is_array {
1189 self.gen_expr(expr_node, Some(target_var));
1190 } else {
1191 let value = self.gen_expr(expr_node, None);
1192 if vtype.is_none() {
1193 let computed_ty = self.get_value_type(&value);
1194 let resolved_computed = self.resolve_type(&computed_ty);
1195 self.var_types
1196 .insert(mangled_name.clone(), resolved_computed);
1197 }
1198 self.code.push(Instruction::Assign {
1199 dst: mangled_name,
1200 src: value,
1201 });
1202 }
1203 } else {
1204 match current_ty {
1205 Some(Type::Int) => {
1206 self.code.push(Instruction::Assign {
1207 dst: mangled_name,
1208 src: Value::Const(0),
1209 });
1210 }
1211 Some(Type::Bool) => {
1212 self.code.push(Instruction::Assign {
1213 dst: mangled_name,
1214 src: Value::Bool(false),
1215 });
1216 }
1217 Some(Type::Char) => {
1218 self.code.push(Instruction::Assign {
1219 dst: mangled_name,
1220 src: Value::Char('\0'),
1221 });
1222 }
1223 Some(Type::Str) | Some(Type::Ptr(_)) => {
1224 self.code.push(Instruction::Assign {
1225 dst: mangled_name,
1226 src: Value::Const(0),
1227 });
1228 }
1229 Some(Type::Struct(_)) | Some(Type::Array { .. }) => {
1230 self.code.push(Instruction::Assign {
1231 dst: mangled_name,
1232 src: Value::Const(0),
1233 });
1234 }
1235 _ => {
1236 self.code.push(Instruction::Assign {
1237 dst: mangled_name,
1238 src: Value::Const(0),
1239 });
1240 }
1241 }
1242 }
1243 }
1244 Stmt::Reassignment { ident, expr } => {
1245 let mangled_name = format!("{}::{}", self.current_function, ident.value);
1246 let is_array =
1247 matches!(self.var_types.get(&mangled_name), Some(Type::Array { .. }));
1248 let target_var = Value::Var(mangled_name.clone());
1249
1250 if is_array {
1251 self.gen_expr(expr, Some(target_var));
1252 } else {
1253 let value = self.gen_expr(expr, None);
1254 self.code.push(Instruction::Assign {
1255 dst: mangled_name,
1256 src: value,
1257 });
1258 }
1259 }
1260 Stmt::Expr(expr) => {
1261 if let ExprKind::Call {
1262 callee,
1263 generic_args,
1264 args,
1265 } = &expr.kind
1266 {
1267 let arg_values: Vec<Value> =
1268 args.iter().map(|arg| self.gen_expr(arg, None)).collect();
1269
1270 for val in arg_values.iter() {
1271 self.code.push(Instruction::Arg { value: val.clone() });
1272 }
1273
1274 let mut resolved_func_name = callee.value.clone();
1275 let substituted_generic_args: Vec<Type> = generic_args
1276 .iter()
1277 .map(|arg_type| self.substitute_type(arg_type, &self.current_substitutions))
1278 .collect();
1279
1280 if !substituted_generic_args.is_empty() {
1281 for arg_type in &substituted_generic_args {
1282 resolved_func_name.push_str("__");
1283 resolved_func_name.push_str(&self.mangle_type(arg_type));
1284 }
1285 }
1286
1287 if !substituted_generic_args.is_empty()
1288 && !self.instantiated_fns.contains(&resolved_func_name)
1289 {
1290 self.instantiated_fns.insert(resolved_func_name.clone());
1291 self.deferred_instantiations
1292 .push((callee.value.clone(), substituted_generic_args.clone()));
1293
1294 if let Some(Stmt::Function {
1295 generic_params,
1296 rttype,
1297 ..
1298 }) = self.fn_blueprints.get(&callee.value).cloned()
1299 {
1300 let substitutions: HashMap<String, Type> = generic_params
1301 .iter()
1302 .cloned()
1303 .zip(substituted_generic_args.iter().cloned())
1304 .collect();
1305 let unres_ty = rttype.unwrap_or(Type::Void);
1306 let sub_ty = self.substitute_type(&unres_ty, &substitutions);
1307
1308 let old_subs = self.current_substitutions.clone();
1309 self.current_substitutions = substitutions;
1310 let resolved_rttype = self.resolve_type(&sub_ty);
1311 self.current_substitutions = old_subs;
1312
1313 self.var_types
1314 .insert(resolved_func_name.clone(), resolved_rttype);
1315 }
1316 }
1317
1318 self.code.push(Instruction::Call {
1319 dest: None,
1320 name: resolved_func_name,
1321 argc: arg_values.len(),
1322 });
1323 } else {
1324 self.gen_expr(expr, None);
1325 }
1326 }
1327 Stmt::If {
1328 cond,
1329 then_branch,
1330 else_if_branches,
1331 else_branch,
1332 } => {
1333 let true_end = self.labels.next_label();
1334
1335 let mut next_target = self.labels.next_label();
1336
1337 let cond_val = self.gen_expr(cond, None);
1338 self.code.push(Instruction::JumpIfFalse {
1339 cond: cond_val,
1340 target: next_target.clone(),
1341 });
1342
1343 for stmt in then_branch {
1344 self.gen_stmt(stmt);
1345 }
1346
1347 self.code.push(Instruction::Jump(true_end.clone()));
1348
1349 for (ei_cond, ei_body) in else_if_branches.iter() {
1350 self.code.push(Instruction::Label(next_target));
1351
1352 next_target = self.labels.next_label();
1353
1354 let ei_cond_val = self.gen_expr(ei_cond, None);
1355 self.code.push(Instruction::JumpIfFalse {
1356 cond: ei_cond_val,
1357 target: next_target.clone(),
1358 });
1359
1360 for stmt in ei_body {
1361 self.gen_stmt(stmt);
1362 }
1363
1364 self.code.push(Instruction::Jump(true_end.clone()));
1365 }
1366
1367 if let Some(else_stmts) = else_branch {
1368 self.code.push(Instruction::Label(next_target));
1369 for stmt in else_stmts {
1370 self.gen_stmt(stmt);
1371 }
1372 } else {
1373 if next_target != true_end {
1374 self.code.push(Instruction::Label(next_target));
1375 }
1376 }
1377
1378 self.code.push(Instruction::Label(true_end));
1379 }
1380 Stmt::While { cond, body } => {
1381 let start = self.labels.next_label();
1382 let end = self.labels.next_label();
1383
1384 self.loop_exits.push(end.clone());
1385
1386 self.code.push(Instruction::Label(start.clone()));
1387 let cond_val = self.gen_expr(cond, None);
1388 self.code.push(Instruction::JumpIfFalse {
1389 cond: cond_val,
1390 target: end.clone(),
1391 });
1392
1393 for stmt in body {
1394 self.gen_stmt(stmt);
1395 }
1396
1397 self.loop_exits.pop();
1398 self.code.push(Instruction::Jump(start));
1399 self.code.push(Instruction::Label(end));
1400 }
1401 Stmt::Break { .. } => {
1402 if let Some(exit_label) = self.loop_exits.last().cloned() {
1403 self.code.push(Instruction::Jump(exit_label));
1404 } else {
1405 panic!(
1406 "Internal compiler error: break statement unvalidated by semantic analyzer"
1407 );
1408 }
1409 }
1410 Stmt::For {
1411 init,
1412 cond,
1413 step,
1414 body,
1415 } => {
1416 let start = self.labels.next_label();
1417 let end = self.labels.next_label();
1418
1419 self.gen_stmt(init);
1420 self.code.push(Instruction::Label(start.clone()));
1421 let cond_val = self.gen_expr(cond, None);
1422 self.code.push(Instruction::JumpIfFalse {
1423 cond: cond_val,
1424 target: end.clone(),
1425 });
1426
1427 for stmt in body {
1428 self.gen_stmt(stmt);
1429 }
1430 self.gen_stmt(step);
1431 self.code.push(Instruction::Jump(start));
1432 self.code.push(Instruction::Label(end));
1433 }
1434 Stmt::Function {
1435 name,
1436 generic_params,
1437 params,
1438 body,
1439 rttype,
1440 ..
1441 } => {
1442 if !generic_params.is_empty() {
1443 self.fn_blueprints.insert(name.value.clone(), stmt.clone());
1444 return;
1445 }
1446
1447 let resolved_rttype = rttype
1448 .clone()
1449 .map(|ty| self.resolve_type(&ty))
1450 .unwrap_or(Type::Void);
1451 self.var_types.insert(name.value.clone(), resolved_rttype);
1452
1453 let start = self.functions.next(name.value.clone());
1454 let old_func = self.current_function.clone();
1455 self.current_function = start.clone();
1456
1457 self.var_types.push_scope();
1458
1459 self.code.push(Instruction::FunctionLabel(start.clone()));
1460
1461 for param in params {
1462 if let Some(param_ty) = ¶m.ptype {
1463 let resolved_param_ty = self.resolve_type(param_ty);
1464 let unique_param_name = format!("{}::{}", start, param.name.value);
1465 self.var_types.insert(unique_param_name, resolved_param_ty);
1466 }
1467 self.code.push(Instruction::Param {
1468 p: format!("{}::{}", start, param.name.value),
1469 });
1470 }
1471
1472 for stmt in body {
1473 self.gen_stmt(stmt);
1474 }
1475
1476 if !matches!(body.last(), Some(Stmt::Return { .. })) {
1477 let fallback_val = Value::Void;
1478 self.code.push(Instruction::Return {
1479 value: fallback_val,
1480 });
1481 }
1482
1483 self.var_types.pop_scope();
1484
1485 self.current_function = old_func;
1486 }
1487 Stmt::Return { value, .. } => {
1488 if let Some(expr) = value {
1489 let val = self.gen_expr(expr, None);
1490 self.code.push(Instruction::Return { value: val });
1491 } else {
1492 self.code.push(Instruction::Return { value: Value::Void })
1493 }
1494 }
1495 Stmt::Extern { name, rttype, .. } => {
1496 let return_type = rttype.clone().unwrap_or(Type::Void);
1497 self.var_types.insert(name.value.clone(), return_type);
1498 self.code.push(Instruction::Extern {
1499 fnname: name.value.clone(),
1500 });
1501 }
1502 Stmt::DerefReassignment { target, expr } => {
1503 let value_to_store = self.gen_expr(expr, None);
1504
1505 match &target.kind {
1506 ExprKind::Unary {
1507 op: UnaryOp::Deref,
1508 expr: inner,
1509 } => {
1510 let ptr_val = self.gen_expr(inner, None);
1511 self.code.push(Instruction::Store {
1512 ptr: ptr_val,
1513 source: value_to_store,
1514 });
1515 }
1516
1517 ExprKind::Field { base, field } => {
1518 let base_addr = self.gen_lvalue_addr(base);
1519
1520 let base_type = self.expr_type(base).unwrap_or(Type::Int);
1521 let resolved_base = self.resolve_type(&base_type);
1522
1523 let struct_name = match resolved_base {
1524 Type::Struct(name) => name,
1525 Type::GenericInstance { name, args } => {
1526 let mut mangled_name = name;
1527 for arg in args {
1528 mangled_name.push_str("__");
1529 mangled_name.push_str(&self.mangle_type(&arg));
1530 }
1531 mangled_name
1532 }
1533 _ => panic!(
1534 "ICE: Field assignment on non-struct type. Found: {}",
1535 type_to_string(&base_type)
1536 ),
1537 };
1538
1539 let (offset, field_type) = {
1540 let (offset, unres_field_ty) = self
1541 .struct_defs
1542 .get(&struct_name)
1543 .unwrap_or_else(|| {
1544 panic!(
1545 "ICE: Structural reference layout untracked for '{}'.",
1546 struct_name
1547 )
1548 })
1549 .field_offsets
1550 .get(field)
1551 .map(|(offset, field_ty)| (*offset, field_ty.clone()))
1552 .unwrap_or_else(|| {
1553 panic!(
1554 "ICE: Referenced struct field '{}' does not exist in '{}'.",
1555 field, struct_name
1556 )
1557 });
1558
1559 (offset, self.resolve_type(&unres_field_ty))
1560 };
1561
1562 let field_addr_temp =
1563 self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
1564 self.code.push(Instruction::Binary {
1565 dst: field_addr_temp.clone(),
1566 op: IrOp::Add,
1567 lhs: base_addr,
1568 rhs: Value::Const(offset),
1569 });
1570
1571 self.code.push(Instruction::Store {
1572 ptr: Value::Temp(field_addr_temp),
1573 source: value_to_store,
1574 });
1575 }
1576
1577 ExprKind::Index { base, index } => {
1578 let base_val = self.gen_expr(base, None);
1579 let index_val = self.gen_expr(index, None);
1580
1581 let base_type = self.expr_type(base);
1582 let element_type = match &base_type {
1583 Some(Type::Array { element_type, .. }) => *element_type.clone(),
1584 Some(Type::Ptr(inner)) => match &**inner {
1585 Type::Array { element_type, .. } => *element_type.clone(),
1586 other => other.clone(),
1587 },
1588 _ => Type::Int,
1589 };
1590
1591 let stride = self.element_size(&element_type);
1592
1593 let offset_temp = self.next_temp_with_type(Type::Int);
1594 self.code.push(Instruction::Binary {
1595 dst: offset_temp.clone(),
1596 op: IrOp::Mul,
1597 lhs: index_val,
1598 rhs: Value::Const(stride),
1599 });
1600
1601 let is_base_pointer = match &base.kind {
1602 ExprKind::Identifier(name) => {
1603 matches!(self.var_types.get(name), Some(Type::Ptr(_)))
1604 }
1605 ExprKind::Unary {
1606 op: UnaryOp::Deref, ..
1607 } => true,
1608 _ => false,
1609 };
1610
1611 let target_addr_temp =
1612 self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
1613
1614 if is_base_pointer || matches!(base_type, Some(Type::Ptr(_))) {
1615 self.code.push(Instruction::Binary {
1616 dst: target_addr_temp.clone(),
1617 op: IrOp::Add,
1618 lhs: base_val,
1619 rhs: Value::Temp(offset_temp),
1620 });
1621 } else {
1622 let base_addr_temp =
1623 self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
1624 self.code.push(Instruction::Unary {
1625 dst: base_addr_temp.clone(),
1626 op: IrOp::Ref,
1627 value: base_val,
1628 });
1629 self.code.push(Instruction::Binary {
1630 dst: target_addr_temp.clone(),
1631 op: IrOp::Add,
1632 lhs: Value::Temp(base_addr_temp),
1633 rhs: Value::Temp(offset_temp),
1634 });
1635 }
1636
1637 self.code.push(Instruction::Store {
1638 ptr: Value::Temp(target_addr_temp),
1639 source: value_to_store,
1640 });
1641 }
1642
1643 ExprKind::Identifier(name) => {
1644 let mangled_name = format!("{}::{}", self.current_function, name);
1645 let dst = if self.var_types.get(&mangled_name).is_some() {
1646 mangled_name
1647 } else {
1648 name.clone()
1649 };
1650 self.code.push(Instruction::Assign {
1651 dst,
1652 src: value_to_store,
1653 });
1654 }
1655
1656 _ => {
1657 panic!("Invalid lvalue in DerefReassignment: {:?}", target.kind);
1658 }
1659 }
1660 }
1661 }
1662 }
1663
1664 pub fn gen_param(&mut self, param: &Parameter) {
1665 self.code.push(Instruction::Param {
1666 p: param.name.value.clone(),
1667 });
1668 }
1669
1670 pub fn gen_program(&mut self, program: &Program) {
1671 for stmt in &program.statements {
1672 if !matches!(stmt, Stmt::Function { .. })
1673 && !matches!(stmt, Stmt::Extern { .. })
1674 && !matches!(stmt, Stmt::Struct { .. })
1675 && !matches!(stmt, Stmt::Constant { .. })
1676 {
1677 println!(
1678 "Codegen Error: top-level statement outside of a function is not supported."
1679 );
1680 std::process::exit(1);
1681 }
1682 self.gen_stmt(stmt);
1683 }
1684
1685 while let Some((callee_name, args)) = self.deferred_instantiations.pop() {
1686 if let Some(blueprint) = self.fn_blueprints.get(&callee_name).cloned()
1687 && let Stmt::Function {
1688 name,
1689 generic_params,
1690 params,
1691 body,
1692 rttype,
1693 ..
1694 } = blueprint
1695 {
1696 let mut resolved_func_name = name.value.clone();
1697 for arg_type in &args {
1698 resolved_func_name.push_str("__");
1699 resolved_func_name.push_str(&self.mangle_type(arg_type));
1700 }
1701
1702 let substitutions: HashMap<String, Type> = generic_params
1703 .iter()
1704 .cloned()
1705 .zip(args.iter().cloned())
1706 .collect();
1707
1708 let old_subs = self.current_substitutions.clone();
1709 self.current_substitutions = substitutions;
1710
1711 let old_func = self.current_function.clone();
1712 self.current_function = resolved_func_name.clone();
1713
1714 self.code
1715 .push(Instruction::FunctionLabel(resolved_func_name.clone()));
1716
1717 for param in params {
1718 if let Some(param_ty) = ¶m.ptype {
1719 let resolved_param_ty = self.resolve_type(param_ty);
1720
1721 let unique_param_name =
1722 format!("{}::{}", resolved_func_name, param.name.value);
1723 self.var_types.insert(unique_param_name, resolved_param_ty);
1724 }
1725
1726 self.code.push(Instruction::Param {
1727 p: format!("{}::{}", resolved_func_name, param.name.value),
1728 });
1729 }
1730
1731 for stmt in body {
1732 self.gen_stmt(&stmt);
1733 }
1734
1735 let base_return_ty = rttype.unwrap_or(Type::Void);
1736 let resolved_return_ty = self.resolve_type(&base_return_ty);
1737
1738 if !matches!(self.code.last(), Some(Instruction::Return { .. })) {
1739 let fallback_val = if resolved_return_ty == Type::Void {
1740 Value::Void
1741 } else if matches!(
1742 resolved_return_ty,
1743 Type::Struct(_) | Type::GenericInstance { .. }
1744 ) {
1745 let dummy_dst = self.next_temp_with_type(resolved_return_ty.clone());
1746 Value::Temp(dummy_dst)
1747 } else {
1748 Value::Const(0)
1749 };
1750
1751 self.code.push(Instruction::Return {
1752 value: fallback_val,
1753 });
1754 }
1755
1756 self.current_function = old_func;
1757 self.current_substitutions = old_subs;
1758 }
1759 }
1760 }
1761
1762 pub fn dump(&self) {
1763 for inst in &self.code {
1764 match inst {
1765 Instruction::Assign { dst, src } => println!("{dst} = {:?}", src),
1766 Instruction::Binary { dst, op, lhs, rhs } => {
1767 println!("{dst} = {:?} {:?} {:?}", lhs, op, rhs)
1768 }
1769 Instruction::Unary { dst, op, value } => println!("{dst} = {:?}{:?}", op, value),
1770 Instruction::Label(label) => println!("{label}:"),
1771 Instruction::Jump(label) => println!("goto {label}"),
1772 Instruction::JumpIfFalse { cond, target } => {
1773 println!("ifFalse {:?} goto {target}", cond)
1774 }
1775 Instruction::Param { p } => println!("param {}", p),
1776 Instruction::FunctionLabel(label) => println!("{label}:"),
1777 Instruction::Return { value } => println!("return {:?}", value),
1778 Instruction::Arg { value } => println!("arg {:?}", value),
1779 Instruction::Call { dest, name, argc } => println!(
1780 "call {:?} @ {:?} [arg_count: {}]",
1781 name,
1782 dest.clone().unwrap_or("n/a".to_string()),
1783 argc
1784 ),
1785 Instruction::Extern { fnname } => println!("extern {}", fnname),
1786 Instruction::Store { ptr, source } => println!("store {:?} to *{:?}", source, ptr),
1787 Instruction::Load { dst, ptr, ty } => {
1788 println!("load {:?} [{:?}] from *{:?}", dst, ty, ptr)
1789 }
1790 Instruction::Cast {
1791 dst,
1792 cast_ty,
1793 value,
1794 to_type,
1795 } => println!(
1796 "{dst} = {:?} as {:?} [casttype: {:?}]",
1797 value, to_type, cast_ty
1798 ),
1799 }
1800 }
1801 }
1802}
1803impl Default for IRGen {
1804 fn default() -> Self {
1805 Self::new()
1806 }
1807}