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>)>, 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 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, }
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 (Type::Ptr(_), Type::Ptr(_)) => CastType::BitCast,
1110
1111 (Type::Ptr(_), Type::Str) => CastType::BitCast,
1113
1114 (
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 _ => 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 }
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 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) = ¶m.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) = ¶m.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}