swamp_vm_types/
types.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::{
6    align_to, AggregateMemoryLocation, CountU16, FrameMemoryAddress, FrameMemoryRegion,
7    FrameMemorySize, HeapMemoryAddress, HeapMemoryRegion, InstructionPosition,
8    InstructionPositionOffset, InstructionRange, MemoryAlignment, MemoryLocation,
9    MemoryOffset, MemorySize, ProgramCounterDelta, RegIndex, HEAP_PTR_ON_FRAME_ALIGNMENT,
10    HEAP_PTR_ON_FRAME_SIZE, MAP_HEADER_ALIGNMENT, MAP_HEADER_SIZE, MAP_ITERATOR_ALIGNMENT, MAP_ITERATOR_SIZE,
11    RANGE_HEADER_ALIGNMENT, RANGE_HEADER_SIZE, RANGE_ITERATOR_ALIGNMENT, RANGE_ITERATOR_SIZE, STRING_PTR_ALIGNMENT,
12    STRING_PTR_SIZE, VEC_HEADER_SIZE, VEC_ITERATOR_ALIGNMENT, VEC_ITERATOR_SIZE, VEC_PTR_ALIGNMENT,
13    VEC_PTR_SIZE,
14};
15use seq_fmt::comma;
16use std::cmp::{max, Ordering};
17use std::fmt::{Debug, Display, Formatter, Write};
18use std::rc::Rc;
19use tracing::error;
20use yansi::Paint;
21
22pub type BasicTypeRef = Rc<BasicType>;
23
24#[derive(Clone, Debug)]
25pub struct OffsetMemoryItem {
26    pub offset: MemoryOffset,
27    pub size: MemorySize,
28    pub name: String,
29    pub ty: BasicTypeRef,
30}
31
32impl Display for OffsetMemoryItem {
33    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34        write!(f, "{}:{}", self.name, self.ty)
35    }
36}
37
38#[derive(Clone, Debug)]
39pub struct StructType {
40    pub name: String,
41    pub fields: Vec<OffsetMemoryItem>,
42    pub total_size: MemorySize,
43    pub max_alignment: MemoryAlignment,
44}
45
46impl Display for StructType {
47    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
48        write!(f, "{}", self.name)?;
49        for field in &self.fields {
50            write!(
51                f,
52                "{:04X}:{:X} {}:{}",
53                field.offset.0, field.size.0, field.name, field.ty
54            )?;
55        }
56        Ok(())
57    }
58}
59
60#[derive(Clone, Debug)]
61pub struct TupleType {
62    pub fields: Vec<OffsetMemoryItem>,
63    pub total_size: MemorySize,
64    pub max_alignment: MemoryAlignment,
65}
66
67impl TupleType {
68    #[must_use]
69    pub fn aligned_size_of_field(&self, field_index: usize) -> MemorySize {
70        let max_alignment: usize = self.max_alignment.into();
71        MemorySize(max(self.fields[field_index].size.0 as usize, max_alignment) as u32)
72    }
73}
74
75impl Display for TupleType {
76    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77        for field in &self.fields {
78            write!(f, "{:04X}:{:X} {}", field.offset.0, field.size.0, field.ty)?;
79        }
80        Ok(())
81    }
82}
83
84#[derive(Clone, Debug)]
85pub struct TaggedUnionVariant {
86    pub name: String,     // e.g., "None", "Some"
87    pub ty: BasicTypeRef, // the payload type (could be unit/empty)
88}
89
90impl Display for TaggedUnionVariant {
91    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
92        write!(f, "{}: {}", self.name, self.ty)
93    }
94}
95
96#[derive(Clone, Debug)]
97pub struct TaggedUnion {
98    pub name: String,
99    pub tag_offset: MemoryOffset, // should always be 0
100    pub tag_alignment: MemoryAlignment,
101    pub tag_size: MemorySize,
102    pub payload_max_size: MemorySize,
103    pub max_payload_alignment: MemoryAlignment,
104    pub payload_offset: MemoryOffset,
105    pub variants: Vec<TaggedUnionVariant>,
106    pub total_size: MemorySize,
107    pub max_alignment: MemoryAlignment,
108}
109
110impl Display for TaggedUnion {
111    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
112        write!(f, "union {}:", self.name, )?;
113        for (offset, variant) in self.variants.iter().enumerate() {
114            writeln!(f, "  {offset}: {variant}")?;
115        }
116        Ok(())
117    }
118}
119
120impl TaggedUnion {
121    #[must_use]
122    pub fn payload_offset(&self) -> MemoryOffset {
123        align_to(MemoryOffset(self.tag_size.0), self.max_alignment)
124    }
125}
126
127impl TaggedUnion {
128    #[must_use]
129    pub fn get_variant_by_index(&self, index: usize) -> &TaggedUnionVariant {
130        debug_assert!(
131            index < self.variants.len(),
132            "variant out of bounds {index} out of {}",
133            self.variants.len()
134        );
135        &self.variants[index]
136    }
137
138    #[must_use]
139    pub fn get_variant_as_offset_item(&self, index: usize) -> OffsetMemoryItem {
140        let variant = self.get_variant_by_index(index);
141        OffsetMemoryItem {
142            offset: self.payload_offset,
143            size: variant.ty.total_size,
144            name: variant.name.clone(),
145            ty: variant.ty.clone(),
146        }
147    }
148}
149
150#[derive(Debug, Clone)]
151pub struct FrameMemoryAttribute {
152    pub is_temporary: bool,
153}
154
155#[derive(Debug, Clone)]
156pub enum DecoratedOperandAccessKind {
157    WriteRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), // register is modified
158    ReadRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), // register is only read from
159    ReadIndirectPointer(FrameMemoryAddress), // TODO: should probably be removed
160    DeltaPc(ProgramCounterDelta),            // for branch
161    AbsolutePc(InstructionPosition),         // e.g. call
162    MemorySize(MemorySize),
163    AbsoluteMemoryPosition(HeapMemoryAddress), // only for loading constants?
164    WriteFrameMemoryAddress(FrameMemoryAddress), // e.g. store to frame
165    ReadFrameMemoryAddress(FrameMemoryAddress), // e.g., load reg from frame
166    WriteBaseRegWithOffset(RegIndex, MemoryOffset),
167    ReadBaseRegWithOffset(RegIndex, MemoryOffset),
168    ImmediateU8(u8),
169    ImmediateU16(u16),
170    ImmediateU32(u32),
171    CountU16(u16),
172    CountU8(u8),
173    WriteMask(u8),
174    ReadMask(u8),
175}
176
177pub struct DecoratedOperandOrigin {}
178
179pub struct DecoratedOperand {
180    pub kind: DecoratedOperandAccessKind,
181    pub origin: DecoratedOperandOrigin,
182}
183
184pub struct DecoratedOpcode {
185    pub name: String,
186    pub operands: Vec<DecoratedOperand>,
187}
188
189#[derive(Clone, Debug)]
190pub struct MemoryElement {
191    pub offset: MemoryOffset,
192    pub size: MemorySize,
193    pub alignment: MemoryAlignment,
194}
195
196#[derive(Clone, Debug)]
197pub enum BasicTypeKind {
198    Empty,
199    U8,
200    B8,
201    U16,
202    S32,
203    Fixed32,
204    U32,
205    StringView {
206        byte: BasicTypeRef,
207        char: BasicTypeRef,
208    },
209    Struct(StructType),
210    TaggedUnion(TaggedUnion),
211    Tuple(TupleType),
212    Optional(TaggedUnion),
213    InternalRangeHeader,
214
215    // Can not be stored:
216    InternalVecIterator,
217    InternalStringIterator,
218    InternalMapIterator,
219    InternalSparseIterator,
220    InternalRangeIterator,
221    //InternalGridIterator,
222    SliceView(BasicTypeRef),
223
224    // Collections
225    FixedCapacityArray(BasicTypeRef, usize),
226    DynamicLengthVecView(BasicTypeRef),
227    VecStorage(BasicTypeRef, usize),
228    StringStorage {
229        element_type: BasicTypeRef,
230        char: BasicTypeRef,
231        capacity: usize,
232    },
233    StackStorage(BasicTypeRef, usize),
234    QueueStorage(BasicTypeRef, usize),
235    MapStorage {
236        key_type: BasicTypeRef,
237        value_type: BasicTypeRef,
238        logical_limit: usize,
239        capacity: CountU16,
240    },
241    SparseView(BasicTypeRef),
242    SparseStorage(BasicTypeRef, usize),
243
244    DynamicLengthMapView(Box<OffsetMemoryItem>, Box<OffsetMemoryItem>),
245    // DynamicLengthMapView(),
246    GridView(BasicTypeRef),
247    GridStorage(BasicTypeRef, usize, usize),
248}
249
250impl BasicTypeKind {}
251
252impl BasicTypeKind {
253    pub(crate) const fn manifestation(&self) -> Manifestation {
254        if self.is_scalar() {
255            Manifestation::Scalar
256        } else {
257            Manifestation::Aggregate
258        }
259    }
260
261    #[must_use]
262    pub fn element(&self) -> Option<BasicTypeRef> {
263        match &self {
264            Self::StackStorage(inner, _)
265            | Self::GridView(inner)
266            | Self::GridStorage(inner, ..)
267            | Self::SparseStorage(inner, _)
268            | Self::SparseView(inner)
269            | Self::QueueStorage(inner, _)
270            | Self::DynamicLengthVecView(inner)
271            | Self::FixedCapacityArray(inner, _)
272            | Self::VecStorage(inner, _)
273            | Self::SliceView(inner) => Some(inner.clone()),
274
275            Self::StringStorage { char, .. } | Self::StringView { char, .. } => Some(char.clone()),
276
277            _ => None,
278        }
279    }
280}
281
282pub enum Manifestation {
283    Scalar,
284    Aggregate,
285}
286
287impl Manifestation {
288    #[must_use]
289    pub const fn string(&self) -> &str {
290        match self {
291            Self::Scalar => "scalar",
292            Self::Aggregate => "aggregate",
293        }
294    }
295}
296
297impl Display for Manifestation {
298    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
299        write!(f, "{}", self.string())
300    }
301}
302
303impl BasicTypeKind {
304    pub(crate) const fn is_scalar(&self) -> bool {
305        matches!(
306            self,
307            Self::Empty
308                | Self::B8
309                | Self::U8
310                | Self::U16
311                | Self::S32
312                | Self::U32
313                | Self::Fixed32
314                | Self::StringView { .. }
315        )
316    }
317
318    #[must_use]
319    pub const fn is_aggregate(&self) -> bool {
320        !self.is_scalar()
321    }
322
323    #[must_use]
324    pub const fn is_mutable_reference(&self) -> bool {
325        false // MutablePointer removed - mutability is handled at analyzer level
326    }
327
328    pub(crate) const fn is_immutable(&self) -> bool {
329        !self.is_mutable_reference()
330    }
331
332    #[must_use]
333    pub const fn needs_copy_back_when_mutable(&self) -> bool {
334        self.is_scalar()
335    }
336
337    #[must_use]
338    pub fn union_info(&self) -> &TaggedUnion {
339        if let Self::TaggedUnion(union) = self {
340            union
341        } else {
342            panic!("wrong type")
343        }
344    }
345}
346
347impl Display for BasicTypeKind {
348    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
349        match self {
350            Self::Empty => write!(f, "()"),
351            Self::U8 => write!(f, "u8"),
352            Self::B8 => write!(f, "b8"),
353            Self::U16 => write!(f, "u16"),
354            Self::S32 => write!(f, "i32"),
355            Self::Fixed32 => write!(f, "Fixed(i32)"),
356            Self::U32 => write!(f, "u32"),
357            Self::StringView { .. } => write!(f, "String"),
358            Self::InternalRangeHeader => write!(f, "Range"),
359            Self::FixedCapacityArray(item_type, size) => write!(f, "[{item_type}; {size}]"),
360            Self::DynamicLengthVecView(item_type) => write!(f, "Vec<{item_type}>"),
361            Self::VecStorage(item_type, size) => write!(f, "Vec<{item_type}, {size}>"),
362            Self::StringStorage {
363                element_type: byte,
364                capacity,
365                ..
366            } => write!(f, "String<{byte}, {capacity}>"),
367            Self::SparseView(item_type) => write!(f, "Sparse<{item_type}>"),
368            Self::GridView(item_type) => write!(f, "Grid<{item_type}>"),
369            Self::SparseStorage(item_type, size) => write!(f, "SparseStorage<{item_type}, {size}>"),
370            Self::StackStorage(item_type, size) => write!(f, "StackStorage<{item_type}, {size}>"),
371            Self::GridStorage(item_type, width, height) => {
372                write!(f, "GridStorage<{item_type}, ({width},{height})>")
373            }
374            Self::QueueStorage(item_type, size) => write!(f, "QueueStorage<{item_type}, {size}>"),
375            Self::MapStorage {
376                logical_limit: logical_size,
377                capacity,
378                key_type,
379                value_type,
380                ..
381            } => write!(
382                f,
383                "MapStorage<{key_type}, {value_type}, {logical_size} ({capacity})>",
384            ),
385            Self::DynamicLengthMapView(key, value) => write!(f, "Map<{key}, {value}>"),
386            Self::InternalVecIterator => write!(f, "Vec::Iterator"),
387            Self::InternalStringIterator => write!(f, "String::Iterator"),
388            Self::InternalMapIterator => write!(f, "Map::Iterator"),
389            Self::InternalSparseIterator => write!(f, "Sparse::Iterator"),
390            Self::InternalRangeIterator => write!(f, "Range::Iterator"),
391            Self::Struct(struct_type) => write!(f, "{}", struct_type.name),
392            Self::TaggedUnion(union) => write!(f, "enum {}", union.name),
393            Self::Optional(optional) => write!(f, "{}?", optional.get_variant_by_index(1).ty),
394            Self::Tuple(tuple_type) => write!(f, "({})", comma(&tuple_type.fields)),
395            Self::SliceView(a) => write!(f, "slice<{}>", a.kind),
396        }
397    }
398}
399
400#[must_use]
401pub fn pointer_type_again() -> BasicTypeRef {
402    Rc::new(BasicType {
403        id: BasicTypeId::EMPTY,
404        kind: BasicTypeKind::U8, // Generic pointer type
405        total_size: MemorySize(4),
406        max_alignment: MemoryAlignment::U32,
407    })
408}
409
410// HACK:
411#[must_use]
412pub fn string_type() -> BasicTypeRef {
413    Rc::new(BasicType {
414        id: BasicTypeId::EMPTY,
415        kind: BasicTypeKind::U8,
416        total_size: STRING_PTR_SIZE,
417        max_alignment: STRING_PTR_ALIGNMENT,
418    })
419}
420// Hack:
421#[must_use]
422pub fn int_type() -> BasicTypeRef {
423    Rc::new(BasicType {
424        id: BasicTypeId::EMPTY,
425        kind: BasicTypeKind::S32,
426        total_size: MemorySize(4),
427        max_alignment: MemoryAlignment::U32,
428    })
429}
430
431// Hack
432#[must_use]
433pub fn float_type() -> BasicTypeRef {
434    Rc::new(BasicType {
435        id: BasicTypeId::EMPTY,
436        kind: BasicTypeKind::Fixed32,
437        total_size: MemorySize(4),
438        max_alignment: MemoryAlignment::U32,
439    })
440}
441
442// HACK
443#[must_use]
444pub fn bytes_type() -> BasicTypeRef {
445    Rc::new(BasicType {
446        id: BasicTypeId::EMPTY,
447        kind: BasicTypeKind::Empty,
448        total_size: MemorySize(0),
449        max_alignment: MemoryAlignment::U32,
450    })
451}
452
453#[must_use]
454pub const fn range_type() -> BasicType {
455    BasicType {
456        id: BasicTypeId::EMPTY,
457        kind: BasicTypeKind::InternalRangeHeader,
458        total_size: RANGE_HEADER_SIZE,
459        max_alignment: RANGE_HEADER_ALIGNMENT,
460    }
461}
462
463#[must_use]
464pub const fn range_iter_type() -> BasicType {
465    BasicType {
466        id: BasicTypeId::EMPTY,
467        kind: BasicTypeKind::InternalRangeIterator,
468        total_size: RANGE_ITERATOR_SIZE,
469        max_alignment: RANGE_ITERATOR_ALIGNMENT,
470    }
471}
472
473#[must_use]
474pub fn slice_type() -> BasicType {
475    BasicType {
476        id: BasicTypeId::EMPTY,
477        kind: BasicTypeKind::SliceView(BasicTypeRef::from(u8_type())), // todo: fix
478        total_size: MAP_HEADER_SIZE,
479        max_alignment: MAP_HEADER_ALIGNMENT,
480    }
481}
482
483// HACK: Used when we don't know the actual type. that should be a rare case.
484#[must_use]
485pub fn unknown_type() -> BasicTypeRef {
486    Rc::new(BasicType {
487        id: BasicTypeId::EMPTY,
488        kind: BasicTypeKind::Empty,
489        total_size: MemorySize(0),
490        max_alignment: MemoryAlignment::U8,
491    })
492}
493
494#[must_use]
495pub fn vec_type() -> BasicType {
496    BasicType {
497        id: BasicTypeId::EMPTY,
498        kind: BasicTypeKind::DynamicLengthVecView(BasicTypeRef::from(unknown_type())),
499        total_size: VEC_PTR_SIZE,
500        max_alignment: VEC_PTR_ALIGNMENT,
501    }
502}
503
504#[must_use]
505pub const fn vec_iter_type() -> BasicType {
506    BasicType {
507        id: BasicTypeId::EMPTY,
508        kind: BasicTypeKind::InternalVecIterator,
509        total_size: VEC_ITERATOR_SIZE,
510        max_alignment: VEC_ITERATOR_ALIGNMENT,
511    }
512}
513
514#[must_use]
515pub fn map_type() -> BasicType {
516    BasicType {
517        id: BasicTypeId::EMPTY,
518        kind: BasicTypeKind::DynamicLengthMapView(
519            Box::from(OffsetMemoryItem {
520                offset: MemoryOffset(0),
521                size: MemorySize(0),
522                name: String::new(),
523                ty: Rc::new(BasicType {
524                    id: BasicTypeId::EMPTY,
525                    kind: BasicTypeKind::Empty,
526                    total_size: MemorySize(0),
527                    max_alignment: MemoryAlignment::U8,
528                }),
529            }),
530            Box::from(OffsetMemoryItem {
531                offset: MemoryOffset(0),
532                size: MemorySize(0),
533                name: String::new(),
534                ty: Rc::new(BasicType {
535                    id: BasicTypeId::EMPTY,
536                    kind: BasicTypeKind::Empty,
537                    total_size: MemorySize(0),
538                    max_alignment: MemoryAlignment::U8,
539                }),
540            }),
541        ),
542
543        total_size: MAP_HEADER_SIZE,
544        max_alignment: MAP_HEADER_ALIGNMENT,
545    }
546}
547
548#[must_use]
549pub const fn map_iter_type() -> BasicType {
550    BasicType {
551        id: BasicTypeId::EMPTY,
552        kind: BasicTypeKind::InternalMapIterator,
553        total_size: MAP_ITERATOR_SIZE,
554        max_alignment: MAP_ITERATOR_ALIGNMENT,
555    }
556}
557
558// HACK: a way to go around the cache. must be fixed.
559#[must_use]
560pub fn u32_type() -> BasicTypeRef {
561    Rc::new(BasicType {
562        id: BasicTypeId::EMPTY,
563        kind: BasicTypeKind::U32,
564        total_size: MemorySize(4),
565        max_alignment: MemoryAlignment::U32,
566    })
567}
568
569#[must_use]
570pub fn u16_type() -> BasicTypeRef {
571    Rc::new(BasicType {
572        id: BasicTypeId::EMPTY,
573        kind: BasicTypeKind::U16,
574        total_size: MemorySize(2),
575        max_alignment: MemoryAlignment::U16,
576    })
577}
578
579// HACK:
580#[must_use]
581pub fn u8_type() -> BasicTypeRef {
582    Rc::new(BasicType {
583        id: BasicTypeId::EMPTY,
584        kind: BasicTypeKind::U8,
585        total_size: MemorySize(1),
586        max_alignment: MemoryAlignment::U8,
587    })
588}
589
590// HACK: should go through the cache
591#[must_use]
592pub fn b8_type() -> BasicTypeRef {
593    Rc::new(BasicType {
594        id: BasicTypeId::EMPTY,
595        kind: BasicTypeKind::B8,
596        total_size: MemorySize(1),
597        max_alignment: MemoryAlignment::U8,
598    })
599}
600
601// This is a hack, used when we don't know what
602// the actual type is
603#[must_use]
604pub fn pointer_type() -> BasicTypeRef {
605    // This is a
606    Rc::new(BasicType {
607        id: BasicTypeId::EMPTY,
608        kind: BasicTypeKind::U8, // Generic pointer type
609        total_size: HEAP_PTR_ON_FRAME_SIZE,
610        max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
611    })
612}
613
614/// Represents a type that has been allocated to a heap relative address
615#[derive(Clone, Debug)]
616pub struct HeapPlacedArray {
617    addr: HeapMemoryAddress,
618    byte_count: u32,
619}
620
621impl HeapPlacedArray {
622    #[must_use]
623    pub const fn new(addr: HeapMemoryAddress, byte_count: u32) -> Self {
624        Self { addr, byte_count }
625    }
626
627    #[must_use]
628    pub const fn addr(&self) -> HeapMemoryAddress {
629        self.addr
630    }
631
632    #[must_use]
633    pub const fn byte_count(&self) -> u32 {
634        self.byte_count
635    }
636}
637
638/// Represents a type that has been allocated to a frame relative address
639#[derive(Clone, Debug)]
640pub struct HeapPlacedType {
641    addr: HeapMemoryAddress,
642    ty: BasicTypeRef,
643}
644
645impl HeapPlacedType {
646    #[must_use]
647    pub const fn new(addr: HeapMemoryAddress, ty: BasicTypeRef) -> Self {
648        Self { addr, ty }
649    }
650
651    #[must_use]
652    pub fn region(&self) -> HeapMemoryRegion {
653        HeapMemoryRegion {
654            addr: self.addr,
655            size: self.ty.total_size,
656        }
657    }
658
659    #[must_use]
660    pub const fn addr(&self) -> HeapMemoryAddress {
661        self.addr
662    }
663
664    #[must_use]
665    pub fn size(&self) -> MemorySize {
666        self.ty.total_size
667    }
668
669    #[must_use]
670    pub const fn ty(&self) -> &BasicTypeRef {
671        &self.ty
672    }
673}
674
675#[derive(Clone, Debug)]
676pub enum Destination {
677    Unit, // no output
678    Register(TypedRegister),
679    Memory(MemoryLocation),
680}
681
682impl Destination {
683    #[must_use]
684    pub const fn vm_type(&self) -> Option<&VmType> {
685        match self {
686            Self::Unit => None,
687            Self::Register(reg) => Some(&reg.ty),
688            Self::Memory(mem) => Some(&mem.ty),
689        }
690    }
691}
692
693impl Display for Destination {
694    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
695        match self {
696            Self::Unit => write!(f, "unit ()"),
697            Self::Register(reg) => write!(f, "reg: {reg}"),
698            Self::Memory(memory_location) => write!(f, "memory_location {memory_location:?}"),
699        }
700    }
701}
702
703impl Destination {
704    #[must_use]
705    pub const fn memory_location(&self) -> Option<&MemoryLocation> {
706        match self {
707            Self::Unit => None,
708            Self::Register(_) => None,
709            Self::Memory(memory_location) => Some(memory_location),
710        }
711    }
712}
713
714impl Destination {
715    #[must_use]
716    pub fn add_offset(&self, offset: MemoryOffset, vm_type: VmType) -> Self {
717        match self {
718            Self::Unit => {
719                panic!("add_offset")
720            }
721            Self::Register(reg) => {
722                if reg.ty.is_aggregate() {
723                    Self::Memory(MemoryLocation {
724                        base_ptr_reg: reg.clone(),
725                        offset,
726                        ty: vm_type,
727                    })
728                } else {
729                    panic!(
730                        "can not add offset to a register since it wasn't an aggregate {}",
731                        reg.ty
732                    )
733                }
734            }
735            Self::Memory(memory_location) => Self::Memory(MemoryLocation {
736                base_ptr_reg: memory_location.base_ptr_reg.clone(),
737                offset: memory_location.offset + offset,
738                ty: vm_type,
739            }),
740        }
741    }
742    #[must_use]
743    pub const fn new_unit() -> Self {
744        Self::Unit
745    }
746    #[must_use]
747    pub const fn new_reg(register: TypedRegister) -> Self {
748        Self::Register(register)
749    }
750    #[must_use]
751    pub const fn new_location(memory_location: MemoryLocation) -> Self {
752        Self::Memory(memory_location)
753    }
754
755    #[must_use]
756    pub const fn is_unit(&self) -> bool {
757        matches!(self, Self::Unit)
758    }
759    #[must_use]
760    pub const fn is_memory_location(&self) -> bool {
761        matches!(self, Self::Memory(_))
762    }
763
764    #[must_use]
765    pub const fn is_register(&self) -> bool {
766        matches!(self, Self::Register(_))
767    }
768    #[must_use]
769    pub fn ty(&self) -> &BasicTypeRef {
770        match self {
771            Self::Unit => panic!("no type"),
772            Self::Register(reg) => &reg.ty.basic_type,
773            Self::Memory(location) => &location.ty.basic_type,
774        }
775    }
776
777    #[must_use]
778    pub const fn register(&self) -> Option<&TypedRegister> {
779        match self {
780            Self::Register(reg) => Some(reg),
781            _ => None,
782        }
783    }
784
785    #[must_use]
786    pub const fn register_involved_in_destination(&self) -> Option<&TypedRegister> {
787        match self {
788            Self::Register(reg) => Some(reg),
789            Self::Memory(memory_location) => Some(memory_location.reg()),
790            Self::Unit => None,
791        }
792    }
793
794    #[must_use]
795    pub fn grab_register(&self) -> &TypedRegister {
796        match self {
797            Self::Register(reg) => reg,
798            Self::Memory(_) => {
799                panic!("assumed it would be a register")
800            }
801            Self::Unit => panic!("assumed it would be a register, but was unit"),
802        }
803    }
804
805    #[must_use]
806    pub fn grab_memory_location(&self) -> &MemoryLocation {
807        match self {
808            Self::Register(_reg) => panic!("assumed it was a memory location"),
809            Self::Memory(location) => location,
810            Self::Unit => {
811                panic!("assumed it would be a memory location, but was unit")
812            }
813        }
814    }
815
816    /// Use if you know for a fact that the Destination is a memory location
817    /// Either a `base_reg` + `offset` or a normal reg (usually from a variable)
818    #[must_use]
819    pub fn memory_location_or_pointer_reg(&self) -> MemoryLocation {
820        match self {
821            Self::Register(reg) => MemoryLocation {
822                base_ptr_reg: reg.clone(),
823                offset: MemoryOffset(0),
824                ty: reg.ty.clone(),
825            },
826            Self::Memory(location) => location.clone(),
827            Self::Unit => {
828                panic!("assumed it would be a memory location, but was unit")
829            }
830        }
831    }
832
833    #[must_use]
834    pub fn grab_aggregate_memory_location_or_pointer_reg(&self) -> AggregateMemoryLocation {
835        AggregateMemoryLocation {
836            location: self.memory_location_or_pointer_reg(),
837        }
838    }
839    #[must_use]
840    pub fn grab_aggregate_memory_location(&self) -> AggregateMemoryLocation {
841        AggregateMemoryLocation {
842            location: self.grab_memory_location().clone(),
843        }
844    }
845}
846
847#[derive(Clone)]
848pub struct TypedRegister {
849    pub index: u8,
850    pub ty: VmType,
851    pub comment: String,
852}
853
854impl PartialEq<Self> for TypedRegister {
855    fn eq(&self, other: &Self) -> bool {
856        self.index == other.index
857    }
858}
859
860impl Eq for TypedRegister {}
861
862impl Ord for TypedRegister {
863    fn cmp(&self, other: &Self) -> Ordering {
864        self.index.cmp(&other.index)
865    }
866}
867impl PartialOrd<Self> for TypedRegister {
868    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
869        self.index.partial_cmp(&other.index)
870    }
871}
872
873impl TypedRegister {
874    #[must_use]
875    pub fn comment(&self) -> &str {
876        &self.comment
877    }
878}
879
880impl TypedRegister {
881    #[must_use]
882    pub fn new_empty_reserved() -> Self {
883        Self {
884            index: 0xff,
885            ty: VmType::new_unknown_placement(BasicTypeRef::from(unknown_type())),
886            comment: String::new(),
887        }
888    }
889}
890
891impl TypedRegister {
892    #[must_use]
893    pub fn final_type(&self) -> BasicTypeRef {
894        self.ty.basic_type.clone()
895    }
896}
897
898impl Debug for TypedRegister {
899    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
900        write!(f, "r{} ({} - {})", self.index, self.ty, self.comment)
901    }
902}
903
904impl Display for TypedRegister {
905    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
906        write!(f, "r{}", self.index)
907    }
908}
909
910impl TypedRegister {
911    #[must_use]
912    pub fn new_frame_placed(index: u8, frame_placed: FramePlacedType) -> Self {
913        Self {
914            index,
915            ty: VmType::new_frame_placed(frame_placed),
916            comment: String::new(),
917        }
918    }
919
920    #[must_use]
921    pub const fn new_vm_type(index: u8, ty: VmType) -> Self {
922        Self {
923            index,
924            ty,
925            comment: String::new(),
926        }
927    }
928
929    pub fn with_comment(&mut self, comment: &str) -> &mut Self {
930        self.comment = comment.to_string();
931        self
932    }
933    #[must_use]
934    pub const fn addressing(&self) -> u8 {
935        self.index
936    }
937
938    #[must_use]
939    pub const fn ty(&self) -> &BasicTypeRef {
940        &self.ty.basic_type
941    }
942
943    #[must_use]
944    pub fn frame_placed(&self) -> FramePlacedType {
945        if let Some(fp) = self.ty.frame_placed_type() {
946            fp
947        } else {
948            panic!("")
949        }
950    }
951
952    #[must_use]
953    pub fn size(&self) -> MemorySize {
954        self.ty.basic_type.total_size
955    }
956
957    #[must_use]
958    pub fn addr(&self) -> FrameMemoryAddress {
959        self.frame_placed().addr
960    }
961
962    #[must_use]
963    pub fn region(&self) -> FrameMemoryRegion {
964        self.frame_placed().region()
965    }
966
967    #[must_use]
968    pub fn underlying(&self) -> BasicTypeRef {
969        self.ty.basic_type.clone()
970    }
971}
972
973#[derive(Clone, Debug)]
974pub enum VmTypeOrigin {
975    Unknown,
976    InsideReg,
977    Frame(FrameMemoryRegion),
978    Heap(HeapMemoryRegion), // Constants only?
979}
980
981impl Display for VmTypeOrigin {
982    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
983        match self {
984            Self::Unknown => Ok(()),
985            Self::Frame(region) => write!(f, "frame {region}"),
986            Self::Heap(region) => write!(f, "heap {region}"),
987            Self::InsideReg => write!(f, "reg"),
988        }
989    }
990}
991
992#[derive(Clone, Debug)]
993pub struct VmType {
994    pub basic_type: BasicTypeRef,
995    pub origin: VmTypeOrigin,
996}
997
998impl VmType {}
999
1000impl VmType {
1001    #[must_use]
1002    pub fn is_collection_like(&self) -> bool {
1003        self.basic_type.is_collection_like()
1004    }
1005}
1006
1007impl VmType {
1008    #[must_use]
1009    pub fn is_mutable_primitive(&self) -> bool {
1010        self.basic_type.is_mutable_reference()
1011            && self
1012            .basic_type
1013            .should_be_copied_back_when_mutable_arg_or_return()
1014    }
1015
1016    #[must_use]
1017    pub fn element_count_always_same_as_capacity(&self) -> bool {
1018        self.basic_type.element_count_always_same_as_capacity()
1019    }
1020}
1021
1022impl Display for VmType {
1023    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1024        write!(
1025            f,
1026            "{} {} {}",
1027            tinter::bright_green(&self.basic_type),
1028            self.origin,
1029            tinter::bright_magenta(self.manifestation())
1030        )
1031    }
1032}
1033
1034impl VmType {
1035    #[must_use]
1036    pub fn new_frame_placed(frame_placed: FramePlacedType) -> Self {
1037        Self {
1038            basic_type: frame_placed.ty.clone(),
1039            origin: VmTypeOrigin::Frame(frame_placed.region()),
1040        }
1041    }
1042    #[must_use]
1043    pub fn is_immutable(&self) -> bool {
1044        self.basic_type.kind.is_immutable()
1045    }
1046
1047    #[must_use]
1048    pub fn manifestation(&self) -> Manifestation {
1049        self.basic_type.manifestation()
1050    }
1051
1052    #[must_use]
1053    pub const fn new_heap_placement(
1054        basic_type: BasicTypeRef,
1055        heap_region: HeapMemoryRegion,
1056    ) -> Self {
1057        Self {
1058            basic_type,
1059            origin: VmTypeOrigin::Heap(heap_region),
1060        }
1061    }
1062
1063    #[must_use]
1064    pub const fn new_contained_in_register(basic_type: BasicTypeRef) -> Self {
1065        Self {
1066            basic_type,
1067            origin: VmTypeOrigin::InsideReg,
1068        }
1069    }
1070
1071    #[must_use]
1072    pub const fn new_unknown_placement(basic_type: BasicTypeRef) -> Self {
1073        Self {
1074            basic_type,
1075            origin: VmTypeOrigin::Unknown,
1076        }
1077    }
1078
1079    #[must_use]
1080    pub const fn new_basic_with_origin(basic_type: BasicTypeRef, origin: VmTypeOrigin) -> Self {
1081        Self { basic_type, origin }
1082    }
1083
1084    #[must_use]
1085    pub fn frame_placed_type(&self) -> Option<FramePlacedType> {
1086        if let VmTypeOrigin::Frame(region) = self.origin {
1087            Some(FramePlacedType {
1088                addr: region.addr,
1089                ty: self.basic_type.clone(),
1090            })
1091        } else {
1092            None
1093        }
1094    }
1095
1096    #[must_use]
1097    pub fn is_mutable_reference_semantic(&self) -> bool {
1098        self.basic_type.is_mutable_reference()
1099    }
1100
1101    #[must_use]
1102    pub fn is_aggregate(&self) -> bool {
1103        self.basic_type.is_aggregate()
1104    }
1105
1106    #[must_use]
1107    pub fn is_scalar(&self) -> bool {
1108        self.basic_type.is_scalar()
1109    }
1110
1111    #[must_use]
1112    pub fn needs_allocated_space_for_return_in_reg0(&self) -> bool {
1113        self.basic_type.is_aggregate()
1114            && !matches!(self.basic_type.kind, BasicTypeKind::StringView { .. })
1115    }
1116
1117    #[must_use]
1118    pub fn needs_copy_back_for_mutable(&self) -> bool {
1119        !self.basic_type.is_aggregate()
1120            || matches!(self.basic_type.kind, BasicTypeKind::StringView { .. })
1121    }
1122    #[must_use]
1123    pub const fn basic_type(&self) -> &BasicTypeRef {
1124        &self.basic_type
1125    }
1126}
1127
1128/// Represents a type that has been allocated to a frame relative address
1129#[derive(Clone, Debug)]
1130pub struct FramePlacedType {
1131    addr: FrameMemoryAddress,
1132    ty: BasicTypeRef,
1133}
1134
1135impl FramePlacedType {
1136    #[must_use]
1137    pub const fn new(addr: FrameMemoryAddress, ty: BasicTypeRef) -> Self {
1138        Self { addr, ty }
1139    }
1140
1141    #[must_use]
1142    pub fn region(&self) -> FrameMemoryRegion {
1143        FrameMemoryRegion {
1144            addr: self.addr,
1145            size: self.ty.total_size,
1146        }
1147    }
1148
1149    #[must_use]
1150    pub const fn addr(&self) -> FrameMemoryAddress {
1151        self.addr
1152    }
1153
1154    #[must_use]
1155    pub fn size(&self) -> MemorySize {
1156        self.ty.total_size
1157    }
1158
1159    #[must_use]
1160    pub fn ty(&self) -> &BasicType {
1161        &self.ty
1162    }
1163
1164    #[must_use]
1165    pub fn final_type(&self) -> BasicTypeRef {
1166        self.ty.clone()
1167    }
1168
1169    #[must_use]
1170    pub fn move_with_offset(&self, offset: MemoryOffset, ty: BasicTypeRef) -> Self {
1171        Self {
1172            addr: self.addr + offset,
1173            ty,
1174        }
1175    }
1176
1177    #[must_use]
1178    pub fn move_to_field(&self, index: usize) -> Self {
1179        let offset_info = self.ty.get_field_offset(index).unwrap();
1180        Self {
1181            addr: self.addr + offset_info.offset,
1182            ty: offset_info.ty.clone(),
1183        }
1184    }
1185
1186    #[must_use]
1187    pub fn move_to_optional_some_payload(&self) -> Self {
1188        self.move_to_optional_payload_variant(1)
1189    }
1190
1191    #[must_use]
1192    pub fn move_to_optional_none_payload(&self) -> Self {
1193        self.move_to_optional_payload_variant(0)
1194    }
1195
1196    #[must_use]
1197    pub fn move_to_optional_payload_variant(&self, index: usize) -> Self {
1198        let optional_info = self.ty.optional_info().unwrap();
1199        Self::new(
1200            self.addr + optional_info.payload_offset,
1201            optional_info.get_variant_by_index(index).ty.clone(),
1202        )
1203    }
1204
1205    #[must_use]
1206    pub fn move_to_optional_tag(&self) -> Self {
1207        let optional_info = self.ty().optional_info().unwrap();
1208
1209        let addr = self.addr() + optional_info.tag_offset;
1210        assert_eq!(optional_info.tag_size.0, 1);
1211
1212        let tag_type = Rc::new(BasicType {
1213            id: BasicTypeId::EMPTY,
1214            kind: BasicTypeKind::B8,
1215            total_size: MemorySize(1),
1216            max_alignment: MemoryAlignment::U8,
1217        });
1218
1219        Self::new(addr, tag_type)
1220    }
1221}
1222
1223pub enum BoundsCheck {
1224    KnownSizeAtCompileTime(u16),
1225    RegisterWithMaxCount(TypedRegister),
1226}
1227
1228#[derive(Clone, Debug)]
1229pub struct BasicTypeId(pub u32);
1230
1231impl BasicTypeId {
1232    pub const EMPTY: Self = Self(0xffff_ffff);
1233}
1234
1235#[derive(Clone, Debug)]
1236pub struct BasicType {
1237    pub id: BasicTypeId,
1238    pub kind: BasicTypeKind,
1239    pub total_size: MemorySize,
1240    pub max_alignment: MemoryAlignment,
1241}
1242
1243impl BasicType {
1244    #[must_use]
1245    pub const fn is_vec_like(&self) -> bool {
1246        matches!(
1247            self.kind,
1248            BasicTypeKind::VecStorage(..)
1249                | BasicTypeKind::StringStorage { .. }
1250                | BasicTypeKind::StackStorage(..)
1251                | BasicTypeKind::QueueStorage(..)
1252                | BasicTypeKind::StringView { .. }
1253                | BasicTypeKind::SliceView(..)
1254                | BasicTypeKind::FixedCapacityArray(..)
1255                | BasicTypeKind::DynamicLengthVecView(..)
1256        )
1257    }
1258
1259    #[must_use]
1260    pub fn element(&self) -> Option<BasicTypeRef> {
1261        self.kind.element()
1262    }
1263
1264    #[must_use]
1265    pub const fn is_collection(&self) -> bool {
1266        matches!(
1267            self.kind,
1268            BasicTypeKind::VecStorage(..)
1269                | BasicTypeKind::StringStorage { .. }
1270                | BasicTypeKind::SliceView(..)
1271                | BasicTypeKind::FixedCapacityArray(..)
1272                | BasicTypeKind::DynamicLengthVecView(..)
1273                | BasicTypeKind::MapStorage { .. }
1274                | BasicTypeKind::DynamicLengthMapView(..)
1275                | BasicTypeKind::GridStorage(..)
1276                | BasicTypeKind::GridView(..)
1277                | BasicTypeKind::SparseStorage(..)
1278                | BasicTypeKind::SparseView(..)
1279                | BasicTypeKind::StackStorage(..)
1280                | BasicTypeKind::QueueStorage(..)
1281        )
1282    }
1283
1284    #[must_use]
1285    pub fn might_contain_collections(&self) -> bool {
1286        match &self.kind {
1287            BasicTypeKind::Struct(struct_type) => struct_type
1288                .fields
1289                .iter()
1290                .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1291            BasicTypeKind::Tuple(tuple_type) => tuple_type
1292                .fields
1293                .iter()
1294                .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1295            BasicTypeKind::TaggedUnion(union_type) => union_type.variants.iter().any(|variant| {
1296                variant.ty.is_collection() || variant.ty.might_contain_collections()
1297            }),
1298            BasicTypeKind::Optional(union_type) => union_type.variants.iter().any(|variant| {
1299                variant.ty.is_collection() || variant.ty.might_contain_collections()
1300            }),
1301            BasicTypeKind::MapStorage { value_type, .. } => {
1302                value_type.is_collection() || value_type.might_contain_collections()
1303            }
1304            _ => false,
1305        }
1306    }
1307
1308    pub(crate) const fn element_count_always_same_as_capacity(&self) -> bool {
1309        matches!(self.kind, BasicTypeKind::FixedCapacityArray(..))
1310    }
1311    #[must_use]
1312    pub const fn is_collection_like(&self) -> bool {
1313        matches!(
1314            self.kind,
1315            BasicTypeKind::FixedCapacityArray(..)
1316            // Vec
1317            | BasicTypeKind::VecStorage(..)
1318            | BasicTypeKind::StackStorage(..)
1319            | BasicTypeKind::DynamicLengthVecView(..)
1320            // Map
1321            | BasicTypeKind::MapStorage {  ..}
1322            | BasicTypeKind::DynamicLengthMapView(..)
1323        )
1324    }
1325    #[must_use]
1326    pub const fn is_collection_with_capacity(&self) -> bool {
1327        matches!(
1328            self.kind,
1329            BasicTypeKind::FixedCapacityArray(..)
1330            // Vec
1331            | BasicTypeKind::VecStorage(..)
1332            | BasicTypeKind::StringStorage {..}
1333            // Map
1334            | BasicTypeKind::MapStorage { ..}
1335        )
1336    }
1337}
1338
1339impl BasicType {
1340    pub(crate) const fn manifestation(&self) -> Manifestation {
1341        self.kind.manifestation()
1342    }
1343}
1344
1345impl BasicType {
1346    #[must_use]
1347    pub const fn should_be_copied_back_when_mutable_arg_or_return(&self) -> bool {
1348        !self.is_aggregate()
1349    }
1350}
1351
1352impl BasicType {
1353    #[must_use]
1354    pub fn referenced_type(&self) -> &Self {
1355        // MutablePointer removed - mutability handled at analyzer level
1356        panic!("referenced_type() is no longer supported - MutablePointer was removed")
1357    }
1358}
1359
1360impl BasicType {
1361    #[must_use]
1362    pub const fn make_pointer(&self) -> Self {
1363        // MutablePointer removed - return a generic pointer type
1364        Self {
1365            id: BasicTypeId::EMPTY,
1366            kind: BasicTypeKind::U8,
1367            total_size: HEAP_PTR_ON_FRAME_SIZE,
1368            max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1369        }
1370    }
1371}
1372
1373impl BasicType {}
1374
1375impl BasicType {
1376    #[must_use]
1377    pub fn get_variant(&self, variant_index: usize) -> &TaggedUnionVariant {
1378        match &self.kind {
1379            BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => {
1380                tagged.get_variant_by_index(variant_index)
1381            }
1382            _ => panic!("type is not a tagged union"),
1383        }
1384    }
1385}
1386
1387impl BasicType {
1388    #[must_use]
1389    pub const fn is_scalar(&self) -> bool {
1390        self.kind.is_scalar()
1391    }
1392
1393    #[must_use]
1394    pub const fn is_mutable_reference(&self) -> bool {
1395        self.kind.is_mutable_reference()
1396    }
1397}
1398
1399impl BasicType {
1400    #[must_use]
1401    pub const fn unwrap_info(
1402        &self,
1403    ) -> Option<(MemoryOffset, MemorySize, MemoryOffset, MemorySize)> {
1404        match &self.kind {
1405            BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => Some((
1406                tagged.tag_offset,
1407                tagged.tag_size,
1408                tagged.payload_offset,
1409                tagged.payload_max_size,
1410            )),
1411            _ => None,
1412        }
1413    }
1414
1415    #[must_use]
1416    pub fn union_info(&self) -> &TaggedUnion {
1417        self.kind.union_info()
1418    }
1419
1420    #[must_use]
1421    pub fn create_mutable_pointer(&self) -> Self {
1422        // MutablePointer removed - return a generic pointer type
1423        debug_assert!(!self.is_mutable_reference());
1424
1425        Self {
1426            id: BasicTypeId::EMPTY,
1427            kind: BasicTypeKind::U8,
1428            total_size: HEAP_PTR_ON_FRAME_SIZE,
1429            max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1430        }
1431    }
1432
1433    #[must_use]
1434    pub const fn is_aggregate(&self) -> bool {
1435        self.kind.is_aggregate()
1436    }
1437
1438    #[must_use]
1439    pub const fn optional_info(&self) -> Option<&TaggedUnion> {
1440        match &self.kind {
1441            BasicTypeKind::Optional(tagged_union) => Some(tagged_union),
1442            _ => None,
1443        }
1444    }
1445
1446    #[must_use]
1447    pub fn get_field_offset(&self, index: usize) -> Option<&OffsetMemoryItem> {
1448        match &self.kind {
1449            BasicTypeKind::Struct(struct_type) => struct_type.fields.get(index),
1450            BasicTypeKind::Tuple(tuple_type) => tuple_type.fields.get(index),
1451            _ => {
1452                error!(?self, "not a type with fields");
1453                None
1454            }
1455        }
1456    }
1457
1458    #[must_use]
1459    pub fn bucket_size_for_vec_like(&self) -> Option<MemorySize> {
1460        match &self.kind {
1461            BasicTypeKind::FixedCapacityArray(inner, _capacity) => Some(inner.total_size),
1462            BasicTypeKind::SliceView(inner) => Some(inner.total_size),
1463            BasicTypeKind::VecStorage(inner, _) => Some(inner.total_size),
1464            BasicTypeKind::StringStorage {
1465                element_type: byte, ..
1466            } => Some(byte.total_size),
1467            BasicTypeKind::DynamicLengthVecView(inner) => Some(inner.total_size),
1468            BasicTypeKind::StringView { .. } => Some(MemorySize(1)), // String elements are bytes (u8)
1469            _ => None,
1470        }
1471    }
1472
1473    #[must_use]
1474    pub const fn header_size_for_vec_like(&self) -> Option<MemorySize> {
1475        match &self.kind {
1476            BasicTypeKind::SliceView(_)
1477            | BasicTypeKind::DynamicLengthVecView(_)
1478            | BasicTypeKind::VecStorage(_, _)
1479            | BasicTypeKind::StringStorage { .. }
1480            | BasicTypeKind::StringView { .. } => Some(VEC_HEADER_SIZE),
1481            BasicTypeKind::DynamicLengthMapView(..) => Some(MAP_HEADER_SIZE),
1482            _ => None,
1483        }
1484    }
1485
1486    #[must_use]
1487    pub fn element_pair(&self) -> Option<(&OffsetMemoryItem, &OffsetMemoryItem)> {
1488        match &self.kind {
1489            BasicTypeKind::DynamicLengthMapView(a, b) => Some((a, b)),
1490            _ => None,
1491        }
1492    }
1493
1494    #[must_use]
1495    pub fn is_int(&self) -> bool {
1496        matches!(self.kind, BasicTypeKind::S32)
1497            && self.total_size.0 == 4
1498            && self.max_alignment == MemoryAlignment::U32
1499    }
1500
1501    #[must_use]
1502    pub fn is_codepoint(&self) -> bool {
1503        matches!(self.kind, BasicTypeKind::U32)
1504            && self.total_size.0 == 4
1505            && self.max_alignment == MemoryAlignment::U32
1506    }
1507    #[must_use]
1508    pub fn is_float(&self) -> bool {
1509        matches!(self.kind, BasicTypeKind::Fixed32)
1510            && self.total_size.0 == 4
1511            && self.max_alignment == MemoryAlignment::U32
1512    }
1513
1514    #[must_use]
1515    pub fn is_str(&self) -> bool {
1516        matches!(self.kind, BasicTypeKind::StringView { .. })
1517            && self.total_size == STRING_PTR_SIZE
1518            && self.max_alignment == STRING_PTR_ALIGNMENT
1519    }
1520
1521    #[must_use]
1522    pub fn is_bool(&self) -> bool {
1523        matches!(self.kind, BasicTypeKind::B8)
1524            && self.total_size.0 == 1
1525            && self.max_alignment == MemoryAlignment::U8
1526    }
1527    #[must_use]
1528    pub fn is_byte(&self) -> bool {
1529        matches!(self.kind, BasicTypeKind::U8)
1530            && self.total_size.0 == 1
1531            && self.max_alignment == MemoryAlignment::U8
1532    }
1533}
1534
1535impl Display for BasicType {
1536    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1537        write!(f, "{}", self.kind)
1538    }
1539}
1540
1541#[derive(Clone, Debug)]
1542pub struct VariableInfo {
1543    pub is_mutable: bool,
1544    pub name: String,
1545}
1546
1547impl Display for VariableInfo {
1548    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1549        let mut_prefix = if self.is_mutable { "mut " } else { "" };
1550
1551        let name = &self.name;
1552        write!(f, "{mut_prefix}{name}")
1553    }
1554}
1555
1556#[derive(Clone, Debug)]
1557pub enum VariableInfoKind {
1558    Variable(VariableInfo),
1559    Parameter(VariableInfo),
1560    Return,
1561}
1562
1563impl Display for VariableInfoKind {
1564    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1565        match self {
1566            Self::Variable(var_info) => {
1567                write!(f, "{} {var_info}", "var:".white())
1568            }
1569            Self::Parameter(var_info) => {
1570                write!(f, "{} {var_info}", "param:".white())
1571            }
1572            Self::Return => {
1573                write!(f, "{}", "return".white())
1574            }
1575        }
1576    }
1577}
1578
1579#[derive(Clone, Debug)]
1580pub struct FrameAddressInfo {
1581    pub kind: VariableInfoKind,
1582    pub frame_placed_type: FramePlacedType,
1583}
1584
1585#[derive(Clone, Debug)]
1586pub struct VariableRegister {
1587    pub unique_id_in_function: usize,
1588    pub variable: VariableInfo,
1589    pub register: TypedRegister,
1590}
1591
1592impl Display for VariableRegister {
1593    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1594        write!(f, "{}: {}", self.register, self.variable)
1595    }
1596}
1597
1598#[derive(Clone, Debug)]
1599pub struct VariableRegisterRange {
1600    pub start: u8,
1601    pub count: u8,
1602}
1603
1604#[derive(Clone, Debug)]
1605pub struct FrameMemoryInfo {
1606    pub infos: Vec<FrameAddressInfo>,
1607    pub total_frame_size: FrameMemorySize,
1608    pub variable_frame_size: FrameMemorySize,
1609    pub variable_registers: Vec<VariableRegister>,
1610    //    pub variable_register_range: VariableRegisterRange,
1611    pub frame_size_for_variables_except_temp: FrameMemorySize,
1612}
1613
1614#[derive(Clone)]
1615pub struct FrameRelativeInfo {
1616    pub frame_memory_region: FrameMemoryRegion,
1617    pub kind: FrameAddressInfo,
1618}
1619
1620#[derive(Clone, Debug)]
1621pub struct PathInfo {
1622    pub steps: Vec<PathStep>,
1623}
1624
1625impl PathInfo {
1626    #[must_use]
1627    pub fn convert_to_string(&self) -> String {
1628        let path = &self.steps;
1629
1630        let last = path.last().unwrap();
1631
1632        let names: Vec<_> = path.iter().map(|x| x.item.name.to_string()).collect();
1633
1634        let types: Vec<_> = path.iter().map(|x| format!("{}", x.item.ty.kind)).collect();
1635
1636        let names_path = names.join(".");
1637        let types_path = types.join("->");
1638
1639        format!(
1640            "{:04X}:{:X} {} ({})",
1641            (last.origin + last.item.offset).0.bright_cyan(),
1642            last.item.ty.total_size.0.yellow(),
1643            names_path.bright_blue(),
1644            types_path.yellow(),
1645        )
1646    }
1647}
1648
1649#[derive(Clone, Debug)]
1650pub struct PathStep {
1651    pub item: OffsetMemoryItem,
1652    pub origin: FrameMemoryAddress,
1653}
1654
1655impl PathStep {
1656    #[must_use]
1657    pub const fn absolute_address(&self) -> FrameMemoryAddress {
1658        FrameMemoryAddress(self.origin.0 + self.item.offset.0)
1659    }
1660}
1661
1662impl FrameMemoryInfo {
1663    #[must_use]
1664    pub const fn size(&self) -> FrameMemorySize {
1665        self.total_frame_size
1666    }
1667
1668    /// Returns a vector of `OffsetMemoryItem` from root to the one containing the address.
1669    #[must_use]
1670    pub fn find_path_to_address_items(&self, target: FrameMemoryAddress) -> Option<PathInfo> {
1671        for info in &self.infos {
1672            // Synthesize a root OffsetMemoryItem
1673            let root_item = OffsetMemoryItem {
1674                offset: MemoryOffset(0),
1675                size: info.frame_placed_type.ty.total_size,
1676                name: info.kind.to_string(),
1677                ty: info.frame_placed_type.ty.clone(),
1678            };
1679            let base_addr = info.frame_placed_type.addr;
1680            let mut path = Vec::new();
1681            if find_in_item(&root_item, base_addr, target, &mut path) {
1682                return Some(PathInfo { steps: path });
1683            }
1684        }
1685        None
1686    }
1687}
1688fn find_in_item(
1689    item: &OffsetMemoryItem,
1690    base_addr: FrameMemoryAddress,
1691    target: FrameMemoryAddress,
1692    path: &mut Vec<PathStep>,
1693) -> bool {
1694    let item_addr = FrameMemoryAddress(base_addr.0 + item.offset.0);
1695    path.push(PathStep {
1696        item: item.clone(),
1697        origin: base_addr,
1698    });
1699
1700    if item_addr.0 == target.0 {
1701        return true;
1702    }
1703
1704    match &item.ty.kind {
1705        BasicTypeKind::Struct(st) => {
1706            for field in &st.fields {
1707                if find_in_item(field, item_addr, target, path) {
1708                    return true;
1709                }
1710            }
1711        }
1712        BasicTypeKind::Tuple(tt) => {
1713            for field in &tt.fields {
1714                if find_in_item(field, item_addr, target, path) {
1715                    return true;
1716                }
1717            }
1718        }
1719        BasicTypeKind::TaggedUnion(tu) => {
1720            for variant in &tu.variants {
1721                // Synthesize an OffsetMemoryItem for the variant
1722                let variant_item = OffsetMemoryItem {
1723                    offset: MemoryOffset(0),
1724                    size: variant.ty.total_size,
1725                    name: variant.name.clone(),
1726                    ty: variant.ty.clone(),
1727                };
1728                if find_in_item(&variant_item, item_addr, target, path) {
1729                    return true;
1730                }
1731            }
1732        }
1733        BasicTypeKind::Optional(tu) => {
1734            for variant in &tu.variants {
1735                let variant_item = OffsetMemoryItem {
1736                    offset: MemoryOffset(0),
1737                    size: variant.ty.total_size,
1738                    name: variant.name.clone(),
1739                    ty: variant.ty.clone(),
1740                };
1741                if find_in_item(&variant_item, item_addr, target, path) {
1742                    return true;
1743                }
1744            }
1745        }
1746        BasicTypeKind::SliceView(inner) => {
1747            let slice_item = OffsetMemoryItem {
1748                offset: MemoryOffset(0),
1749                size: inner.total_size,
1750                name: "slice".to_string(),
1751                ty: inner.clone(),
1752            };
1753            if find_in_item(&slice_item, item_addr, target, path) {
1754                return true;
1755            }
1756        }
1757        BasicTypeKind::DynamicLengthMapView(a, b) => {
1758            if find_in_item(a, item_addr, target, path) {
1759                return true;
1760            }
1761            if find_in_item(b, item_addr, target, path) {
1762                return true;
1763            }
1764        }
1765        _ => {}
1766    }
1767
1768    path.pop();
1769    false
1770}
1771
1772#[derive(Clone, Debug)]
1773pub enum FunctionInfoKind {
1774    Constant(usize),
1775    Normal(usize),
1776}
1777
1778#[derive(Clone, Debug)]
1779pub struct FunctionInfo {
1780    pub kind: FunctionInfoKind,
1781    pub frame_memory: FrameMemoryInfo,
1782    pub return_type: VmType,
1783    pub name: String,
1784    pub ip_range: InstructionRange,
1785}
1786
1787#[derive(Clone, Debug)]
1788pub struct CompleteFunctionInfo {
1789    pub ip: InstructionPosition,
1790    pub size: InstructionPositionOffset,
1791    pub info: FunctionInfo,
1792}
1793
1794pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1795    let tab_str = "  ".repeat(tabs);
1796    writeln!(f)?;
1797    write!(f, "{tab_str}")
1798}
1799
1800pub fn show_memory_offset(
1801    offset: MemoryOffset,
1802    origin: FrameMemoryAddress,
1803    f: &mut dyn Write,
1804    _tabs: usize,
1805) -> std::fmt::Result {
1806    let result = origin + offset;
1807    write!(f, "{}+{:04X}", result, offset.0.yellow())
1808}
1809fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1810    write!(f, "{} ({})", size.green(), size.0)
1811}
1812
1813pub fn show_offset_item(
1814    offset_item: &OffsetMemoryItem,
1815    origin: FrameMemoryAddress,
1816    f: &mut dyn Write,
1817    tabs: usize,
1818) -> std::fmt::Result {
1819    show_memory_offset(offset_item.offset, origin, f, tabs)?;
1820    write!(f, ":")?;
1821    show_memory_size(offset_item.size, f, tabs)?;
1822    write!(f, " ")?;
1823    write_identifier_and_colon(&offset_item.name, f)?;
1824    let adjusted_origin = origin + offset_item.offset;
1825    write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1826}
1827
1828pub fn show_tagged_union(
1829    tagged_union: &TaggedUnion,
1830    origin: FrameMemoryAddress,
1831    f: &mut dyn Write,
1832    tabs: usize,
1833) -> std::fmt::Result {
1834    write!(f, "union tag_size:")?;
1835    show_memory_size(tagged_union.tag_size, f, tabs)?;
1836    write!(f, " max payload:")?;
1837    show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1838
1839    let adjusted_payload_origin = origin + tagged_union.payload_offset;
1840
1841    for (index, union_data) in tagged_union
1842        .variants
1843        .clone()
1844        .into_iter()
1845        .take(4)
1846        .enumerate()
1847    {
1848        //iter().enumerate() {
1849        new_line_and_tab(f, tabs + 1)?;
1850        write!(f, "{}> ", index.bright_magenta())?;
1851        write_identifier_and_colon(&union_data.name, f)?;
1852        write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1853    }
1854    Ok(())
1855}
1856
1857pub fn show_struct_type(
1858    s: &StructType,
1859    origin: FrameMemoryAddress,
1860    f: &mut dyn Write,
1861    tabs: usize,
1862) -> std::fmt::Result {
1863    write!(f, "{} {{", s.name)?;
1864    for offset_item in &s.fields {
1865        new_line_and_tab(f, tabs + 1)?;
1866        show_offset_item(offset_item, origin, f, tabs + 1)?;
1867    }
1868    write!(f, " }}")
1869}
1870
1871pub fn show_tuple_type(
1872    s: &TupleType,
1873    origin: FrameMemoryAddress,
1874    f: &mut dyn Write,
1875    tabs: usize,
1876) -> std::fmt::Result {
1877    write!(f, "(")?;
1878    for offset_item in &s.fields {
1879        new_line_and_tab(f, tabs + 1)?;
1880        show_offset_item(offset_item, origin, f, tabs + 1)?;
1881    }
1882    write!(f, " )")
1883}
1884
1885pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1886    write!(f, "{}: ", identifier.blue())
1887}
1888
1889pub fn write_basic_type(
1890    ty: &BasicType,
1891    origin: FrameMemoryAddress,
1892    f: &mut dyn Write,
1893    tabs: usize,
1894) -> std::fmt::Result {
1895    match &ty.kind {
1896        BasicTypeKind::Empty => write!(f, "()"),
1897        BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1898        BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1899        BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1900        BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1901        BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1902        BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1903        BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1904        BasicTypeKind::TaggedUnion(tagged_union) => {
1905            show_tagged_union(tagged_union, origin, f, tabs)
1906        }
1907        BasicTypeKind::Optional(tagged_union) => {
1908            write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1909            show_tagged_union(tagged_union, origin, f, tabs)
1910        }
1911        BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1912
1913        BasicTypeKind::SliceView(slice_inner_type) => {
1914            write!(f, "[|")?;
1915            write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1916            write!(f, "|]")
1917        }
1918        BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1919            write!(f, "[|")?;
1920            show_offset_item(key_type, origin, f, tabs + 1)?;
1921            write!(f, ", ")?;
1922            show_offset_item(value_type, origin, f, tabs + 1)?;
1923            write!(f, "|]")
1924        }
1925        BasicTypeKind::StringView { .. } => {
1926            write!(f, "str")
1927        }
1928        BasicTypeKind::InternalRangeHeader => {
1929            write!(f, "range")
1930        }
1931
1932        BasicTypeKind::FixedCapacityArray(element_type, size) => {
1933            write!(f, "[{element_type}, {size}]")
1934        }
1935        BasicTypeKind::DynamicLengthVecView(element_type) => {
1936            write!(f, "Vec<{element_type}>")
1937        }
1938        BasicTypeKind::VecStorage(element_type, size) => {
1939            write!(f, "VecStorage<{element_type}, {size}>")
1940        }
1941        BasicTypeKind::StringStorage {
1942            element_type: byte,
1943            capacity,
1944            ..
1945        } => {
1946            write!(f, "StringStorage<{byte}, {capacity}>")
1947        }
1948        BasicTypeKind::QueueStorage(element_type, size) => {
1949            write!(f, "QueueStorage<{element_type}, {size}>")
1950        }
1951        BasicTypeKind::GridStorage(element_type, width, height) => {
1952            write!(f, "GridStorage<{element_type}, ({width},{height})>")
1953        }
1954        BasicTypeKind::StackStorage(element_type, size) => {
1955            write!(f, "StackStorage<{element_type}, {size}>")
1956        }
1957        BasicTypeKind::SparseView(element_type) => {
1958            write!(f, "Sparse<{element_type}>")
1959        }
1960        BasicTypeKind::GridView(element_type) => {
1961            write!(f, "grid<{element_type}>")
1962        }
1963        BasicTypeKind::SparseStorage(element_type, size) => {
1964            write!(f, "SparseStorage<{element_type}, {size}>")
1965        }
1966        BasicTypeKind::MapStorage {
1967            logical_limit: logical_size,
1968            key_type,
1969            value_type,
1970            ..
1971        } => {
1972            write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>", )
1973        }
1974        BasicTypeKind::InternalVecIterator => {
1975            write!(f, "vec_iter")
1976        }
1977        BasicTypeKind::InternalStringIterator => {
1978            write!(f, "str_iter")
1979        }
1980        BasicTypeKind::InternalRangeIterator => {
1981            write!(f, "range_iter")
1982        }
1983        BasicTypeKind::InternalMapIterator => {
1984            write!(f, "map_iter")
1985        }
1986        BasicTypeKind::InternalSparseIterator => {
1987            write!(f, "sparse_iter")
1988        }
1989    }
1990}
1991
1992pub fn show_frame_addr(
1993    addr: FrameMemoryAddress,
1994    f: &mut dyn Write,
1995    _tabs: usize,
1996) -> std::fmt::Result {
1997    write!(f, "{:04X}", addr.0.blue())
1998}
1999
2000pub fn show_frame_region(
2001    region: FrameMemoryRegion,
2002    f: &mut dyn Write,
2003    tabs: usize,
2004) -> std::fmt::Result {
2005    show_frame_addr(region.addr, f, tabs)?;
2006    write!(f, ":")?;
2007    show_memory_size(region.size, f, tabs)
2008}
2009
2010pub fn show_frame_memory(
2011    frame_relative_infos: &FrameMemoryInfo,
2012    f: &mut dyn Write,
2013) -> std::fmt::Result {
2014    for mem in &frame_relative_infos.infos {
2015        let addr = mem.frame_placed_type.addr;
2016        show_frame_region(mem.frame_placed_type.region(), f, 0)?;
2017        write!(f, " ")?;
2018        match &mem.kind {
2019            VariableInfoKind::Variable(v) => {
2020                write!(f, "var ")?;
2021                write_identifier_and_colon(&v.name, f)?;
2022            }
2023            VariableInfoKind::Parameter(v) => {
2024                write!(f, "param ")?;
2025                write_identifier_and_colon(&v.name, f)?;
2026            }
2027            VariableInfoKind::Return => {
2028                write!(f, "return:")?;
2029            }
2030        }
2031        write!(f, " ")?;
2032        write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2033        writeln!(f)?;
2034    }
2035
2036    writeln!(
2037        f,
2038        "frame size for variables: {:0}",
2039        frame_relative_infos.frame_size_for_variables_except_temp
2040    )?;
2041    Ok(())
2042}