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::StackStorage(..)
1295            | BasicTypeKind::DynamicLengthVecView(..)
1296            // Map
1297            | BasicTypeKind::MapStorage {  ..}
1298            | BasicTypeKind::DynamicLengthMapView(..)
1299        )
1300    }
1301    #[must_use]
1302    pub const fn is_collection_with_capacity(&self) -> bool {
1303        matches!(
1304            self.kind,
1305            BasicTypeKind::FixedCapacityArray(..)
1306            // Vec
1307            | BasicTypeKind::VecStorage(..)
1308            | BasicTypeKind::StringStorage(..)
1309            // Map
1310            | BasicTypeKind::MapStorage { ..}
1311        )
1312    }
1313}
1314
1315impl BasicType {
1316    pub(crate) const fn manifestation(&self) -> Manifestation {
1317        self.kind.manifestation()
1318    }
1319}
1320
1321impl BasicType {
1322    #[must_use]
1323    pub const fn should_be_copied_back_when_mutable_arg_or_return(&self) -> bool {
1324        !self.is_aggregate()
1325    }
1326}
1327
1328impl BasicType {
1329    #[must_use]
1330    pub fn referenced_type(&self) -> &Self {
1331        // MutablePointer removed - mutability handled at analyzer level
1332        panic!("referenced_type() is no longer supported - MutablePointer was removed")
1333    }
1334}
1335
1336impl BasicType {
1337    #[must_use]
1338    pub const fn make_pointer(&self) -> Self {
1339        // MutablePointer removed - return a generic pointer type
1340        Self {
1341            id: BasicTypeId::EMPTY,
1342            kind: BasicTypeKind::U8,
1343            total_size: HEAP_PTR_ON_FRAME_SIZE,
1344            max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1345        }
1346    }
1347}
1348
1349impl BasicType {}
1350
1351impl BasicType {
1352    #[must_use]
1353    pub fn get_variant(&self, variant_index: usize) -> &TaggedUnionVariant {
1354        match &self.kind {
1355            BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => {
1356                tagged.get_variant_by_index(variant_index)
1357            }
1358            _ => panic!("type is not a tagged union"),
1359        }
1360    }
1361}
1362
1363impl BasicType {
1364    #[must_use]
1365    pub const fn is_scalar(&self) -> bool {
1366        self.kind.is_scalar()
1367    }
1368
1369    #[must_use]
1370    pub const fn is_mutable_reference(&self) -> bool {
1371        self.kind.is_mutable_reference()
1372    }
1373}
1374
1375impl BasicType {
1376    #[must_use]
1377    pub const fn unwrap_info(
1378        &self,
1379    ) -> Option<(MemoryOffset, MemorySize, MemoryOffset, MemorySize)> {
1380        match &self.kind {
1381            BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => Some((
1382                tagged.tag_offset,
1383                tagged.tag_size,
1384                tagged.payload_offset,
1385                tagged.payload_max_size,
1386            )),
1387            _ => None,
1388        }
1389    }
1390
1391    #[must_use]
1392    pub fn union_info(&self) -> &TaggedUnion {
1393        self.kind.union_info()
1394    }
1395
1396    #[must_use]
1397    pub fn create_mutable_pointer(&self) -> Self {
1398        // MutablePointer removed - return a generic pointer type
1399        debug_assert!(!self.is_mutable_reference());
1400
1401        Self {
1402            id: BasicTypeId::EMPTY,
1403            kind: BasicTypeKind::U8,
1404            total_size: HEAP_PTR_ON_FRAME_SIZE,
1405            max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1406        }
1407    }
1408
1409    #[must_use]
1410    pub const fn is_aggregate(&self) -> bool {
1411        self.kind.is_aggregate()
1412    }
1413
1414    #[must_use]
1415    pub const fn optional_info(&self) -> Option<&TaggedUnion> {
1416        match &self.kind {
1417            BasicTypeKind::Optional(tagged_union) => Some(tagged_union),
1418            _ => None,
1419        }
1420    }
1421
1422    #[must_use]
1423    pub fn get_field_offset(&self, index: usize) -> Option<&OffsetMemoryItem> {
1424        match &self.kind {
1425            BasicTypeKind::Struct(struct_type) => struct_type.fields.get(index),
1426            BasicTypeKind::Tuple(tuple_type) => tuple_type.fields.get(index),
1427            _ => {
1428                error!(?self, "not a type with fields");
1429                None
1430            }
1431        }
1432    }
1433
1434    #[must_use]
1435    pub fn bucket_size_for_vec_like(&self) -> Option<MemorySize> {
1436        match &self.kind {
1437            BasicTypeKind::FixedCapacityArray(inner, capacity) => Some(inner.total_size),
1438            BasicTypeKind::SliceView(inner) => Some(inner.total_size),
1439            BasicTypeKind::VecStorage(inner, _) => Some(inner.total_size),
1440            BasicTypeKind::StringStorage(inner, _) => Some(inner.total_size),
1441            BasicTypeKind::DynamicLengthVecView(inner) => Some(inner.total_size),
1442            BasicTypeKind::StringView => Some(MemorySize(1)), // String elements are bytes (u8)
1443            _ => None,
1444        }
1445    }
1446
1447    #[must_use]
1448    pub fn element(&self) -> Option<BasicTypeRef> {
1449        match &self.kind {
1450            BasicTypeKind::StackStorage(inner, _)
1451            | BasicTypeKind::GridView(inner)
1452            | BasicTypeKind::GridStorage(inner, ..)
1453            | BasicTypeKind::SparseStorage(inner, _)
1454            | BasicTypeKind::SparseView(inner)
1455            | BasicTypeKind::QueueStorage(inner, _)
1456            | BasicTypeKind::DynamicLengthVecView(inner)
1457            | BasicTypeKind::FixedCapacityArray(inner, _)
1458            | BasicTypeKind::VecStorage(inner, _)
1459            | BasicTypeKind::StringStorage(inner, _)
1460            | BasicTypeKind::SliceView(inner) => Some(inner.clone()),
1461            BasicTypeKind::StringView => Some(Rc::new(self.clone())),
1462            _ => None,
1463        }
1464    }
1465
1466    #[must_use]
1467    pub const fn header_size_for_vec_like(&self) -> Option<MemorySize> {
1468        match &self.kind {
1469            BasicTypeKind::SliceView(_)
1470            | BasicTypeKind::DynamicLengthVecView(_)
1471            | BasicTypeKind::VecStorage(_, _)
1472            | BasicTypeKind::StringStorage(_, _)
1473            | BasicTypeKind::StringView => Some(VEC_HEADER_SIZE),
1474            BasicTypeKind::DynamicLengthMapView(..) => Some(MAP_HEADER_SIZE),
1475            _ => None,
1476        }
1477    }
1478
1479    #[must_use]
1480    pub fn element_pair(&self) -> Option<(&OffsetMemoryItem, &OffsetMemoryItem)> {
1481        match &self.kind {
1482            BasicTypeKind::DynamicLengthMapView(a, b) => Some((a, b)),
1483            _ => None,
1484        }
1485    }
1486
1487    #[must_use]
1488    pub fn is_int(&self) -> bool {
1489        matches!(self.kind, BasicTypeKind::S32)
1490            && self.total_size.0 == 4
1491            && self.max_alignment == MemoryAlignment::U32
1492    }
1493    #[must_use]
1494    pub fn is_float(&self) -> bool {
1495        matches!(self.kind, BasicTypeKind::Fixed32)
1496            && self.total_size.0 == 4
1497            && self.max_alignment == MemoryAlignment::U32
1498    }
1499
1500    #[must_use]
1501    pub fn is_str(&self) -> bool {
1502        matches!(self.kind, BasicTypeKind::StringView)
1503            && self.total_size == STRING_PTR_SIZE
1504            && self.max_alignment == STRING_PTR_ALIGNMENT
1505    }
1506
1507    #[must_use]
1508    pub fn is_bool(&self) -> bool {
1509        matches!(self.kind, BasicTypeKind::B8)
1510            && self.total_size.0 == 1
1511            && self.max_alignment == MemoryAlignment::U8
1512    }
1513    #[must_use]
1514    pub fn is_byte(&self) -> bool {
1515        matches!(self.kind, BasicTypeKind::U8)
1516            && self.total_size.0 == 1
1517            && self.max_alignment == MemoryAlignment::U8
1518    }
1519}
1520
1521impl Display for BasicType {
1522    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1523        write!(f, "{}", self.kind)
1524    }
1525}
1526
1527#[derive(Clone, Debug)]
1528pub struct VariableInfo {
1529    pub is_mutable: bool,
1530    pub name: String,
1531}
1532
1533impl Display for VariableInfo {
1534    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1535        let mut_prefix = if self.is_mutable { "mut " } else { "" };
1536
1537        let name = &self.name;
1538        write!(f, "{mut_prefix}{name}")
1539    }
1540}
1541
1542#[derive(Clone, Debug)]
1543pub enum VariableInfoKind {
1544    Variable(VariableInfo),
1545    Parameter(VariableInfo),
1546    Return,
1547}
1548
1549impl Display for VariableInfoKind {
1550    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1551        match self {
1552            Self::Variable(var_info) => {
1553                write!(f, "{} {var_info}", "var:".white())
1554            }
1555            Self::Parameter(var_info) => {
1556                write!(f, "{} {var_info}", "param:".white())
1557            }
1558            Self::Return => {
1559                write!(f, "{}", "return".white())
1560            }
1561        }
1562    }
1563}
1564
1565#[derive(Clone, Debug)]
1566pub struct FrameAddressInfo {
1567    pub kind: VariableInfoKind,
1568    pub frame_placed_type: FramePlacedType,
1569}
1570
1571#[derive(Clone, Debug)]
1572pub struct VariableRegister {
1573    pub unique_id_in_function: usize,
1574    pub variable: VariableInfo,
1575    pub register: TypedRegister,
1576}
1577
1578impl Display for VariableRegister {
1579    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1580        write!(f, "{}: {}", self.register, self.variable)
1581    }
1582}
1583
1584#[derive(Clone, Debug)]
1585pub struct VariableRegisterRange {
1586    pub start: u8,
1587    pub count: u8,
1588}
1589
1590#[derive(Clone, Debug)]
1591pub struct FrameMemoryInfo {
1592    pub infos: Vec<FrameAddressInfo>,
1593    pub total_frame_size: FrameMemorySize,
1594    pub variable_frame_size: FrameMemorySize,
1595    pub variable_registers: Vec<VariableRegister>,
1596    //    pub variable_register_range: VariableRegisterRange,
1597    pub frame_size_for_variables_except_temp: FrameMemorySize,
1598}
1599
1600#[derive(Clone)]
1601pub struct FrameRelativeInfo {
1602    pub frame_memory_region: FrameMemoryRegion,
1603    pub kind: FrameAddressInfo,
1604}
1605
1606#[derive(Clone, Debug)]
1607pub struct PathInfo {
1608    pub steps: Vec<PathStep>,
1609}
1610
1611impl PathInfo {
1612    #[must_use]
1613    pub fn convert_to_string(&self) -> String {
1614        let path = &self.steps;
1615
1616        let last = path.last().unwrap();
1617
1618        let names: Vec<_> = path.iter().map(|x| x.item.name.to_string()).collect();
1619
1620        let types: Vec<_> = path.iter().map(|x| format!("{}", x.item.ty.kind)).collect();
1621
1622        let names_path = names.join(".");
1623        let types_path = types.join("->");
1624
1625        format!(
1626            "{:04X}:{:X} {} ({})",
1627            (last.origin + last.item.offset).0.bright_cyan(),
1628            last.item.ty.total_size.0.yellow(),
1629            names_path.bright_blue(),
1630            types_path.yellow(),
1631        )
1632    }
1633}
1634
1635#[derive(Clone, Debug)]
1636pub struct PathStep {
1637    pub item: OffsetMemoryItem,
1638    pub origin: FrameMemoryAddress,
1639}
1640
1641impl PathStep {
1642    #[must_use]
1643    pub const fn absolute_address(&self) -> FrameMemoryAddress {
1644        FrameMemoryAddress(self.origin.0 + self.item.offset.0)
1645    }
1646}
1647
1648impl FrameMemoryInfo {
1649    #[must_use]
1650    pub const fn size(&self) -> FrameMemorySize {
1651        self.total_frame_size
1652    }
1653
1654    /// Returns a vector of `OffsetMemoryItem` from root to the one containing the address.
1655    #[must_use]
1656    pub fn find_path_to_address_items(&self, target: FrameMemoryAddress) -> Option<PathInfo> {
1657        for info in &self.infos {
1658            // Synthesize a root OffsetMemoryItem
1659            let root_item = OffsetMemoryItem {
1660                offset: MemoryOffset(0),
1661                size: info.frame_placed_type.ty.total_size,
1662                name: info.kind.to_string(),
1663                ty: info.frame_placed_type.ty.clone(),
1664            };
1665            let base_addr = info.frame_placed_type.addr;
1666            let mut path = Vec::new();
1667            if find_in_item(&root_item, base_addr, target, &mut path) {
1668                return Some(PathInfo { steps: path });
1669            }
1670        }
1671        None
1672    }
1673}
1674fn find_in_item(
1675    item: &OffsetMemoryItem,
1676    base_addr: FrameMemoryAddress,
1677    target: FrameMemoryAddress,
1678    path: &mut Vec<PathStep>,
1679) -> bool {
1680    let item_addr = FrameMemoryAddress(base_addr.0 + item.offset.0);
1681    path.push(PathStep {
1682        item: item.clone(),
1683        origin: base_addr,
1684    });
1685
1686    if item_addr.0 == target.0 {
1687        return true;
1688    }
1689
1690    match &item.ty.kind {
1691        BasicTypeKind::Struct(st) => {
1692            for field in &st.fields {
1693                if find_in_item(field, item_addr, target, path) {
1694                    return true;
1695                }
1696            }
1697        }
1698        BasicTypeKind::Tuple(tt) => {
1699            for field in &tt.fields {
1700                if find_in_item(field, item_addr, target, path) {
1701                    return true;
1702                }
1703            }
1704        }
1705        BasicTypeKind::TaggedUnion(tu) => {
1706            for variant in &tu.variants {
1707                // Synthesize an OffsetMemoryItem for the variant
1708                let variant_item = OffsetMemoryItem {
1709                    offset: MemoryOffset(0),
1710                    size: variant.ty.total_size,
1711                    name: variant.name.clone(),
1712                    ty: variant.ty.clone(),
1713                };
1714                if find_in_item(&variant_item, item_addr, target, path) {
1715                    return true;
1716                }
1717            }
1718        }
1719        BasicTypeKind::Optional(tu) => {
1720            for variant in &tu.variants {
1721                let variant_item = OffsetMemoryItem {
1722                    offset: MemoryOffset(0),
1723                    size: variant.ty.total_size,
1724                    name: variant.name.clone(),
1725                    ty: variant.ty.clone(),
1726                };
1727                if find_in_item(&variant_item, item_addr, target, path) {
1728                    return true;
1729                }
1730            }
1731        }
1732        BasicTypeKind::SliceView(inner) => {
1733            let slice_item = OffsetMemoryItem {
1734                offset: MemoryOffset(0),
1735                size: inner.total_size,
1736                name: "slice".to_string(),
1737                ty: inner.clone(),
1738            };
1739            if find_in_item(&slice_item, item_addr, target, path) {
1740                return true;
1741            }
1742        }
1743        BasicTypeKind::DynamicLengthMapView(a, b) => {
1744            if find_in_item(a, item_addr, target, path) {
1745                return true;
1746            }
1747            if find_in_item(b, item_addr, target, path) {
1748                return true;
1749            }
1750        }
1751        _ => {}
1752    }
1753
1754    path.pop();
1755    false
1756}
1757
1758#[derive(Clone, Debug)]
1759pub enum FunctionInfoKind {
1760    Constant(usize),
1761    Normal(usize),
1762}
1763
1764#[derive(Clone, Debug)]
1765pub struct FunctionInfo {
1766    pub kind: FunctionInfoKind,
1767    pub frame_memory: FrameMemoryInfo,
1768    pub return_type: VmType,
1769    pub name: String,
1770    pub ip_range: InstructionRange,
1771}
1772
1773#[derive(Clone, Debug)]
1774pub struct CompleteFunctionInfo {
1775    pub ip: InstructionPosition,
1776    pub size: InstructionPositionOffset,
1777    pub info: FunctionInfo,
1778}
1779
1780pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1781    let tab_str = "  ".repeat(tabs);
1782    writeln!(f)?;
1783    write!(f, "{tab_str}")
1784}
1785
1786pub fn show_memory_offset(
1787    offset: MemoryOffset,
1788    origin: FrameMemoryAddress,
1789    f: &mut dyn Write,
1790    _tabs: usize,
1791) -> std::fmt::Result {
1792    let result = origin + offset;
1793    write!(f, "{}+{:04X}", result, offset.0.yellow())
1794}
1795fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1796    write!(f, "{} ({})", size.green(), size.0)
1797}
1798
1799pub fn show_offset_item(
1800    offset_item: &OffsetMemoryItem,
1801    origin: FrameMemoryAddress,
1802    f: &mut dyn Write,
1803    tabs: usize,
1804) -> std::fmt::Result {
1805    show_memory_offset(offset_item.offset, origin, f, tabs)?;
1806    write!(f, ":")?;
1807    show_memory_size(offset_item.size, f, tabs)?;
1808    write!(f, " ")?;
1809    write_identifier_and_colon(&offset_item.name, f)?;
1810    let adjusted_origin = origin + offset_item.offset;
1811    write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1812}
1813
1814pub fn show_tagged_union(
1815    tagged_union: &TaggedUnion,
1816    origin: FrameMemoryAddress,
1817    f: &mut dyn Write,
1818    tabs: usize,
1819) -> std::fmt::Result {
1820    write!(f, "union tag_size:")?;
1821    show_memory_size(tagged_union.tag_size, f, tabs)?;
1822    write!(f, " max payload:")?;
1823    show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1824
1825    let adjusted_payload_origin = origin + tagged_union.payload_offset;
1826
1827    for (index, union_data) in tagged_union
1828        .variants
1829        .clone()
1830        .into_iter()
1831        .take(4)
1832        .enumerate()
1833    {
1834        //iter().enumerate() {
1835        new_line_and_tab(f, tabs + 1)?;
1836        write!(f, "{}> ", index.bright_magenta())?;
1837        write_identifier_and_colon(&union_data.name, f)?;
1838        write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1839    }
1840    Ok(())
1841}
1842
1843pub fn show_struct_type(
1844    s: &StructType,
1845    origin: FrameMemoryAddress,
1846    f: &mut dyn Write,
1847    tabs: usize,
1848) -> std::fmt::Result {
1849    write!(f, "{} {{", s.name)?;
1850    for offset_item in &s.fields {
1851        new_line_and_tab(f, tabs + 1)?;
1852        show_offset_item(offset_item, origin, f, tabs + 1)?;
1853    }
1854    write!(f, " }}")
1855}
1856
1857pub fn show_tuple_type(
1858    s: &TupleType,
1859    origin: FrameMemoryAddress,
1860    f: &mut dyn Write,
1861    tabs: usize,
1862) -> std::fmt::Result {
1863    write!(f, "(")?;
1864    for offset_item in &s.fields {
1865        new_line_and_tab(f, tabs + 1)?;
1866        show_offset_item(offset_item, origin, f, tabs + 1)?;
1867    }
1868    write!(f, " )")
1869}
1870
1871pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1872    write!(f, "{}: ", identifier.blue())
1873}
1874
1875pub fn write_basic_type(
1876    ty: &BasicType,
1877    origin: FrameMemoryAddress,
1878    f: &mut dyn Write,
1879    tabs: usize,
1880) -> std::fmt::Result {
1881    match &ty.kind {
1882        BasicTypeKind::Empty => write!(f, "()"),
1883        BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1884        BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1885        BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1886        BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1887        BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1888        BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1889        BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1890        BasicTypeKind::TaggedUnion(tagged_union) => {
1891            show_tagged_union(tagged_union, origin, f, tabs)
1892        }
1893        BasicTypeKind::Optional(tagged_union) => {
1894            write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1895            show_tagged_union(tagged_union, origin, f, tabs)
1896        }
1897        BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1898
1899        BasicTypeKind::SliceView(slice_inner_type) => {
1900            write!(f, "[|")?;
1901            write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1902            write!(f, "|]")
1903        }
1904        BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1905            write!(f, "[|")?;
1906            show_offset_item(key_type, origin, f, tabs + 1)?;
1907            write!(f, ", ")?;
1908            show_offset_item(value_type, origin, f, tabs + 1)?;
1909            write!(f, "|]")
1910        }
1911        BasicTypeKind::StringView => {
1912            write!(f, "str")
1913        }
1914        BasicTypeKind::InternalRangeHeader => {
1915            write!(f, "range")
1916        }
1917
1918        BasicTypeKind::FixedCapacityArray(element_type, size) => {
1919            write!(f, "[{element_type}, {size}]")
1920        }
1921        BasicTypeKind::DynamicLengthVecView(element_type) => {
1922            write!(f, "Vec<{element_type}>")
1923        }
1924        BasicTypeKind::VecStorage(element_type, size) => {
1925            write!(f, "VecStorage<{element_type}, {size}>")
1926        }
1927        BasicTypeKind::StringStorage(element_type, size) => {
1928            write!(f, "StringStorage<{element_type}, {size}>")
1929        }
1930        BasicTypeKind::QueueStorage(element_type, size) => {
1931            write!(f, "QueueStorage<{element_type}, {size}>")
1932        }
1933        BasicTypeKind::GridStorage(element_type, width, height) => {
1934            write!(f, "GridStorage<{element_type}, ({width},{height})>")
1935        }
1936        BasicTypeKind::StackStorage(element_type, size) => {
1937            write!(f, "StackStorage<{element_type}, {size}>")
1938        }
1939        BasicTypeKind::SparseView(element_type) => {
1940            write!(f, "Sparse<{element_type}>")
1941        }
1942        BasicTypeKind::GridView(element_type) => {
1943            write!(f, "grid<{element_type}>")
1944        }
1945        BasicTypeKind::SparseStorage(element_type, size) => {
1946            write!(f, "SparseStorage<{element_type}, {size}>")
1947        }
1948        BasicTypeKind::DynamicLengthMapView(key, value) => {
1949            write!(f, "Map<{key}, {value}>")
1950        }
1951        BasicTypeKind::MapStorage {
1952            logical_limit: logical_size,
1953            key_type,
1954            value_type,
1955            ..
1956        } => {
1957            write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>",)
1958        }
1959        BasicTypeKind::InternalVecIterator => {
1960            write!(f, "vec_iter")
1961        }
1962        BasicTypeKind::InternalStringIterator => {
1963            write!(f, "str_iter")
1964        }
1965        BasicTypeKind::InternalRangeIterator => {
1966            write!(f, "range_iter")
1967        }
1968        BasicTypeKind::InternalMapIterator => {
1969            write!(f, "map_iter")
1970        }
1971        BasicTypeKind::InternalSparseIterator => {
1972            write!(f, "sparse_iter")
1973        }
1974    }
1975}
1976
1977pub fn show_frame_addr(
1978    addr: FrameMemoryAddress,
1979    f: &mut dyn Write,
1980    _tabs: usize,
1981) -> std::fmt::Result {
1982    write!(f, "{:04X}", addr.0.blue())
1983}
1984
1985pub fn show_frame_region(
1986    region: FrameMemoryRegion,
1987    f: &mut dyn Write,
1988    tabs: usize,
1989) -> std::fmt::Result {
1990    show_frame_addr(region.addr, f, tabs)?;
1991    write!(f, ":")?;
1992    show_memory_size(region.size, f, tabs)
1993}
1994
1995pub fn show_frame_memory(
1996    frame_relative_infos: &FrameMemoryInfo,
1997    f: &mut dyn Write,
1998) -> std::fmt::Result {
1999    for mem in &frame_relative_infos.infos {
2000        let addr = mem.frame_placed_type.addr;
2001        show_frame_region(mem.frame_placed_type.region(), f, 0)?;
2002        write!(f, " ")?;
2003        match &mem.kind {
2004            VariableInfoKind::Variable(v) => {
2005                write!(f, "var ")?;
2006                write_identifier_and_colon(&v.name, f)?;
2007            }
2008            VariableInfoKind::Parameter(v) => {
2009                write!(f, "param ")?;
2010                write_identifier_and_colon(&v.name, f)?;
2011            }
2012            VariableInfoKind::Return => {
2013                write!(f, "return:")?;
2014            }
2015        }
2016        write!(f, " ")?;
2017        write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2018        writeln!(f)?;
2019    }
2020
2021    writeln!(
2022        f,
2023        "frame size for variables: {:0}",
2024        frame_relative_infos.frame_size_for_variables_except_temp
2025    )?;
2026    Ok(())
2027}