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