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