swamp_script_code_gen/
alloc_util.rs

1use crate::alloc::{FrameMemoryRegion, ScopeAllocator};
2use seq_map::SeqMap;
3use swamp_script_types::{AnonymousStructType, EnumVariantType, Type};
4use swamp_vm_instr_build::{FLOAT_SIZE, INT_SIZE, STR_SIZE};
5use swamp_vm_types::{MemoryAlignment, MemoryOffset, MemorySize};
6use tracing::error;
7
8pub fn layout_struct(anon_struct: &AnonymousStructType) -> (MemorySize, MemoryAlignment) {
9    let mut calculated_offset = MemoryOffset(0);
10    let mut largest_alignment = MemoryAlignment::U8;
11    for (_name, field) in &anon_struct.field_name_sorted_fields {
12        let (field_size, field_alignment) = type_size_and_alignment(&field.field_type);
13        if field_alignment.greater_than(largest_alignment) {
14            largest_alignment = field_alignment;
15        }
16        calculated_offset.space(field_size, field_alignment);
17    }
18
19    let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
20
21    (total_offset.as_size(), largest_alignment)
22}
23
24pub fn layout_tuple(types: &Vec<Type>) -> (MemorySize, MemoryAlignment) {
25    let mut calculated_offset = MemoryOffset(0);
26    let mut largest_alignment = MemoryAlignment::U8;
27    for ty in types {
28        let (field_size, field_alignment) = type_size_and_alignment(&ty);
29        if field_alignment.greater_than(largest_alignment) {
30            largest_alignment = field_alignment;
31        }
32        calculated_offset.space(field_size, field_alignment);
33    }
34    let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
35    (total_offset.as_size(), largest_alignment)
36}
37
38pub fn layout_union(variants: &SeqMap<String, EnumVariantType>) -> (MemorySize, MemoryAlignment) {
39    let mut max_variant_alignment = MemoryAlignment::U8;
40    let mut max_variant_size = MemorySize(0);
41    let mut calculated_offset = MemoryOffset(0);
42    for (_name, variant) in variants {
43        let (variant_size, variant_alignment) = match variant {
44            EnumVariantType::Struct(anon_struct) => layout_struct(&anon_struct.anon_struct),
45            EnumVariantType::Tuple(types) => layout_tuple(&types.fields_in_order),
46            EnumVariantType::Nothing(_) => (MemorySize(0), MemoryAlignment::U8),
47        };
48
49        if variant_alignment.greater_than(max_variant_alignment) {
50            max_variant_alignment = variant_alignment;
51        }
52
53        if variant_size.0 > max_variant_size.0 {
54            max_variant_size = variant_size;
55        }
56    }
57
58    (max_variant_size, max_variant_alignment)
59}
60
61pub fn type_size_and_alignment(ty: &Type) -> (MemorySize, MemoryAlignment) {
62    match ty {
63        Type::Int => (MemorySize(INT_SIZE), MemoryAlignment::U32),
64        Type::Float => (MemorySize(FLOAT_SIZE), MemoryAlignment::U32),
65        Type::String => (MemorySize(STR_SIZE), MemoryAlignment::U16),
66        Type::Bool => (MemorySize(1), MemoryAlignment::U8),
67        Type::Unit => (MemorySize(0), MemoryAlignment::U8),
68        Type::Never => (MemorySize(0), MemoryAlignment::U8),
69        Type::Tuple(types) => layout_tuple(types),
70        Type::NamedStruct(named_struct) => type_size_and_alignment(&Type::AnonymousStruct(
71            named_struct.anon_struct_type.clone(),
72        )),
73        Type::Slice(value_type) => type_size_and_alignment(value_type),
74        Type::SlicePair(key_type, value_type) => {
75            layout_tuple(&vec![*key_type.clone(), *value_type.clone()])
76        }
77        Type::AnonymousStruct(anon_struct) => layout_struct(anon_struct),
78        Type::Enum(enum_type) => {
79            let (offset, alignment) = layout_union(&enum_type.variants);
80
81            let alignment_octets: usize = alignment.into();
82
83            (MemorySize(offset.0 + alignment_octets as u16), alignment)
84        }
85        Type::Function(_) => (MemorySize(2), MemoryAlignment::U16),
86        Type::Optional(inner_type) => {
87            let (offset, alignment) = type_size_and_alignment(inner_type);
88
89            let alignment_octets: usize = alignment.into();
90
91            (MemorySize(offset.0 + alignment_octets as u16), alignment)
92        }
93        Type::Generic(a, b) => {
94            error!(?a, ?b, "generic can not be generated");
95            panic!("generic is not supported")
96        }
97        Type::MutableReference(referenced_type) => type_size_and_alignment(referenced_type),
98        Type::Iterable(_) => panic!("not supported"),
99        Type::Blueprint(_) => panic!("not supported"),
100        Type::Variable(_) => panic!("not supported"),
101        Type::External(_) => todo!(),
102    }
103}
104
105pub fn reserve_space_for_type(ty: &Type, allocator: &mut ScopeAllocator) -> FrameMemoryRegion {
106    let (size, alignment) = type_size_and_alignment(ty);
107
108    allocator.reserve(size, alignment)
109}