Skip to main content

mysz_core/ir/
irgen.rs

1use std::collections::HashMap;
2
3use indexmap::IndexMap;
4
5use crate::{
6    ir::tac::{CastType, Instruction, IrOp, ScopedMap, Value},
7    parse::parsing::{BinaryOp, Expr, ExprKind, Literal, Parameter, Program, Stmt, Type, UnaryOp},
8    utils::location::Location,
9    utils::typesafe::type_to_string,
10};
11
12use crate::utils::typesafe;
13use crate::utils::typesafe::variadic;
14
15#[derive(Debug, Clone, PartialEq)]
16pub enum ConstVal {
17    Bool(bool),
18    Str(String),
19    Char(char),
20    Int(i64),
21}
22
23pub struct TempGen {
24    counter: usize,
25}
26impl TempGen {
27    pub fn new() -> Self {
28        Self { counter: 0 }
29    }
30    pub fn next_temp(&mut self) -> String {
31        self.counter += 1;
32        format!("t{}", self.counter)
33    }
34}
35impl Default for TempGen {
36    fn default() -> Self {
37        Self::new()
38    }
39}
40
41pub struct LabelGen {
42    counter: usize,
43}
44impl LabelGen {
45    pub fn new() -> Self {
46        Self { counter: 0 }
47    }
48    pub fn next_label(&mut self) -> String {
49        self.counter += 1;
50        format!("L{}", self.counter)
51    }
52}
53impl Default for LabelGen {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58pub struct FunctionGen {
59    counter: usize,
60}
61impl FunctionGen {
62    pub fn new() -> Self {
63        Self { counter: 0 }
64    }
65    pub fn next(&mut self, name: String) -> String {
66        self.counter += 1;
67        name
68    }
69}
70impl Default for FunctionGen {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75#[derive(Debug)]
76pub struct StructLayout {
77    pub total_size: i64,
78    pub alignment: i64,
79    pub field_offsets: IndexMap<String, (i64, Type)>,
80}
81
82pub struct IRGen {
83    pub code: Vec<Instruction>,
84    temps: TempGen,
85    labels: LabelGen,
86    functions: FunctionGen,
87    loop_exits: Vec<String>,
88    pub analyser_constants: HashMap<String, (Type, Expr)>,
89    pub evaluated_constants: HashMap<String, Value>,
90    pub var_types: ScopedMap,
91    pub struct_defs: HashMap<String, StructLayout>,
92    pub struct_blueprints: HashMap<String, (Vec<String>, Vec<Parameter>)>,
93    pub current_function: String,
94
95    pub fn_blueprints: HashMap<String, Stmt>,
96    pub instantiated_fns: std::collections::HashSet<String>,
97    pub deferred_instantiations: Vec<(String, Vec<Type>, Vec<Type>)>, // (callee_name, generic_args, variadic_arg_types)
98    pub current_substitutions: HashMap<String, Type>,
99
100    pub var_aliases: Vec<HashMap<String, String>>,
101}
102
103impl IRGen {
104    pub fn new() -> Self {
105        Self {
106            code: Vec::new(),
107            temps: TempGen::new(),
108            labels: LabelGen::new(),
109            functions: FunctionGen::new(),
110            loop_exits: Vec::new(),
111            struct_defs: HashMap::new(),
112            struct_blueprints: HashMap::new(),
113            var_types: ScopedMap::new(HashMap::new()),
114            current_function: String::new(),
115
116            analyser_constants: HashMap::new(),
117            evaluated_constants: HashMap::new(),
118
119            fn_blueprints: HashMap::new(),
120            instantiated_fns: std::collections::HashSet::new(),
121            deferred_instantiations: Vec::new(),
122            current_substitutions: HashMap::new(),
123
124            var_aliases: vec![HashMap::new()],
125        }
126    }
127    pub fn eval_const(&mut self, expr: &Expr) -> Option<ConstVal> {
128        match &expr.kind {
129            ExprKind::Literal(lit) => match lit {
130                Literal::Int(i) => Some(ConstVal::Int(*i)),
131                Literal::String(s) => Some(ConstVal::Str(s.clone())),
132                Literal::Char(c) => Some(ConstVal::Char(*c)),
133                Literal::Bool(b) => Some(ConstVal::Bool(*b)),
134                _ => None,
135            },
136
137            ExprKind::Typeof { expr: inner } => {
138                let ty = self.type_of_expr(inner)?;
139                Some(ConstVal::Str(typesafe::typeof_string(&ty)))
140            }
141
142            ExprKind::Binary { left, op, right } => {
143                let l = self.eval_const(left)?;
144                let r = self.eval_const(right)?;
145
146                match (op, l, r) {
147                    (BinaryOp::Eq, ConstVal::Str(a), ConstVal::Str(b)) => {
148                        Some(ConstVal::Bool(a == b))
149                    }
150                    (BinaryOp::Eq, ConstVal::Int(a), ConstVal::Int(b)) => {
151                        Some(ConstVal::Bool(a == b))
152                    }
153                    (BinaryOp::Eq, ConstVal::Bool(a), ConstVal::Bool(b)) => {
154                        Some(ConstVal::Bool(a == b))
155                    }
156                    (BinaryOp::Eq, ConstVal::Char(a), ConstVal::Char(b)) => {
157                        Some(ConstVal::Bool(a == b))
158                    }
159
160                    (BinaryOp::NEq, ConstVal::Str(a), ConstVal::Str(b)) => {
161                        Some(ConstVal::Bool(a != b))
162                    }
163                    (BinaryOp::NEq, ConstVal::Int(a), ConstVal::Int(b)) => {
164                        Some(ConstVal::Bool(a != b))
165                    }
166                    (BinaryOp::NEq, ConstVal::Bool(a), ConstVal::Bool(b)) => {
167                        Some(ConstVal::Bool(a != b))
168                    }
169                    (BinaryOp::NEq, ConstVal::Char(a), ConstVal::Char(b)) => {
170                        Some(ConstVal::Bool(a != b))
171                    }
172
173                    (BinaryOp::And, ConstVal::Bool(a), ConstVal::Bool(b)) => {
174                        Some(ConstVal::Bool(a && b))
175                    }
176                    (BinaryOp::Or, ConstVal::Bool(a), ConstVal::Bool(b)) => {
177                        Some(ConstVal::Bool(a || b))
178                    }
179
180                    (BinaryOp::Gt, ConstVal::Int(a), ConstVal::Int(b)) => {
181                        Some(ConstVal::Bool(a > b))
182                    }
183                    (BinaryOp::GtE, ConstVal::Int(a), ConstVal::Int(b)) => {
184                        Some(ConstVal::Bool(a >= b))
185                    }
186                    (BinaryOp::Lt, ConstVal::Int(a), ConstVal::Int(b)) => {
187                        Some(ConstVal::Bool(a < b))
188                    }
189                    (BinaryOp::LtE, ConstVal::Int(a), ConstVal::Int(b)) => {
190                        Some(ConstVal::Bool(a <= b))
191                    }
192                    (BinaryOp::Add, ConstVal::Int(a), ConstVal::Int(b)) => {
193                        Some(ConstVal::Int(a + b))
194                    }
195                    (BinaryOp::Sub, ConstVal::Int(a), ConstVal::Int(b)) => {
196                        Some(ConstVal::Int(a - b))
197                    }
198                    (BinaryOp::Mul, ConstVal::Int(a), ConstVal::Int(b)) => {
199                        Some(ConstVal::Int(a * b))
200                    }
201                    (BinaryOp::Div, ConstVal::Int(a), ConstVal::Int(b)) => {
202                        if b == 0 {
203                            None
204                        } else {
205                            Some(ConstVal::Int(a / b))
206                        }
207                    }
208                    (BinaryOp::Mod, ConstVal::Int(a), ConstVal::Int(b)) => {
209                        if b == 0 {
210                            None
211                        } else {
212                            Some(ConstVal::Int(a % b))
213                        }
214                    }
215
216                    _ => None,
217                }
218            }
219
220            _ => None,
221        }
222    }
223
224    pub fn type_of_expr(&self, expr: &Expr) -> Option<Type> {
225        match &expr.kind {
226            ExprKind::Literal(lit) => match lit {
227                Literal::Int(_) => Some(Type::Int),
228                Literal::String(_) => Some(Type::Str),
229                Literal::Char(_) => Some(Type::Char),
230                Literal::Bool(_) => Some(Type::Bool),
231                Literal::Arr { elements } => {
232                    let elem_type = elements.first().and_then(|e| self.type_of_expr(e))?;
233                    Some(Type::Array {
234                        element_type: Box::new(elem_type),
235                        size: elements.len(),
236                    })
237                }
238            },
239
240            ExprKind::Identifier(name) => {
241                let resolved = self.resolve_var_name(name);
242
243                if let Some(ty) = self.var_types.get(&resolved) {
244                    return Some(ty.clone());
245                }
246
247                if let Some(ty) = self.var_types.get(name) {
248                    return Some(ty.clone());
249                }
250
251                None
252            }
253
254            ExprKind::Cast { right, .. } => Some(right.clone()),
255
256            ExprKind::Binary { op, left, .. } => match op {
257                BinaryOp::Eq
258                | BinaryOp::NEq
259                | BinaryOp::Gt
260                | BinaryOp::GtE
261                | BinaryOp::Lt
262                | BinaryOp::LtE
263                | BinaryOp::And
264                | BinaryOp::Or => Some(Type::Bool),
265                _ => self.type_of_expr(left),
266            },
267
268            ExprKind::Unary { op, expr } => match op {
269                UnaryOp::Not => Some(Type::Bool),
270                UnaryOp::AddressOf => {
271                    let inner_ty = self.type_of_expr(expr)?;
272                    Some(Type::Ptr(Box::new(inner_ty)))
273                }
274                UnaryOp::Deref => {
275                    if let Some(Type::Ptr(inner_ty)) = self.type_of_expr(expr) {
276                        Some(*inner_ty)
277                    } else {
278                        None
279                    }
280                }
281                _ => self.type_of_expr(expr),
282            },
283
284            ExprKind::Typeof { .. } => Some(Type::Str),
285
286            ExprKind::Field { base, field } => {
287                let base_ty = self.type_of_expr(base)?;
288
289                let struct_name = match base_ty {
290                    Type::Struct(name) => name,
291
292                    Type::GenericInstance { name, args } => {
293                        let mut mangled_name = name;
294
295                        for arg in args {
296                            mangled_name.push_str("__");
297                            mangled_name.push_str(&self.mangle_type(&arg));
298                        }
299
300                        mangled_name
301                    }
302
303                    _ => return None,
304                };
305
306                self.struct_defs
307                    .get(&struct_name)
308                    .and_then(|layout| layout.field_offsets.get(field))
309                    .map(|(_, ty)| ty.clone())
310            }
311
312            _ => None,
313        }
314    }
315
316    pub fn next_temp_with_type(&mut self, ty: Type) -> String {
317        let base_name = self.temps.next_temp();
318        let qualified_name = if self.current_function.is_empty() {
319            base_name
320        } else {
321            format!("{}::{}", self.current_function, base_name)
322        };
323        self.var_types.insert(qualified_name.clone(), ty);
324        qualified_name
325    }
326
327    fn resolve_var_name(&self, name: &str) -> String {
328        if let Some(aliased) = self.var_aliases.iter().rev().find_map(|s| s.get(name)) {
329            return aliased.clone();
330        }
331
332        let local_mangled = format!("{}::{}", self.current_function, name);
333        if self.var_types.get(&local_mangled).is_some() {
334            return local_mangled;
335        }
336
337        name.to_string()
338    }
339
340    fn substitute_type(&self, ty: &Type, substitutions: &HashMap<String, Type>) -> Type {
341        match ty {
342            Type::Struct(name) => substitutions
343                .get(name)
344                .cloned()
345                .unwrap_or(Type::Struct(name.clone())),
346
347            Type::Ptr(inner) => Type::Ptr(Box::new(self.substitute_type(inner, substitutions))),
348
349            Type::Array { element_type, size } => Type::Array {
350                element_type: Box::new(self.substitute_type(element_type, substitutions)),
351                size: *size,
352            },
353
354            Type::GenericInstance { name, args } => Type::GenericInstance {
355                name: name.clone(),
356                args: args
357                    .iter()
358                    .map(|arg| self.substitute_type(arg, substitutions))
359                    .collect(),
360            },
361            Type::GenericParam(name) => substitutions
362                .get(name)
363                .cloned()
364                .unwrap_or_else(|| panic!("Unresolved generic parameter: {}", name)),
365
366            Type::VariadicPack { .. } => {
367                panic!(
368                    "ICE: VariadicPack reached substitute_type: it should have been resolved to a concrete __variadic__ struct before codegen substitution."
369                )
370            }
371
372            Type::Int
373            | Type::UInt
374            | Type::Int8
375            | Type::UInt8
376            | Type::Bool
377            | Type::Str
378            | Type::Char
379            | Type::Void
380            | Type::Any => ty.clone(),
381        }
382    }
383
384    fn mangle_type(&self, ty: &Type) -> String {
385        crate::utils::typesafe::type_to_mangled_string(ty)
386    }
387
388    fn mangle_call_name(
389        &self,
390        base: &str,
391        generic_args: &[Type],
392        variadic_args: &[Type],
393        is_variadic_capable: bool,
394    ) -> String {
395        let mut name = base.to_string();
396        for arg in generic_args {
397            name.push_str("__");
398            name.push_str(&self.mangle_type(arg));
399        }
400        if is_variadic_capable {
401            name.push('.');
402            name.push_str(
403                &variadic_args
404                    .iter()
405                    .map(|t| self.mangle_type(t))
406                    .collect::<Vec<_>>()
407                    .join("__"),
408            );
409        }
410        name
411    }
412
413    /// Builds the layout for a variadic argument pack.
414    ///
415    /// This defers entirely to `typesafe::variadic::structure` — the same
416    /// function the analyser uses to type-check field access on a
417    /// `VariadicPack` (e.g. `pack.i0`, `pack.il`) — so the fields the
418    /// analyser considers valid and the fields actually laid out in memory
419    /// here can never drift apart. Field names/order come from that single
420    /// source of truth instead of being duplicated as ad-hoc strings.
421    fn instantiate_variadic_struct(
422        &mut self,
423        struct_name: &str,
424        arg_types: &[Type],
425        location: Location,
426    ) {
427        if self.struct_defs.contains_key(struct_name) {
428            return;
429        }
430
431        let signature = variadic::structure(arg_types, location);
432
433        let mut offset: i64 = 0;
434        let mut max_align: i64 = 1;
435        let mut field_offsets = IndexMap::new();
436
437        for (field_name, ty) in signature.fields.iter() {
438            let size = self.type_size(ty);
439            let align = self.type_alignment(ty);
440            if align > max_align {
441                max_align = align;
442            }
443            offset = (offset + align - 1) & !(align - 1);
444            field_offsets.insert(field_name.clone(), (offset, ty.clone()));
445            offset += size;
446        }
447
448        let total_size = (offset + max_align - 1) & !(max_align - 1);
449
450        self.struct_defs.insert(
451            struct_name.to_string(),
452            StructLayout {
453                total_size,
454                alignment: max_align,
455                field_offsets,
456            },
457        );
458    }
459
460    pub fn resolve_type(&mut self, ty: &Type) -> Type {
461        let substituted = if !self.current_substitutions.is_empty() {
462            self.substitute_type(ty, &self.current_substitutions.clone())
463        } else {
464            ty.clone()
465        };
466
467        if substituted != *ty {
468            return self.resolve_type(&substituted);
469        }
470
471        match substituted {
472            Type::GenericInstance { name, args } => {
473                let resolved_args: Vec<Type> =
474                    args.iter().map(|arg| self.resolve_type(arg)).collect();
475
476                let mut mangled_name = name.clone();
477                for arg in &resolved_args {
478                    mangled_name.push_str("__");
479                    mangled_name.push_str(&self.mangle_type(arg));
480                }
481
482                if !self.struct_defs.contains_key(&mangled_name)
483                    && let Some((params, fields)) = self.struct_blueprints.get(&name).cloned()
484                {
485                    let substitutions: HashMap<String, Type> =
486                        params.into_iter().zip(resolved_args).collect();
487
488                    self.instantiate_struct_layout(mangled_name.clone(), &fields, &substitutions);
489                }
490                Type::Struct(mangled_name)
491            }
492            Type::Ptr(inner) => Type::Ptr(Box::new(self.resolve_type(&inner))),
493            Type::Array { element_type, size } => Type::Array {
494                element_type: Box::new(self.resolve_type(&element_type)),
495                size,
496            },
497            _ => substituted,
498        }
499    }
500
501    fn instantiate_struct_layout(
502        &mut self,
503        mangled_name: String,
504        fields: &[Parameter],
505        substitutions: &HashMap<String, Type>,
506    ) {
507        let mut current_offset: i64 = 0;
508        let mut max_alignment: i64 = 1;
509        let mut field_offsets = IndexMap::new();
510
511        for field in fields {
512            let field_name = field.name.value.clone();
513            let base_type = field.ptype.clone().unwrap_or(Type::Int);
514
515            let substituted = self.substitute_type(&base_type, substitutions);
516            let field_type = self.resolve_type(&substituted);
517
518            let field_size = self.type_size(&field_type);
519            let field_align = self.type_alignment(&field_type);
520
521            if field_align > max_alignment {
522                max_alignment = field_align;
523            }
524
525            current_offset = (current_offset + field_align - 1) & !(field_align - 1);
526            field_offsets.insert(field_name, (current_offset, field_type));
527            current_offset += field_size;
528        }
529
530        let total_size = (current_offset + max_alignment - 1) & !(max_alignment - 1);
531        self.struct_defs.insert(
532            mangled_name.clone(),
533            StructLayout {
534                total_size,
535                alignment: max_alignment,
536                field_offsets,
537            },
538        );
539    }
540
541    fn get_struct_layout(&self, name: &str) -> Option<&StructLayout> {
542        if let Some(layout) = self.struct_defs.get(name) {
543            return Some(layout);
544        }
545        if let Some(base_name) = name.split("__").next() {
546            for (key, layout) in &self.struct_defs {
547                if key == base_name || key.starts_with(&format!("{}__", base_name)) {
548                    return Some(layout);
549                }
550            }
551        }
552        None
553    }
554
555    fn get_value_type(&self, value: &Value) -> Type {
556        match value {
557            Value::Temp(name) | Value::Var(name) => {
558                self.var_types.get(name).cloned().unwrap_or(Type::Int)
559            }
560            Value::Const(_) => Type::Int,
561            Value::Bool(_) => Type::Bool,
562            Value::Char(_) => Type::Char,
563            Value::Str(_) => Type::Str,
564            Value::Void => Type::Void,
565        }
566    }
567
568    fn type_size(&self, ty: &Type) -> i64 {
569        match ty {
570            Type::Int | Type::UInt => 8,
571            Type::Int8 | Type::UInt8 => 1,
572            Type::Bool => 1,
573            Type::Str => 8,
574            Type::Ptr(_) => 8,
575            Type::Array { element_type, size } => self.element_size(element_type) * (*size as i64),
576            Type::GenericParam(name) => {
577                panic!("Cannot get size of unresolved generic parameter: {}", name)
578            }
579            Type::Char => 1,
580            Type::Struct(name) => self
581                .get_struct_layout(name)
582                .map(|l| l.total_size)
583                .unwrap_or_else(|| panic!("Failed to find layout for struct: {name}")),
584            Type::GenericInstance { name, args } => {
585                let mut mangled_name = name.clone();
586                for arg in args {
587                    mangled_name.push_str("__");
588                    mangled_name.push_str(&self.mangle_type(arg));
589                }
590                self.get_struct_layout(&mangled_name)
591                    .map(|l| l.total_size)
592                    .unwrap_or_else(|| {
593                        panic!("Failed to find layout for generic instance: {mangled_name}")
594                    })
595            }
596            Type::VariadicPack { .. } => {
597                panic!(
598                    "ICE: VariadicPack reached type_size: it should have been resolved to a concrete __variadic__ struct before size queries."
599                )
600            }
601
602            Type::Void => 0,
603            Type::Any => 8, // default value, since any is unsafe anyway
604        }
605    }
606
607    fn type_alignment(&self, ty: &Type) -> i64 {
608        match ty {
609            Type::Int | Type::UInt => 8,
610            Type::Int8 | Type::UInt8 => 1,
611            Type::Bool => 1,
612            Type::GenericParam(name) => {
613                panic!(
614                    "Cannot get alignment of unresolved generic parameter: {}",
615                    name
616                )
617            }
618            Type::Char => 1,
619            Type::Str => 8,
620            Type::Ptr(_) => 8,
621            Type::Array { element_type, .. } => self.type_alignment(element_type),
622            Type::Struct(name) => self
623                .get_struct_layout(name)
624                .map(|l| l.alignment)
625                .unwrap_or_else(|| panic!("Failed to find layout for struct: {name}")),
626            Type::GenericInstance { name, args } => {
627                let mut mangled_name = name.clone();
628                for arg in args {
629                    mangled_name.push_str("__");
630                    mangled_name.push_str(&self.mangle_type(arg));
631                }
632                self.get_struct_layout(&mangled_name)
633                    .map(|l| l.alignment)
634                    .unwrap_or_else(|| {
635                        panic!("Failed to find layout for generic instance: {mangled_name}")
636                    })
637            }
638            Type::VariadicPack { .. } => {
639                panic!(
640                    "ICE: VariadicPack reached type_alignment: it should have been resolved to a concrete __variadic__ struct before alignment queries."
641                )
642            }
643            Type::Void => 0,
644            Type::Any => 8,
645        }
646    }
647
648    fn element_size(&self, ty: &Type) -> i64 {
649        self.type_size(ty)
650    }
651
652    fn emit_binary(&mut self, op: IrOp, lhs: Value, rhs: Value) -> Value {
653        let lhs_ty = self.get_value_type(&lhs);
654        let rhs_ty = self.get_value_type(&rhs);
655
656        let result_ty = match op {
657            IrOp::Add | IrOp::Sub | IrOp::Mul | IrOp::Div | IrOp::Mod => {
658                if lhs_ty == Type::Str || rhs_ty == Type::Str {
659                    Type::Str
660                } else {
661                    Type::Int
662                }
663            }
664            IrOp::Eq | IrOp::NEq | IrOp::Gt | IrOp::GtE | IrOp::Lt | IrOp::LtE => Type::Bool,
665            _ => Type::Int,
666        };
667
668        let temp = self.next_temp_with_type(result_ty);
669        self.code.push(Instruction::Binary {
670            dst: temp.clone(),
671            op,
672            lhs,
673            rhs,
674        });
675        Value::Temp(temp)
676    }
677
678    fn emit_unary(&mut self, op: IrOp, value: Value) -> Value {
679        let inner_ty = self.get_value_type(&value);
680
681        let result_ty = match op {
682            IrOp::Pos | IrOp::Neg => inner_ty,
683            IrOp::Ref => Type::Ptr(Box::new(inner_ty)),
684            _ => Type::Int,
685        };
686
687        let temp = self.next_temp_with_type(result_ty);
688        self.code.push(Instruction::Unary {
689            dst: temp.clone(),
690            op,
691            value,
692        });
693        Value::Temp(temp)
694    }
695
696    fn is_string_valued(&self, value: &Value) -> bool {
697        matches!(value, Value::Str(_))
698    }
699
700    pub fn expr_type(&mut self, expr: &Expr) -> Option<Type> {
701        match &expr.kind {
702            ExprKind::Cast { left: _, right } => Some(right.clone()),
703            ExprKind::Sizeof { .. } => Some(Type::Int),
704            ExprKind::Typeof { .. } => Some(Type::Str),
705            ExprKind::Literal(Literal::String(_)) => Some(Type::Str),
706            ExprKind::Literal(Literal::Int(_)) => Some(Type::Int),
707            ExprKind::Literal(Literal::Bool(_)) => Some(Type::Bool),
708            ExprKind::Literal(Literal::Char(_)) => Some(Type::Char),
709            ExprKind::Literal(Literal::Arr { elements }) => {
710                if !elements.is_empty() {
711                    let element_type = self.expr_type(&elements[0])?;
712                    Some(Type::Array {
713                        element_type: Box::new(element_type),
714                        size: elements.len(),
715                    })
716                } else {
717                    Some(Type::Array {
718                        element_type: Box::new(Type::Int),
719                        size: 0,
720                    })
721                }
722            }
723            ExprKind::Identifier(name) => {
724                let local_mangled = format!("{}::{}", self.current_function, name);
725                if let Some(ty) = self.var_types.get(&local_mangled).cloned() {
726                    return Some(self.resolve_type(&ty));
727                }
728                if let Some((ty, _)) = self.analyser_constants.get(name) {
729                    let ty = ty.clone();
730                    return Some(self.resolve_type(&ty));
731                }
732                if let Some(ty) = self.var_types.get(name).cloned() {
733                    return Some(self.resolve_type(&ty));
734                }
735                None
736            }
737            ExprKind::Binary { left, op, .. } => match op {
738                BinaryOp::Eq
739                | BinaryOp::NEq
740                | BinaryOp::Gt
741                | BinaryOp::GtE
742                | BinaryOp::Lt
743                | BinaryOp::LtE => Some(Type::Bool),
744                _ => self.expr_type(left),
745            },
746            ExprKind::Call { .. } => None,
747
748            ExprKind::Index { base, .. } => match self.expr_type(base)? {
749                Type::Array { element_type, .. } => Some(*element_type),
750                Type::Str => Some(Type::Char),
751                Type::Ptr(inner) => match *inner {
752                    Type::Array { element_type, .. } => Some(*element_type),
753                    other => Some(other),
754                },
755                _ => None,
756            },
757
758            ExprKind::Unary {
759                op,
760                expr: inner_expr,
761            } => {
762                let inner_type = self.expr_type(inner_expr)?;
763                match op {
764                    UnaryOp::AddressOf => Some(Type::Ptr(Box::new(inner_type))),
765                    UnaryOp::Deref => match inner_type {
766                        Type::Ptr(inner) => Some(*inner),
767                        _ => None,
768                    },
769                    UnaryOp::Positive | UnaryOp::Negative => Some(Type::Int),
770                    UnaryOp::Not => Some(Type::Bool),
771                }
772            }
773            ExprKind::Field { base, field } => {
774                if let Some(base_ty) = self.expr_type(base) {
775                    let struct_name = match self.resolve_type(&base_ty) {
776                        Type::Struct(name) => Some(name),
777                        Type::GenericInstance { name, args } => {
778                            let mut mangled_name = name;
779                            for arg in args {
780                                mangled_name.push_str("__");
781                                mangled_name.push_str(&self.mangle_type(&arg));
782                            }
783                            Some(mangled_name)
784                        }
785                        _ => None,
786                    };
787
788                    if let Some(name) = struct_name {
789                        let found_field_ty = self
790                            .get_struct_layout(&name)
791                            .and_then(|layout| layout.field_offsets.get(field))
792                            .map(|(_, field_ty)| field_ty.clone());
793
794                        if let Some(field_ty) = found_field_ty {
795                            return Some(self.resolve_type(&field_ty));
796                        }
797                    }
798                }
799                None
800            }
801            ExprKind::StructLiteral { struct_name, .. } => Some(Type::Struct(struct_name.clone())),
802        }
803    }
804
805    fn gen_call(
806        &mut self,
807        callee: &crate::parse::parsing::Identifier,
808        generic_args: &[Type],
809        args: &[Expr],
810        want_result: bool,
811    ) -> Option<Value> {
812        let blueprint = self.fn_blueprints.get(&callee.value).cloned();
813
814        let (generic_params, fixed_param_count, is_variadic_capable) =
815            if let Some(Stmt::Function {
816                generic_params,
817                params,
818                ..
819            }) = &blueprint
820            {
821                let fixed = params.iter().filter(|p| !p.is_variadic).count();
822                let variadic = params.iter().any(|p| p.is_variadic);
823                (generic_params.clone(), fixed, variadic)
824            } else {
825                (Vec::new(), args.len(), false)
826            };
827
828        let substituted_generic_args: Vec<Type> = generic_args
829            .iter()
830            .map(|t| self.substitute_type(t, &self.current_substitutions))
831            .collect();
832
833        let split_at = fixed_param_count.min(args.len());
834        let (fixed_arg_exprs, variadic_arg_exprs) = if is_variadic_capable {
835            args.split_at(split_at)
836        } else {
837            (args, &args[args.len()..])
838        };
839
840        let mut arg_values: Vec<Value> = fixed_arg_exprs
841            .iter()
842            .map(|a| self.gen_expr(a, None))
843            .collect();
844
845        let mut variadic_types = Vec::new();
846        let mut variadic_values = Vec::new();
847        for a in variadic_arg_exprs {
848            let v = self.gen_expr(a, None);
849            let t = self.expr_type(a).unwrap_or(Type::Int);
850            variadic_types.push(t);
851            variadic_values.push(v);
852        }
853
854        let resolved_func_name = self.mangle_call_name(
855            &callee.value,
856            &substituted_generic_args,
857            &variadic_types,
858            is_variadic_capable,
859        );
860
861        if is_variadic_capable {
862            let struct_name = format!("__variadic__{}", resolved_func_name);
863            self.instantiate_variadic_struct(
864                &struct_name,
865                &variadic_types,
866                callee.location.clone(),
867            );
868
869            let raw = self.temps.next_temp();
870            let pack_var = format!("_anon_struct_{}", raw);
871
872            let pack_type = Type::Struct(struct_name.clone());
873
874            self.var_types.insert(pack_var.clone(), pack_type.clone());
875
876            let variadic_len = variadic_values.len() as i64;
877
878            let store_field = |irgen: &mut Self, field_name: &str, val: Value| {
879                let (offset, field_ty) =
880                    irgen.struct_defs[&struct_name].field_offsets[field_name].clone();
881
882                let base_addr_temp = irgen
883                    .next_temp_with_type(Type::Ptr(Box::new(Type::Struct(struct_name.clone()))));
884                irgen.code.push(Instruction::Unary {
885                    dst: base_addr_temp.clone(),
886                    op: IrOp::Ref,
887                    value: Value::Var(pack_var.clone()),
888                });
889
890                let slot_addr_temp = irgen.next_temp_with_type(Type::Ptr(Box::new(field_ty)));
891                irgen.code.push(Instruction::Binary {
892                    dst: slot_addr_temp.clone(),
893                    op: IrOp::Add,
894                    lhs: Value::Temp(base_addr_temp),
895                    rhs: Value::Const(offset),
896                });
897
898                irgen.code.push(Instruction::Store {
899                    ptr: Value::Temp(slot_addr_temp),
900                    source: val,
901                });
902            };
903
904            for (i, val) in variadic_values.into_iter().enumerate() {
905                store_field(self, &variadic::field_name(i), val);
906            }
907            store_field(self, variadic::length_field(), Value::Const(variadic_len));
908
909            arg_values.push(Value::Var(pack_var));
910        }
911
912        for v in &arg_values {
913            self.code.push(Instruction::Arg { value: v.clone() });
914        }
915
916        if blueprint.is_some() && !self.instantiated_fns.contains(&resolved_func_name) {
917            self.instantiated_fns.insert(resolved_func_name.clone());
918            self.deferred_instantiations.push((
919                callee.value.clone(),
920                substituted_generic_args.clone(),
921                variadic_types.clone(),
922            ));
923
924            if let Some(Stmt::Function { rttype, .. }) = &blueprint {
925                let substitutions: HashMap<String, Type> = generic_params
926                    .iter()
927                    .cloned()
928                    .zip(substituted_generic_args.iter().cloned())
929                    .collect();
930                let unres_ty = rttype.clone().unwrap_or(Type::Void);
931                let sub_ty = self.substitute_type(&unres_ty, &substitutions);
932
933                let old_subs = self.current_substitutions.clone();
934                self.current_substitutions = substitutions;
935                let resolved_rttype = self.resolve_type(&sub_ty);
936                self.current_substitutions = old_subs;
937
938                self.var_types
939                    .insert(resolved_func_name.clone(), resolved_rttype);
940            }
941        }
942
943        let return_ty = self
944            .var_types
945            .get(&resolved_func_name)
946            .cloned()
947            .unwrap_or(Type::Int);
948
949        if want_result {
950            let dst = self.next_temp_with_type(return_ty);
951            self.code.push(Instruction::Call {
952                dest: Some(dst.clone()),
953                name: resolved_func_name,
954                argc: arg_values.len(),
955            });
956            Some(Value::Temp(dst))
957        } else {
958            self.code.push(Instruction::Call {
959                dest: None,
960                name: resolved_func_name,
961                argc: arg_values.len(),
962            });
963            None
964        }
965    }
966
967    fn gen_lvalue_addr(&mut self, expr: &Expr) -> Value {
968        match &expr.kind {
969            ExprKind::Identifier(name) => {
970                let resolved_name = self.resolve_var_name(name);
971
972                let ty = self
973                    .var_types
974                    .get(&resolved_name)
975                    .cloned()
976                    .unwrap_or(Type::Int);
977
978                let temp = self.next_temp_with_type(Type::Ptr(Box::new(ty)));
979
980                self.code.push(Instruction::Unary {
981                    dst: temp.clone(),
982                    op: IrOp::Ref,
983                    value: Value::Var(resolved_name),
984                });
985
986                Value::Temp(temp)
987            }
988
989            ExprKind::Unary {
990                op: UnaryOp::Deref,
991                expr: inner,
992            } => self.gen_expr(inner, None),
993
994            ExprKind::Field { base, field } => {
995                let base_addr = self.gen_lvalue_addr(base);
996
997                let base_type = self.expr_type(base).unwrap_or(Type::Int);
998                let resolved_base = self.resolve_type(&base_type);
999
1000                let struct_name = match resolved_base {
1001                    Type::Struct(name) => name,
1002                    Type::GenericInstance { name, args } => {
1003                        let mut mangled_name = name;
1004                        for arg in args {
1005                            mangled_name.push_str("__");
1006                            mangled_name.push_str(&self.mangle_type(&arg));
1007                        }
1008                        mangled_name
1009                    }
1010                    _ => panic!(
1011                        "Field access on non-struct type: {}",
1012                        type_to_string(&base_type)
1013                    ),
1014                };
1015
1016                let (offset, field_type) = {
1017                    let (offset, unres_field_ty) = self
1018                        .struct_defs
1019                        .get(&struct_name)
1020                        .unwrap_or_else(|| panic!("Struct layout not found: {}", struct_name))
1021                        .field_offsets
1022                        .get(field)
1023                        .map(|(offset, field_ty)| (*offset, field_ty.clone()))
1024                        .unwrap_or_else(|| {
1025                            panic!("Field '{}' not found in struct '{}'", field, struct_name)
1026                        });
1027
1028                    (offset, self.resolve_type(&unres_field_ty))
1029                };
1030
1031                let field_addr_temp = self.next_temp_with_type(Type::Ptr(Box::new(field_type)));
1032                self.code.push(Instruction::Binary {
1033                    dst: field_addr_temp.clone(),
1034                    op: IrOp::Add,
1035                    lhs: base_addr,
1036                    rhs: Value::Const(offset),
1037                });
1038
1039                Value::Temp(field_addr_temp)
1040            }
1041
1042            ExprKind::Index { base, index } => {
1043                let base_addr = self.gen_lvalue_addr(base);
1044                let index_val = self.gen_expr(index, None);
1045
1046                let base_type = self.expr_type(base);
1047                let element_type = match &base_type {
1048                    Some(Type::Array { element_type, .. }) => *element_type.clone(),
1049                    Some(Type::Ptr(inner)) => match &**inner {
1050                        Type::Array { element_type, .. } => *element_type.clone(),
1051                        other => other.clone(),
1052                    },
1053                    Some(Type::Str) => Type::Char,
1054                    _ => Type::Int,
1055                };
1056
1057                let stride = self.element_size(&element_type);
1058
1059                let offset_temp = self.next_temp_with_type(Type::Int);
1060                self.code.push(Instruction::Binary {
1061                    dst: offset_temp.clone(),
1062                    op: IrOp::Mul,
1063                    lhs: index_val,
1064                    rhs: Value::Const(stride),
1065                });
1066
1067                let elem_addr_temp = self.next_temp_with_type(Type::Ptr(Box::new(element_type)));
1068                self.code.push(Instruction::Binary {
1069                    dst: elem_addr_temp.clone(),
1070                    op: IrOp::Add,
1071                    lhs: base_addr,
1072                    rhs: Value::Temp(offset_temp),
1073                });
1074
1075                Value::Temp(elem_addr_temp)
1076            }
1077
1078            _ => {
1079                panic!("Cannot take address of: {:?}", expr.kind);
1080            }
1081        }
1082    }
1083
1084    pub fn gen_expr(&mut self, expr: &Expr, target_dest: Option<Value>) -> Value {
1085        match &expr.kind {
1086            ExprKind::Sizeof { ty } => {
1087                let resolved_ty = self.resolve_type(ty);
1088                let size = self.type_size(&resolved_ty);
1089                Value::Const(size)
1090            }
1091            ExprKind::Typeof { expr } => {
1092                let resolved_expr = self.expr_type(expr);
1093                if let Some(rexpr) = resolved_expr {
1094                    let etype = typesafe::typeof_string(&rexpr);
1095                    return Value::Str(etype);
1096                }
1097
1098                panic!("ICE: typeof statement cannot resolve expression.")
1099            }
1100
1101            ExprKind::Cast { left, right } => {
1102                let val_to_cast = self.gen_expr(left, None);
1103
1104                let from_type = self.expr_type(left).unwrap_or(Type::Int);
1105                let to_type = self.resolve_type(right);
1106
1107                let cast_kind = match (&from_type, &to_type) {
1108                    // Pointer to pointer
1109                    (Type::Ptr(_), Type::Ptr(_)) => CastType::BitCast,
1110
1111                    // 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)
1112                    (Type::Ptr(_), Type::Str) => CastType::BitCast,
1113
1114                    // Integer size transformations
1115                    (
1116                        Type::Int | Type::UInt | Type::Int8 | Type::UInt8,
1117                        Type::Int | Type::UInt | Type::Int8 | Type::UInt8,
1118                    ) => {
1119                        let from_size = self.type_size(&from_type);
1120                        let to_size = self.type_size(&to_type);
1121                        if from_size < to_size {
1122                            CastType::Extend
1123                        } else if from_size > to_size {
1124                            CastType::Truncate
1125                        } else {
1126                            CastType::BitCast
1127                        }
1128                    }
1129
1130                    // Fallback
1131                    _ => CastType::BitCast,
1132                };
1133
1134                let result_temp = self.next_temp_with_type(to_type.clone());
1135
1136                self.code.push(Instruction::Cast {
1137                    dst: result_temp.clone(),
1138                    cast_ty: cast_kind,
1139                    value: val_to_cast,
1140                    to_type,
1141                });
1142
1143                Value::Temp(result_temp)
1144            }
1145
1146            ExprKind::Literal(lit) => match lit {
1147                Literal::Int(v) => Value::Const(*v),
1148                Literal::String(s) => Value::Str(s.clone()),
1149                Literal::Bool(b) => Value::Bool(*b),
1150                Literal::Char(c) => Value::Char(*c),
1151                Literal::Arr { elements } => {
1152                    let element_type = if !elements.is_empty() {
1153                        self.expr_type(&elements[0]).unwrap_or(Type::Int)
1154                    } else {
1155                        Type::Int
1156                    };
1157                    let stride = self.element_size(&element_type);
1158
1159                    let base_val = match target_dest {
1160                        Some(dest) => dest,
1161                        None => {
1162                            let raw_temp = self.temps.next_temp();
1163                            let anon_name = format!("_anon_{}", raw_temp);
1164                            self.var_types.insert(
1165                                anon_name.clone(),
1166                                Type::Array {
1167                                    element_type: Box::new(element_type.clone()),
1168                                    size: elements.len(),
1169                                },
1170                            );
1171                            Value::Var(anon_name)
1172                        }
1173                    };
1174
1175                    for (index, element_expr) in elements.iter().enumerate() {
1176                        let element_val = self.gen_expr(element_expr, None);
1177
1178                        let offset_temp = self.next_temp_with_type(Type::Int);
1179                        self.code.push(Instruction::Binary {
1180                            dst: offset_temp.clone(),
1181                            op: IrOp::Mul,
1182                            lhs: Value::Const(index as i64),
1183                            rhs: Value::Const(stride),
1184                        });
1185
1186                        let base_addr_temp =
1187                            self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
1188                        self.code.push(Instruction::Unary {
1189                            dst: base_addr_temp.clone(),
1190                            op: IrOp::Ref,
1191                            value: base_val.clone(),
1192                        });
1193
1194                        let slot_addr_temp =
1195                            self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
1196                        self.code.push(Instruction::Binary {
1197                            dst: slot_addr_temp.clone(),
1198                            op: IrOp::Add,
1199                            lhs: Value::Temp(base_addr_temp),
1200                            rhs: Value::Temp(offset_temp),
1201                        });
1202
1203                        self.code.push(Instruction::Store {
1204                            ptr: Value::Temp(slot_addr_temp),
1205                            source: element_val,
1206                        });
1207                    }
1208
1209                    base_val
1210                }
1211            },
1212
1213            ExprKind::Field { base, field } => {
1214                let base_val = self.gen_expr(base, None);
1215                let base_type = self.expr_type(base).unwrap_or(Type::Int);
1216                let resolved_base = self.resolve_type(&base_type);
1217
1218                let struct_name = match resolved_base {
1219                    Type::Struct(name) => name,
1220                    Type::GenericInstance { name, args } => {
1221                        let mut mangled_name = name;
1222                        for arg in args {
1223                            mangled_name.push_str("__");
1224                            mangled_name.push_str(&self.mangle_type(&arg));
1225                        }
1226                        mangled_name
1227                    }
1228                    _ => panic!(
1229                        "ICE: Attempted field access on non-struct type. Found: {}",
1230                        type_to_string(&base_type)
1231                    ),
1232                };
1233
1234                let (offset, field_type) = {
1235                    let (offset, unres_field_ty) = self
1236                        .get_struct_layout(&struct_name)
1237                        .unwrap_or_else(|| {
1238                            panic!(
1239                                "ICE: Structural reference layout untracked for '{}'.",
1240                                struct_name
1241                            )
1242                        })
1243                        .field_offsets
1244                        .get(field)
1245                        .map(|(offset, field_ty)| (*offset, field_ty.clone()))
1246                        .unwrap_or_else(|| {
1247                            panic!(
1248                                "ICE: Referenced struct field '{}' does not exist in '{}'.",
1249                                field, struct_name
1250                            )
1251                        });
1252
1253                    (offset, self.resolve_type(&unres_field_ty))
1254                };
1255
1256                let base_addr_temp =
1257                    self.next_temp_with_type(Type::Ptr(Box::new(Type::Struct(struct_name))));
1258                self.code.push(Instruction::Unary {
1259                    dst: base_addr_temp.clone(),
1260                    op: IrOp::Ref,
1261                    value: base_val,
1262                });
1263
1264                let field_addr_temp =
1265                    self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
1266                self.code.push(Instruction::Binary {
1267                    dst: field_addr_temp.clone(),
1268                    op: IrOp::Add,
1269                    lhs: Value::Temp(base_addr_temp),
1270                    rhs: Value::Const(offset),
1271                });
1272
1273                let result_temp = self.next_temp_with_type(field_type.clone());
1274                self.code.push(Instruction::Load {
1275                    dst: result_temp.clone(),
1276                    ptr: Value::Temp(field_addr_temp),
1277                    ty: field_type,
1278                });
1279
1280                Value::Temp(result_temp)
1281            }
1282
1283            ExprKind::StructLiteral {
1284                struct_name,
1285                generic_args,
1286                fields,
1287            } => {
1288                let concrete_type = if generic_args.is_empty() {
1289                    Type::Struct(struct_name.clone())
1290                } else {
1291                    let generic_ty = Type::GenericInstance {
1292                        name: struct_name.clone(),
1293                        args: generic_args.clone(),
1294                    };
1295                    self.resolve_type(&generic_ty)
1296                };
1297
1298                let concrete_struct_name = match &concrete_type {
1299                    Type::Struct(name) => name.clone(),
1300                    _ => panic!("Expected concrete struct type after resolution"),
1301                };
1302
1303                let target_val = match target_dest {
1304                    Some(dest) => dest,
1305                    None => {
1306                        let anon_name = format!("_anon_struct_{}", self.temps.next_temp());
1307                        self.var_types
1308                            .insert(anon_name.clone(), concrete_type.clone());
1309
1310                        Value::Var(anon_name)
1311                    }
1312                };
1313
1314                let layout_fields = self
1315                    .struct_defs
1316                    .get(&concrete_struct_name)
1317                    .expect("ICE: Structural initialization on untracked layout.")
1318                    .field_offsets
1319                    .clone();
1320
1321                for (field_name, field_expr) in fields {
1322                    let field_val = self.gen_expr(field_expr, None);
1323                    let (offset, field_type) = layout_fields
1324                        .get(field_name)
1325                        .expect("ICE: Field initialization lookup failure.");
1326
1327                    let base_addr_temp =
1328                        self.next_temp_with_type(Type::Ptr(Box::new(concrete_type.clone())));
1329                    self.code.push(Instruction::Unary {
1330                        dst: base_addr_temp.clone(),
1331                        op: IrOp::Ref,
1332                        value: target_val.clone(),
1333                    });
1334
1335                    let slot_addr_temp =
1336                        self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
1337                    self.code.push(Instruction::Binary {
1338                        dst: slot_addr_temp.clone(),
1339                        op: IrOp::Add,
1340                        lhs: Value::Temp(base_addr_temp),
1341                        rhs: Value::Const(*offset),
1342                    });
1343
1344                    self.code.push(Instruction::Store {
1345                        ptr: Value::Temp(slot_addr_temp),
1346                        source: field_val,
1347                    });
1348                }
1349
1350                target_val
1351            }
1352
1353            ExprKind::Index { base, index } => {
1354                let base_val = self.gen_expr(base, None);
1355                let index_val = self.gen_expr(index, None);
1356
1357                let base_type = self.expr_type(base);
1358                let element_type = match &base_type {
1359                    Some(Type::Array { element_type, .. }) => *element_type.clone(),
1360                    Some(Type::Ptr(inner)) => match &**inner {
1361                        Type::Array { element_type, .. } => *element_type.clone(),
1362                        other => other.clone(),
1363                    },
1364                    Some(Type::Str) => Type::Char,
1365                    _ => Type::Int,
1366                };
1367
1368                let stride = self.element_size(&element_type);
1369                let offset_temp = self.next_temp_with_type(Type::Int);
1370                self.code.push(Instruction::Binary {
1371                    dst: offset_temp.clone(),
1372                    op: IrOp::Mul,
1373                    lhs: index_val,
1374                    rhs: Value::Const(stride),
1375                });
1376
1377                let target_addr_temp =
1378                    self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
1379                let is_base_variable_a_pointer = match &base_val {
1380                    Value::Var(name) => matches!(self.var_types.get(name), Some(Type::Ptr(_))),
1381                    _ => false,
1382                };
1383
1384                if is_base_variable_a_pointer || matches!(base_type, Some(Type::Ptr(_))) {
1385                    self.code.push(Instruction::Binary {
1386                        dst: target_addr_temp.clone(),
1387                        op: IrOp::Add,
1388                        lhs: base_val,
1389                        rhs: Value::Temp(offset_temp),
1390                    });
1391                } else {
1392                    match base_val {
1393                        Value::Var(_) => {
1394                            let base_addr_temp =
1395                                self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
1396                            self.code.push(Instruction::Unary {
1397                                dst: base_addr_temp.clone(),
1398                                op: IrOp::Ref,
1399                                value: base_val,
1400                            });
1401                            self.code.push(Instruction::Binary {
1402                                dst: target_addr_temp.clone(),
1403                                op: IrOp::Add,
1404                                lhs: Value::Temp(base_addr_temp),
1405                                rhs: Value::Temp(offset_temp),
1406                            });
1407                        }
1408                        _ => {
1409                            self.code.push(Instruction::Binary {
1410                                dst: target_addr_temp.clone(),
1411                                op: IrOp::Add,
1412                                lhs: base_val,
1413                                rhs: Value::Temp(offset_temp),
1414                            });
1415                        }
1416                    }
1417                }
1418
1419                let result_temp = self.next_temp_with_type(element_type.clone());
1420                self.code.push(Instruction::Load {
1421                    dst: result_temp.clone(),
1422                    ptr: Value::Temp(target_addr_temp),
1423                    ty: element_type,
1424                });
1425
1426                Value::Temp(result_temp)
1427            }
1428
1429            ExprKind::Identifier(name) => {
1430                let maybe_const_expr = self
1431                    .analyser_constants
1432                    .get(name)
1433                    .map(|(_, expr)| expr.clone());
1434
1435                if let Some(expr) = maybe_const_expr {
1436                    if let Some(val) = self.evaluated_constants.get(name) {
1437                        return val.clone();
1438                    }
1439                    let val = self.gen_expr(&expr, None);
1440                    self.evaluated_constants.insert(name.clone(), val.clone());
1441                    return val;
1442                }
1443
1444                Value::Var(self.resolve_var_name(name))
1445            }
1446
1447            ExprKind::Unary { op, expr } => match op {
1448                UnaryOp::Positive => {
1449                    let value = self.gen_expr(expr, None);
1450                    self.emit_unary(IrOp::Pos, value)
1451                }
1452                UnaryOp::Negative => {
1453                    let value = self.gen_expr(expr, None);
1454                    self.emit_unary(IrOp::Neg, value)
1455                }
1456                UnaryOp::Deref => {
1457                    let value = self.gen_expr(expr, None);
1458                    let inner_type = self.expr_type(expr).unwrap_or(Type::Void);
1459                    let value_type = match inner_type {
1460                        Type::Ptr(inner) => *inner,
1461                        _ => {
1462                            unreachable!(
1463                                "non-pointer type dereferenced (this should be handled by analyser)"
1464                            )
1465                        }
1466                    };
1467                    let result_temp = self.next_temp_with_type(value_type.clone());
1468                    self.code.push(Instruction::Load {
1469                        dst: result_temp.clone(),
1470                        ptr: value,
1471                        ty: value_type,
1472                    });
1473                    Value::Temp(result_temp)
1474                }
1475                UnaryOp::Not => {
1476                    let value = self.gen_expr(expr, None);
1477                    self.emit_unary(IrOp::Not, value)
1478                }
1479                UnaryOp::AddressOf => {
1480                    if let ExprKind::Literal(lit) = &expr.kind {
1481                        let lit_val = match lit {
1482                            Literal::Int(v) => Value::Const(*v),
1483                            Literal::Bool(b) => Value::Bool(*b),
1484                            Literal::Char(c) => Value::Char(*c),
1485                            Literal::String(s) => Value::Str(s.clone()),
1486                            Literal::Arr { .. } => self.gen_expr(expr, None),
1487                        };
1488
1489                        let lit_ty = self.expr_type(expr).unwrap_or(Type::Int);
1490                        let raw_temp = self.temps.next_temp();
1491                        let anon_var_name = format!("_anon_lit_{}", raw_temp);
1492
1493                        self.var_types.insert(anon_var_name.clone(), lit_ty.clone());
1494
1495                        self.code.push(Instruction::Assign {
1496                            dst: anon_var_name.clone(),
1497                            src: lit_val,
1498                        });
1499
1500                        let ref_temp = self.next_temp_with_type(Type::Ptr(Box::new(lit_ty)));
1501                        self.code.push(Instruction::Unary {
1502                            dst: ref_temp.clone(),
1503                            op: IrOp::Ref,
1504                            value: Value::Var(anon_var_name),
1505                        });
1506
1507                        Value::Temp(ref_temp)
1508                    } else if matches!(
1509                        expr.kind,
1510                        ExprKind::Field { .. }
1511                            | ExprKind::Index { .. }
1512                            | ExprKind::Unary {
1513                                op: UnaryOp::Deref,
1514                                ..
1515                            }
1516                    ) {
1517                        self.gen_lvalue_addr(expr)
1518                    } else {
1519                        let value = self.gen_expr(expr, None);
1520                        let inner_type = self.get_value_type(&value);
1521                        let temp = self.next_temp_with_type(Type::Ptr(Box::new(inner_type)));
1522                        self.code.push(Instruction::Unary {
1523                            dst: temp.clone(),
1524                            op: IrOp::Ref,
1525                            value,
1526                        });
1527                        Value::Temp(temp)
1528                    }
1529                }
1530            },
1531
1532            ExprKind::Binary { left, op, right } => {
1533                let lhs = self.gen_expr(left, None);
1534                let rhs = self.gen_expr(right, None);
1535
1536                if matches!(op, BinaryOp::Add)
1537                    && (self.is_string_valued(&lhs) || self.expr_type(left) == Some(Type::Str))
1538                    && (self.is_string_valued(&rhs) || self.expr_type(right) == Some(Type::Str))
1539                {
1540                    self.code.push(Instruction::Arg { value: lhs });
1541                    self.code.push(Instruction::Arg { value: rhs });
1542                    let dst = self.next_temp_with_type(Type::Str);
1543                    self.code.push(Instruction::Call {
1544                        dest: Some(dst.clone()),
1545                        name: "str_concat".to_string(),
1546                        argc: 2,
1547                    });
1548                    return Value::Temp(dst);
1549                }
1550
1551                let ir_op = match op {
1552                    BinaryOp::Add => IrOp::Add,
1553                    BinaryOp::Sub => IrOp::Sub,
1554                    BinaryOp::Mul => IrOp::Mul,
1555                    BinaryOp::Div => IrOp::Div,
1556                    BinaryOp::Eq => IrOp::Eq,
1557                    BinaryOp::NEq => IrOp::NEq,
1558                    BinaryOp::Gt => IrOp::Gt,
1559                    BinaryOp::GtE => IrOp::GtE,
1560                    BinaryOp::And => IrOp::And,
1561                    BinaryOp::Or => IrOp::Or,
1562                    BinaryOp::Lt => IrOp::Lt,
1563                    BinaryOp::LtE => IrOp::LtE,
1564                    BinaryOp::Mod => IrOp::Mod,
1565                };
1566
1567                self.emit_binary(ir_op, lhs, rhs)
1568            }
1569
1570            ExprKind::Call {
1571                callee,
1572                generic_args,
1573                args,
1574            } => self
1575                .gen_call(callee, generic_args, args, true)
1576                .unwrap_or(Value::Void),
1577        }
1578    }
1579
1580    pub fn gen_stmt(&mut self, stmt: &Stmt) {
1581        match stmt {
1582            Stmt::Use { .. } => unreachable!(),
1583
1584            Stmt::Struct {
1585                name,
1586                generic_params,
1587                fields,
1588            } => {
1589                if !generic_params.is_empty() {
1590                    self.struct_blueprints
1591                        .insert(name.value.clone(), (generic_params.clone(), fields.clone()));
1592                } else {
1593                    self.instantiate_struct_layout(name.value.clone(), fields, &HashMap::new());
1594                }
1595            }
1596            Stmt::Constant { .. } => {
1597                // Constants are generated at use sites
1598            }
1599            Stmt::Assignment { ident, vtype, expr } => {
1600                let mangled_name = format!("{}::{}", self.current_function, ident.value);
1601
1602                if let Some(explicit_ty) = vtype {
1603                    let resolved = self.resolve_type(explicit_ty);
1604                    self.var_types.insert(mangled_name.clone(), resolved);
1605                }
1606
1607                let current_ty = vtype
1608                    .clone()
1609                    .or_else(|| self.var_types.get(&mangled_name).cloned())
1610                    .map(|ty| self.resolve_type(&ty));
1611
1612                let is_aggregate = matches!(
1613                    current_ty,
1614                    Some(Type::Array { .. })
1615                        | Some(Type::Struct(_))
1616                        | Some(Type::GenericInstance { .. })
1617                        | Some(Type::VariadicPack { .. })
1618                );
1619
1620                let target_var = Value::Var(mangled_name.clone());
1621
1622                if let Some(expr_node) = expr {
1623                    if is_aggregate {
1624                        let value = self.gen_expr(expr_node, Some(target_var));
1625
1626                        self.code.push(Instruction::Assign {
1627                            dst: mangled_name,
1628                            src: value,
1629                        });
1630                    } else {
1631                        let value = self.gen_expr(expr_node, None);
1632                        if vtype.is_none() {
1633                            let computed_ty = self.get_value_type(&value);
1634                            let resolved_computed = self.resolve_type(&computed_ty);
1635                            self.var_types
1636                                .insert(mangled_name.clone(), resolved_computed);
1637                        }
1638                        self.code.push(Instruction::Assign {
1639                            dst: mangled_name,
1640                            src: value,
1641                        });
1642                    }
1643                } else {
1644                    match current_ty {
1645                        Some(Type::Int) => {
1646                            self.code.push(Instruction::Assign {
1647                                dst: mangled_name,
1648                                src: Value::Const(0),
1649                            });
1650                        }
1651                        Some(Type::Bool) => {
1652                            self.code.push(Instruction::Assign {
1653                                dst: mangled_name,
1654                                src: Value::Bool(false),
1655                            });
1656                        }
1657                        Some(Type::Char) => {
1658                            self.code.push(Instruction::Assign {
1659                                dst: mangled_name,
1660                                src: Value::Char('\0'),
1661                            });
1662                        }
1663                        Some(Type::Str) | Some(Type::Ptr(_)) => {
1664                            self.code.push(Instruction::Assign {
1665                                dst: mangled_name,
1666                                src: Value::Const(0),
1667                            });
1668                        }
1669                        Some(Type::Struct(_)) | Some(Type::Array { .. }) => {
1670                            self.code.push(Instruction::Assign {
1671                                dst: mangled_name,
1672                                src: Value::Const(0),
1673                            });
1674                        }
1675                        _ => {
1676                            self.code.push(Instruction::Assign {
1677                                dst: mangled_name,
1678                                src: Value::Const(0),
1679                            });
1680                        }
1681                    }
1682                }
1683            }
1684
1685            Stmt::Reassignment { ident, expr } => {
1686                let mangled_name = format!("{}::{}", self.current_function, ident.value);
1687                let var_type = self.var_types.get(&mangled_name).cloned();
1688
1689                let is_aggregate =
1690                    matches!(var_type, Some(Type::Array { .. } | Type::Struct { .. }));
1691
1692                let target_var = Value::Var(mangled_name.clone());
1693
1694                if is_aggregate {
1695                    let src_val = self.gen_expr(expr, Some(target_var.clone()));
1696
1697                    if src_val != target_var {
1698                        self.code.push(Instruction::Store {
1699                            ptr: target_var,
1700                            source: src_val,
1701                        });
1702                    }
1703                } else {
1704                    let value = self.gen_expr(expr, None);
1705                    self.code.push(Instruction::Assign {
1706                        dst: mangled_name,
1707                        src: value,
1708                    });
1709                }
1710            }
1711            Stmt::Expr(expr) => {
1712                if let ExprKind::Call {
1713                    callee,
1714                    generic_args,
1715                    args,
1716                } = &expr.kind
1717                {
1718                    self.gen_call(callee, generic_args, args, false);
1719                } else {
1720                    self.gen_expr(expr, None);
1721                }
1722            }
1723
1724            Stmt::If {
1725                cond,
1726                then_branch,
1727                else_if_branches,
1728                else_branch,
1729            } => {
1730                if let Some(ConstVal::Bool(is_true)) = self.eval_const(cond) {
1731                    if is_true {
1732                        for stmt in then_branch {
1733                            self.gen_stmt(stmt);
1734                        }
1735                        return;
1736                    }
1737
1738                    let mut resolved_statically = true;
1739                    for (ei_cond, ei_body) in else_if_branches {
1740                        match self.eval_const(ei_cond) {
1741                            Some(ConstVal::Bool(true)) => {
1742                                for stmt in ei_body {
1743                                    self.gen_stmt(stmt);
1744                                }
1745                                return;
1746                            }
1747                            Some(ConstVal::Bool(false)) => continue,
1748                            _ => {
1749                                resolved_statically = false;
1750                                break;
1751                            }
1752                        }
1753                    }
1754
1755                    if resolved_statically {
1756                        if let Some(else_stmts) = else_branch {
1757                            for stmt in else_stmts {
1758                                self.gen_stmt(stmt);
1759                            }
1760                        }
1761                        return;
1762                    }
1763                }
1764
1765                let true_end = self.labels.next_label();
1766                let mut next_target = self.labels.next_label();
1767
1768                let cond_val = self.gen_expr(cond, None);
1769                self.code.push(Instruction::JumpIfFalse {
1770                    cond: cond_val,
1771                    target: next_target.clone(),
1772                });
1773
1774                for stmt in then_branch {
1775                    self.gen_stmt(stmt);
1776                }
1777
1778                self.code.push(Instruction::Jump(true_end.clone()));
1779
1780                for (ei_cond, ei_body) in else_if_branches.iter() {
1781                    self.code.push(Instruction::Label(next_target));
1782
1783                    next_target = self.labels.next_label();
1784
1785                    let ei_cond_val = self.gen_expr(ei_cond, None);
1786                    self.code.push(Instruction::JumpIfFalse {
1787                        cond: ei_cond_val,
1788                        target: next_target.clone(),
1789                    });
1790
1791                    for stmt in ei_body {
1792                        self.gen_stmt(stmt);
1793                    }
1794
1795                    self.code.push(Instruction::Jump(true_end.clone()));
1796                }
1797
1798                if let Some(else_stmts) = else_branch {
1799                    self.code.push(Instruction::Label(next_target));
1800                    for stmt in else_stmts {
1801                        self.gen_stmt(stmt);
1802                    }
1803                } else if next_target != true_end {
1804                    self.code.push(Instruction::Label(next_target));
1805                }
1806
1807                self.code.push(Instruction::Label(true_end));
1808            }
1809            Stmt::While { cond, body } => {
1810                let start = self.labels.next_label();
1811                let end = self.labels.next_label();
1812
1813                self.loop_exits.push(end.clone());
1814
1815                self.code.push(Instruction::Label(start.clone()));
1816                let cond_val = self.gen_expr(cond, None);
1817                self.code.push(Instruction::JumpIfFalse {
1818                    cond: cond_val,
1819                    target: end.clone(),
1820                });
1821
1822                for stmt in body {
1823                    self.gen_stmt(stmt);
1824                }
1825
1826                self.loop_exits.pop();
1827                self.code.push(Instruction::Jump(start));
1828                self.code.push(Instruction::Label(end));
1829            }
1830            Stmt::Break { .. } => {
1831                if let Some(exit_label) = self.loop_exits.last().cloned() {
1832                    self.code.push(Instruction::Jump(exit_label));
1833                } else {
1834                    panic!(
1835                        "Internal compiler error: break statement unvalidated by semantic analyzer"
1836                    );
1837                }
1838            }
1839            Stmt::ForIn {
1840                field_ident,
1841                target_expr,
1842                body,
1843            } => {
1844                let target_type = self
1845                    .expr_type(target_expr)
1846                    .unwrap_or_else(|| panic!("ICE: Cannot determine type of for-in target"));
1847
1848                let resolved_type = self.resolve_type(&target_type);
1849
1850                let target_value = self.gen_expr(target_expr, None);
1851
1852                let field_var = format!("{}::{}", self.current_function, field_ident.value);
1853
1854                match resolved_type {
1855                    Type::Struct(struct_name) => {
1856                        let layout = self.get_struct_layout(&struct_name).unwrap_or_else(|| {
1857                            panic!("ICE: Struct layout not found for '{}'", struct_name)
1858                        });
1859
1860                        let mut fields: Vec<(i64, Type)> = layout
1861                            .field_offsets
1862                            .values()
1863                            .map(|(offset, ty)| (*offset, ty.clone()))
1864                            .collect();
1865
1866                        fields.sort_by_key(|(offset, _)| *offset);
1867
1868                        for (i, (offset, field_type)) in fields.into_iter().enumerate() {
1869                            let field_type = self.resolve_type(&field_type);
1870
1871                            let iteration_var =
1872                                format!("{}::{}#{}", self.current_function, field_ident.value, i);
1873                            let shadow_var =
1874                                format!("{}::{}", self.current_function, field_ident.value);
1875
1876                            let base_addr = self.next_temp_with_type(Type::Ptr(Box::new(
1877                                Type::Struct(struct_name.clone()),
1878                            )));
1879
1880                            self.code.push(Instruction::Unary {
1881                                dst: base_addr.clone(),
1882                                op: IrOp::Ref,
1883                                value: target_value.clone(),
1884                            });
1885
1886                            let field_addr =
1887                                self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
1888
1889                            self.code.push(Instruction::Binary {
1890                                dst: field_addr.clone(),
1891                                op: IrOp::Add,
1892                                lhs: Value::Temp(base_addr),
1893                                rhs: Value::Const(offset),
1894                            });
1895
1896                            let field_value = self.next_temp_with_type(field_type.clone());
1897
1898                            self.code.push(Instruction::Load {
1899                                dst: field_value.clone(),
1900                                ptr: Value::Temp(field_addr),
1901                                ty: field_type.clone(),
1902                            });
1903
1904                            self.var_types.push_scope();
1905
1906                            let mut alias_scope = HashMap::new();
1907                            alias_scope.insert(field_ident.value.clone(), iteration_var.clone());
1908                            self.var_aliases.push(alias_scope);
1909
1910                            self.var_types
1911                                .insert(iteration_var.clone(), field_type.clone());
1912                            self.var_types
1913                                .insert(shadow_var.clone(), field_type.clone());
1914                            self.var_types
1915                                .insert(field_ident.value.clone(), field_type.clone());
1916
1917                            self.code.push(Instruction::Assign {
1918                                dst: iteration_var,
1919                                src: Value::Temp(field_value),
1920                            });
1921
1922                            for stmt in body {
1923                                self.gen_stmt(stmt);
1924                            }
1925
1926                            self.var_aliases.pop();
1927                            self.var_types.pop_scope();
1928                        }
1929                    }
1930                    Type::GenericInstance { name, args } => {
1931                        let concrete_type =
1932                            self.resolve_type(&Type::GenericInstance { name, args });
1933
1934                        match concrete_type {
1935                            Type::Struct(struct_name) => {
1936                                let layout =
1937                                    self.get_struct_layout(&struct_name).unwrap_or_else(|| {
1938                                        panic!("ICE: Struct layout not found for '{}'", struct_name)
1939                                    });
1940
1941                                let mut fields: Vec<(i64, Type)> = layout
1942                                    .field_offsets
1943                                    .values()
1944                                    .map(|(offset, ty)| (*offset, ty.clone()))
1945                                    .collect();
1946
1947                                fields.sort_by_key(|(offset, _)| *offset);
1948
1949                                for (offset, field_type) in fields {
1950                                    let field_type = self.resolve_type(&field_type);
1951
1952                                    let base_addr = self.next_temp_with_type(Type::Ptr(Box::new(
1953                                        Type::Struct(struct_name.clone()),
1954                                    )));
1955
1956                                    self.code.push(Instruction::Unary {
1957                                        dst: base_addr.clone(),
1958                                        op: IrOp::Ref,
1959                                        value: target_value.clone(),
1960                                    });
1961
1962                                    let field_addr = self.next_temp_with_type(Type::Ptr(Box::new(
1963                                        field_type.clone(),
1964                                    )));
1965
1966                                    self.code.push(Instruction::Binary {
1967                                        dst: field_addr.clone(),
1968                                        op: IrOp::Add,
1969                                        lhs: Value::Temp(base_addr),
1970                                        rhs: Value::Const(offset),
1971                                    });
1972
1973                                    let field_value = self.next_temp_with_type(field_type.clone());
1974
1975                                    self.code.push(Instruction::Load {
1976                                        dst: field_value.clone(),
1977                                        ptr: Value::Temp(field_addr),
1978                                        ty: field_type.clone(),
1979                                    });
1980
1981                                    self.var_types.insert(field_var.clone(), field_type);
1982
1983                                    self.code.push(Instruction::Assign {
1984                                        dst: field_var.clone(),
1985                                        src: Value::Temp(field_value),
1986                                    });
1987
1988                                    for stmt in body {
1989                                        self.gen_stmt(stmt);
1990                                    }
1991                                }
1992                            }
1993
1994                            other => {
1995                                panic!(
1996                                    "ICE: Generic for-in target resolved to non-struct type {}",
1997                                    type_to_string(&other)
1998                                );
1999                            }
2000                        }
2001                    }
2002
2003                    Type::VariadicPack { .. } => {
2004                        /*
2005                         * A VariadicPack has already been materialised by gen_call()
2006                         * as a concrete __variadic__ struct. Therefore use its
2007                         * generated struct layout exactly like an ordinary struct.
2008                         */
2009                        let struct_type = self.resolve_type(&target_type);
2010
2011                        let struct_name = match struct_type {
2012                            Type::Struct(name) => name,
2013                            other => {
2014                                panic!(
2015                                    "ICE: VariadicPack did not resolve to a struct: {}",
2016                                    type_to_string(&other)
2017                                );
2018                            }
2019                        };
2020
2021                        let layout = self.get_struct_layout(&struct_name).unwrap_or_else(|| {
2022                            panic!("ICE: Variadic pack layout not found for '{}'", struct_name)
2023                        });
2024
2025                        let mut fields: Vec<(String, i64, Type)> = layout
2026                            .field_offsets
2027                            .iter()
2028                            .map(|(name, (offset, ty))| (name.clone(), *offset, ty.clone()))
2029                            .filter(|(name, _, _)| name != variadic::length_field())
2030                            .collect();
2031
2032                        fields.sort_by_key(|(_, offset, _)| *offset);
2033
2034                        for (_, offset, field_type) in fields {
2035                            let field_type = self.resolve_type(&field_type);
2036
2037                            let base_addr = self.next_temp_with_type(Type::Ptr(Box::new(
2038                                Type::Struct(struct_name.clone()),
2039                            )));
2040
2041                            self.code.push(Instruction::Unary {
2042                                dst: base_addr.clone(),
2043                                op: IrOp::Ref,
2044                                value: target_value.clone(),
2045                            });
2046
2047                            let field_addr =
2048                                self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
2049
2050                            self.code.push(Instruction::Binary {
2051                                dst: field_addr.clone(),
2052                                op: IrOp::Add,
2053                                lhs: Value::Temp(base_addr),
2054                                rhs: Value::Const(offset),
2055                            });
2056
2057                            let field_value = self.next_temp_with_type(field_type.clone());
2058
2059                            self.code.push(Instruction::Load {
2060                                dst: field_value.clone(),
2061                                ptr: Value::Temp(field_addr),
2062                                ty: field_type.clone(),
2063                            });
2064
2065                            self.var_types.insert(field_var.clone(), field_type);
2066
2067                            self.code.push(Instruction::Assign {
2068                                dst: field_var.clone(),
2069                                src: Value::Temp(field_value),
2070                            });
2071
2072                            for stmt in body {
2073                                self.gen_stmt(stmt);
2074                            }
2075                        }
2076                    }
2077
2078                    other => {
2079                        panic!(
2080                            "ICE: Cannot use type {} as a for-in target",
2081                            type_to_string(&other)
2082                        );
2083                    }
2084                }
2085            }
2086
2087            Stmt::For {
2088                init,
2089                cond,
2090                step,
2091                body,
2092            } => {
2093                let start = self.labels.next_label();
2094                let end = self.labels.next_label();
2095
2096                self.gen_stmt(init);
2097                self.code.push(Instruction::Label(start.clone()));
2098                let cond_val = self.gen_expr(cond, None);
2099                self.code.push(Instruction::JumpIfFalse {
2100                    cond: cond_val,
2101                    target: end.clone(),
2102                });
2103
2104                for stmt in body {
2105                    self.gen_stmt(stmt);
2106                }
2107                self.gen_stmt(step);
2108                self.code.push(Instruction::Jump(start));
2109                self.code.push(Instruction::Label(end));
2110            }
2111            Stmt::Function {
2112                name,
2113                generic_params,
2114                params,
2115                body,
2116                rttype,
2117                ..
2118            } => {
2119                let has_variadic = params.iter().any(|p| p.is_variadic);
2120                if !generic_params.is_empty() || has_variadic {
2121                    self.fn_blueprints.insert(name.value.clone(), stmt.clone());
2122                    return;
2123                }
2124
2125                let resolved_rttype = rttype
2126                    .clone()
2127                    .map(|ty| self.resolve_type(&ty))
2128                    .unwrap_or(Type::Void);
2129                self.var_types.insert(name.value.clone(), resolved_rttype);
2130
2131                let start = self.functions.next(name.value.clone());
2132                let old_func = self.current_function.clone();
2133                self.current_function = start.clone();
2134
2135                self.var_types.push_scope();
2136
2137                self.code.push(Instruction::FunctionLabel(start.clone()));
2138
2139                for param in params {
2140                    if let Some(param_ty) = &param.ptype {
2141                        let resolved_param_ty = self.resolve_type(param_ty);
2142                        let unique_param_name = format!("{}::{}", start, param.name.value);
2143                        self.var_types.insert(unique_param_name, resolved_param_ty);
2144                    }
2145                    self.code.push(Instruction::Param {
2146                        p: format!("{}::{}", start, param.name.value),
2147                    });
2148                }
2149
2150                for stmt in body {
2151                    self.gen_stmt(stmt);
2152                }
2153
2154                if !matches!(body.last(), Some(Stmt::Return { .. })) {
2155                    let fallback_val = Value::Void;
2156                    self.code.push(Instruction::Return {
2157                        value: fallback_val,
2158                    });
2159                }
2160
2161                self.var_types.pop_scope();
2162
2163                self.current_function = old_func;
2164            }
2165            Stmt::Return { value, .. } => {
2166                if let Some(expr) = value {
2167                    let val = self.gen_expr(expr, None);
2168                    self.code.push(Instruction::Return { value: val });
2169                } else {
2170                    self.code.push(Instruction::Return { value: Value::Void })
2171                }
2172            }
2173            Stmt::Extern { name, rttype, .. } => {
2174                let return_type = rttype.clone().unwrap_or(Type::Void);
2175                self.var_types.insert(name.value.clone(), return_type);
2176                self.code.push(Instruction::Extern {
2177                    fnname: name.value.clone(),
2178                });
2179            }
2180            Stmt::DerefReassignment { target, expr } => {
2181                let value_to_store = self.gen_expr(expr, None);
2182
2183                match &target.kind {
2184                    ExprKind::Unary {
2185                        op: UnaryOp::Deref,
2186                        expr: inner,
2187                    } => {
2188                        let ptr_val = self.gen_expr(inner, None);
2189                        self.code.push(Instruction::Store {
2190                            ptr: ptr_val,
2191                            source: value_to_store,
2192                        });
2193                    }
2194
2195                    ExprKind::Field { base, field } => {
2196                        let base_addr = self.gen_lvalue_addr(base);
2197
2198                        let base_type = self.expr_type(base).unwrap_or(Type::Int);
2199                        let resolved_base = self.resolve_type(&base_type);
2200
2201                        let struct_name = match resolved_base {
2202                            Type::Struct(name) => name,
2203                            Type::GenericInstance { name, args } => {
2204                                let mut mangled_name = name;
2205                                for arg in args {
2206                                    mangled_name.push_str("__");
2207                                    mangled_name.push_str(&self.mangle_type(&arg));
2208                                }
2209                                mangled_name
2210                            }
2211                            _ => panic!(
2212                                "ICE: Field assignment on non-struct type. Found: {}",
2213                                type_to_string(&base_type)
2214                            ),
2215                        };
2216
2217                        let (offset, field_type) = {
2218                            let (offset, unres_field_ty) = self
2219                                .struct_defs
2220                                .get(&struct_name)
2221                                .unwrap_or_else(|| {
2222                                    panic!(
2223                                        "ICE: Structural reference layout untracked for '{}'.",
2224                                        struct_name
2225                                    )
2226                                })
2227                                .field_offsets
2228                                .get(field)
2229                                .map(|(offset, field_ty)| (*offset, field_ty.clone()))
2230                                .unwrap_or_else(|| {
2231                                    panic!(
2232                                        "ICE: Referenced struct field '{}' does not exist in '{}'.",
2233                                        field, struct_name
2234                                    )
2235                                });
2236
2237                            (offset, self.resolve_type(&unres_field_ty))
2238                        };
2239
2240                        let field_addr_temp =
2241                            self.next_temp_with_type(Type::Ptr(Box::new(field_type.clone())));
2242                        self.code.push(Instruction::Binary {
2243                            dst: field_addr_temp.clone(),
2244                            op: IrOp::Add,
2245                            lhs: base_addr,
2246                            rhs: Value::Const(offset),
2247                        });
2248
2249                        self.code.push(Instruction::Store {
2250                            ptr: Value::Temp(field_addr_temp),
2251                            source: value_to_store,
2252                        });
2253                    }
2254
2255                    ExprKind::Index { base, index } => {
2256                        let base_val = self.gen_expr(base, None);
2257                        let index_val = self.gen_expr(index, None);
2258
2259                        let base_type = self.expr_type(base);
2260                        let element_type = match &base_type {
2261                            Some(Type::Array { element_type, .. }) => *element_type.clone(),
2262                            Some(Type::Ptr(inner)) => match &**inner {
2263                                Type::Array { element_type, .. } => *element_type.clone(),
2264                                other => other.clone(),
2265                            },
2266                            Some(Type::Str) => Type::Char,
2267                            _ => Type::Int,
2268                        };
2269
2270                        let stride = self.element_size(&element_type);
2271
2272                        let offset_temp = self.next_temp_with_type(Type::Int);
2273                        self.code.push(Instruction::Binary {
2274                            dst: offset_temp.clone(),
2275                            op: IrOp::Mul,
2276                            lhs: index_val,
2277                            rhs: Value::Const(stride),
2278                        });
2279
2280                        let is_base_pointer = match &base.kind {
2281                            ExprKind::Identifier(name) => {
2282                                matches!(self.var_types.get(name), Some(Type::Ptr(_)))
2283                            }
2284                            ExprKind::Unary {
2285                                op: UnaryOp::Deref, ..
2286                            } => true,
2287                            _ => false,
2288                        };
2289
2290                        let target_addr_temp =
2291                            self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
2292
2293                        if is_base_pointer || matches!(base_type, Some(Type::Ptr(_))) {
2294                            self.code.push(Instruction::Binary {
2295                                dst: target_addr_temp.clone(),
2296                                op: IrOp::Add,
2297                                lhs: base_val,
2298                                rhs: Value::Temp(offset_temp),
2299                            });
2300                        } else {
2301                            let base_addr_temp =
2302                                self.next_temp_with_type(Type::Ptr(Box::new(element_type.clone())));
2303                            self.code.push(Instruction::Unary {
2304                                dst: base_addr_temp.clone(),
2305                                op: IrOp::Ref,
2306                                value: base_val,
2307                            });
2308                            self.code.push(Instruction::Binary {
2309                                dst: target_addr_temp.clone(),
2310                                op: IrOp::Add,
2311                                lhs: Value::Temp(base_addr_temp),
2312                                rhs: Value::Temp(offset_temp),
2313                            });
2314                        }
2315
2316                        self.code.push(Instruction::Store {
2317                            ptr: Value::Temp(target_addr_temp),
2318                            source: value_to_store,
2319                        });
2320                    }
2321
2322                    ExprKind::Identifier(name) => {
2323                        let dst = self.resolve_var_name(name);
2324                        self.code.push(Instruction::Assign {
2325                            dst,
2326                            src: value_to_store,
2327                        });
2328                    }
2329
2330                    _ => {
2331                        panic!("Invalid lvalue in DerefReassignment: {:?}", target.kind);
2332                    }
2333                }
2334            }
2335        }
2336    }
2337
2338    pub fn gen_param(&mut self, param: &Parameter) {
2339        self.code.push(Instruction::Param {
2340            p: param.name.value.clone(),
2341        });
2342    }
2343
2344    pub fn gen_program(&mut self, program: &Program) {
2345        for stmt in &program.statements {
2346            if !matches!(stmt, Stmt::Function { .. })
2347                && !matches!(stmt, Stmt::Extern { .. })
2348                && !matches!(stmt, Stmt::Struct { .. })
2349                && !matches!(stmt, Stmt::Constant { .. })
2350            {
2351                println!(
2352                    "Codegen Error: top-level statement outside of a function is not supported."
2353                );
2354                std::process::exit(1);
2355            }
2356            self.gen_stmt(stmt);
2357        }
2358
2359        while let Some((callee_name, generic_args, variadic_types)) =
2360            self.deferred_instantiations.pop()
2361        {
2362            if let Some(blueprint) = self.fn_blueprints.get(&callee_name).cloned()
2363                && let Stmt::Function {
2364                    name,
2365                    generic_params,
2366                    params,
2367                    body,
2368                    rttype,
2369                    ..
2370                } = blueprint
2371            {
2372                let has_variadic = params.iter().any(|p| p.is_variadic);
2373                let resolved_func_name = self.mangle_call_name(
2374                    &name.value,
2375                    &generic_args,
2376                    &variadic_types,
2377                    has_variadic,
2378                );
2379
2380                let substitutions: HashMap<String, Type> = generic_params
2381                    .iter()
2382                    .cloned()
2383                    .zip(generic_args.iter().cloned())
2384                    .collect();
2385
2386                let old_subs = self.current_substitutions.clone();
2387                self.current_substitutions = substitutions;
2388
2389                let old_func = self.current_function.clone();
2390                self.current_function = resolved_func_name.clone();
2391
2392                self.code
2393                    .push(Instruction::FunctionLabel(resolved_func_name.clone()));
2394
2395                for param in params.iter().filter(|p| !p.is_variadic) {
2396                    if let Some(param_ty) = &param.ptype {
2397                        let resolved_param_ty = self.resolve_type(param_ty);
2398                        let unique_param_name =
2399                            format!("{}::{}", resolved_func_name, param.name.value);
2400                        self.var_types.insert(unique_param_name, resolved_param_ty);
2401                    }
2402                    self.code.push(Instruction::Param {
2403                        p: format!("{}::{}", resolved_func_name, param.name.value),
2404                    });
2405                }
2406
2407                if let Some(variadic_param) = params.iter().find(|p| p.is_variadic) {
2408                    let struct_name = format!("__variadic__{}", resolved_func_name);
2409                    self.instantiate_variadic_struct(
2410                        &struct_name,
2411                        &variadic_types,
2412                        variadic_param.name.location.clone(),
2413                    );
2414                    let unique_param_name =
2415                        format!("{}::{}", resolved_func_name, variadic_param.name.value);
2416                    self.var_types
2417                        .insert(unique_param_name.clone(), Type::Struct(struct_name));
2418                    self.code.push(Instruction::Param {
2419                        p: unique_param_name,
2420                    });
2421                }
2422
2423                for stmt in &body {
2424                    self.gen_stmt(stmt);
2425                }
2426
2427                let base_return_ty = rttype.unwrap_or(Type::Void);
2428                let resolved_return_ty = self.resolve_type(&base_return_ty);
2429
2430                if !matches!(self.code.last(), Some(Instruction::Return { .. })) {
2431                    let fallback_val = if resolved_return_ty == Type::Void {
2432                        Value::Void
2433                    } else if matches!(
2434                        resolved_return_ty,
2435                        Type::Struct(_) | Type::GenericInstance { .. }
2436                    ) {
2437                        let dummy_dst = self.next_temp_with_type(resolved_return_ty.clone());
2438                        Value::Temp(dummy_dst)
2439                    } else {
2440                        Value::Const(0)
2441                    };
2442
2443                    self.code.push(Instruction::Return {
2444                        value: fallback_val,
2445                    });
2446                }
2447
2448                self.current_function = old_func;
2449                self.current_substitutions = old_subs;
2450            }
2451        }
2452    }
2453
2454    pub fn dump(&self) {
2455        for inst in &self.code {
2456            match inst {
2457                Instruction::Assign { dst, src } => println!("{dst} = {:?}", src),
2458                Instruction::Binary { dst, op, lhs, rhs } => {
2459                    println!("{dst} = {:?} {:?} {:?}", lhs, op, rhs)
2460                }
2461                Instruction::Unary { dst, op, value } => println!("{dst} = {:?}{:?}", op, value),
2462                Instruction::Label(label) => println!("{label}:"),
2463                Instruction::Jump(label) => println!("goto {label}"),
2464                Instruction::JumpIfFalse { cond, target } => {
2465                    println!("ifFalse {:?} goto {target}", cond)
2466                }
2467                Instruction::Param { p } => println!("param {}", p),
2468                Instruction::FunctionLabel(label) => println!("{label}:"),
2469                Instruction::Return { value } => println!("return {:?}", value),
2470                Instruction::Arg { value } => println!("arg {:?}", value),
2471                Instruction::Call { dest, name, argc } => println!(
2472                    "call {:?} @ {:?} [arg_count: {}]",
2473                    name,
2474                    dest.clone().unwrap_or("n/a".to_string()),
2475                    argc
2476                ),
2477                Instruction::Extern { fnname } => println!("extern {}", fnname),
2478                Instruction::Store { ptr, source } => println!("store {:?} to *{:?}", source, ptr),
2479                Instruction::Load { dst, ptr, ty } => {
2480                    println!("load {:?} [{:?}] from *{:?}", dst, ty, ptr)
2481                }
2482                Instruction::Cast {
2483                    dst,
2484                    cast_ty,
2485                    value,
2486                    to_type,
2487                } => println!(
2488                    "{dst} = {:?} as {:?} [casttype: {:?}]",
2489                    value, to_type, cast_ty
2490                ),
2491            }
2492        }
2493        println!("[DUMP_END]")
2494    }
2495}
2496impl Default for IRGen {
2497    fn default() -> Self {
2498        Self::new()
2499    }
2500}