Skip to main content

mysz_core/ir/
irgen.rs

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, // default value, since any is unsafe anyway
300        }
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, // default value, since any is unsafe anyway
336        }
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                    // Pointer to pointer
617                    (Type::Ptr(_), Type::Ptr(_)) => CastType::BitCast,
618
619                    // ptr<char> -> str (they're the exact same, just make sure the ptr<char> has a direct block of characters that end with \0 following it)
620                    (Type::Ptr(_), Type::Str) => CastType::BitCast,
621
622                    // Integer size transformations
623                    (
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                    // Fallback
639                    _ => 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                // Constants are generated at use sites
1169            }
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) = &param.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) = &param.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}