swamp_script_code_gen/
alloc_util.rs1use 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}