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