swamp_code_gen/
enum_variants.rs1use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7use source_map_node::Node;
8use swamp_semantic::EnumLiteralExpressions;
9use swamp_types::prelude::EnumVariantType;
10use swamp_types::{TypeKind, TypeRef};
11use swamp_vm_types::AggregateMemoryLocation;
12use swamp_vm_types::types::{BasicTypeKind, VmType, u8_type};
13
14impl CodeBuilder<'_> {
15 pub fn emit_enum_variant_to_memory_location(
16 &mut self,
17 target_memory_location: &AggregateMemoryLocation,
18 enum_type: &TypeRef,
19 variant_type: &EnumVariantType,
20 sorted_expressions: &EnumLiteralExpressions,
21 node: &Node,
22 ctx: &Context,
23 ) {
24 let variant_index = variant_type.common().container_index as usize;
25 let layout_gen_enum = self.state.layout_cache.layout(enum_type);
26 let BasicTypeKind::TaggedUnion(layout_enum) = &layout_gen_enum.kind else {
27 panic!("wrong")
28 };
29 let layout_variant = layout_enum.get_variant_by_index(variant_index);
30
31 let hwm = self.temp_registers.save_mark();
32
33 let temp_payload_reg = self.temp_registers.allocate(
35 VmType::new_unknown_placement(layout_variant.ty.clone()),
36 "variant literal payload",
37 );
38
39 self.builder.add_mov8_immediate(
40 temp_payload_reg.register(),
41 variant_index as u8,
42 node,
43 &format!("enum variant `{}` tag", variant_type.common().assigned_name),
44 );
45
46 let tag_memory_location = target_memory_location.offset(layout_enum.tag_offset, u8_type());
47 self.builder.add_st8_using_ptr_with_offset(
48 &tag_memory_location.location,
49 temp_payload_reg.register(),
50 node,
51 &format!("put enum tag in place {tag_memory_location} <- {temp_payload_reg}"),
52 );
53
54 let payload_basic_type = self.state.layout_cache.layout(&variant_type.payload_type);
56 let payload_memory_location =
57 target_memory_location.offset(layout_enum.payload_offset, payload_basic_type.clone());
58
59 self.emit_initialize_collections_in_type(
62 &payload_memory_location,
63 &payload_basic_type,
64 node,
65 &format!(
66 "initialize collections in enum variant payload for {}",
67 variant_type.common().assigned_name
68 ),
69 );
70
71 match &*variant_type.payload_type.kind {
73 TypeKind::Unit => {}
74 TypeKind::Tuple(_) => {
75 let EnumLiteralExpressions::Tuple(tuple_expressions) = sorted_expressions else {
76 panic!("internal error");
77 };
78 self.emit_tuple_literal_into_memory(
79 &payload_memory_location,
80 &variant_type.payload_type,
81 tuple_expressions,
82 ctx,
83 node,
84 );
85 }
86 TypeKind::AnonymousStruct(_) => {
87 let EnumLiteralExpressions::Struct(sorted_field_expressions) = sorted_expressions
88 else {
89 panic!("internal error");
90 };
91
92 self.emit_anonymous_struct_into_memory(
93 &payload_memory_location,
94 &variant_type.payload_type,
95 sorted_field_expressions,
96 node,
97 ctx,
98 );
99 }
100 _ => {
101 let EnumLiteralExpressions::Tuple(tuple_expressions) = sorted_expressions else {
103 panic!("internal error: expected single element tuple for direct payload type");
104 };
105
106 assert!(
107 (tuple_expressions.len() == 1),
108 "internal error: direct payload type should have exactly one expression"
109 );
110
111 self.emit_expression_into_target_memory(
113 &payload_memory_location.location,
114 &tuple_expressions[0],
115 &format!(
116 "direct payload for enum variant {}",
117 variant_type.common().assigned_name
118 ),
119 ctx,
120 );
121 }
122 }
123
124 self.temp_registers.restore_to_mark(hwm);
125 }
126}