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