1use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7use source_map_node::Node;
8use swamp_semantic::{Expression, MapType};
9use swamp_vm_types::types::{BasicTypeRef, Destination, VmType};
10use swamp_vm_types::{MemoryLocation, MemoryOffset, PointerLocation};
11
12impl CodeBuilder<'_> {
13 pub fn map_subscript_helper(
15 &mut self,
16 map_header_location: &Destination,
17 map_type: &MapType,
18 key_expression: &Expression,
19 should_create_if_needed: bool,
20 ctx: &Context,
21 ) -> Destination {
22 let map_header_ptr_reg = self.emit_compute_effective_address_to_register(
23 map_header_location,
24 &key_expression.node,
25 "get map header absolute pointer",
26 );
27
28 let pointer_location = PointerLocation::new(map_header_ptr_reg);
29
30 let key_temp_storage_reg =
32 self.emit_aggregate_pointer_or_pointer_to_scalar_memory(key_expression, ctx);
33
34 let gen_value_type = self.state.layout_cache.layout(&map_type.value);
35 let map_entry_reg = self.temp_registers.allocate(
36 VmType::new_unknown_placement(gen_value_type.clone()),
37 "map entry temp",
38 );
39
40 if should_create_if_needed {
41 self.builder.add_map_get_or_reserve_entry_location(
42 map_entry_reg.register(),
43 &pointer_location,
44 &key_temp_storage_reg,
45 &key_expression.node,
46 "lookup the entry for this key, or create one, in the map",
47 );
48 let map_value_pointer = MemoryLocation::new_copy_over_whole_type_with_zero_offset(
50 map_entry_reg.register.clone(),
51 );
52 self.emit_initialize_memory_for_any_type(
53 &map_value_pointer,
54 &key_expression.node,
55 "initialize the map value entry, just to be safe",
56 );
57 } else {
58 self.builder.add_map_get_entry_location(
59 map_entry_reg.register(),
60 &pointer_location,
61 &key_temp_storage_reg,
62 &key_expression.node,
63 "lookup the entry for this key in the map",
64 );
65 }
66
67 Destination::Memory(MemoryLocation {
69 base_ptr_reg: map_entry_reg.register,
70 offset: MemoryOffset(0),
71 ty: VmType::new_unknown_placement(gen_value_type),
72 })
73 }
74
75 pub(crate) fn emit_map_storage_init_from_initializer_pair_list(
76 &mut self,
77 target_map_header_ptr_reg: &PointerLocation, initializer_pair_list_expressions: &[(Expression, Expression)],
79 key_type: &BasicTypeRef,
80 value_type: &BasicTypeRef,
81 logical_limit: usize,
82 node: &Node,
83 comment: &str,
84 ctx: &Context,
85 ) {
86 let hwm = self.temp_registers.save_mark();
87
88 let safe_output_register = self.temp_registers.allocate(
89 VmType::new_contained_in_register(
90 target_map_header_ptr_reg.ptr_reg.ty.basic_type().clone(),
91 ),
92 "safe output destination for map initialization list",
93 );
94 self.builder.add_mov_reg(
95 &safe_output_register.register,
96 &target_map_header_ptr_reg.ptr_reg,
97 node,
98 "safe output register destination for map initialization",
99 );
100 let safe_output_map_header_pointer_location =
101 PointerLocation::new(safe_output_register.register);
102
103 let key_frame_location = self.allocate_frame_space_and_return_destination_to_it(
104 key_type,
105 node,
106 "key temporary storage",
107 );
108 let key_frame_place = key_frame_location
109 .vm_type()
110 .unwrap()
111 .frame_placed_type()
112 .unwrap();
113
114 let value_target_register = self.temp_registers.allocate(
115 VmType::new_unknown_placement(value_type.clone()),
116 "key temp",
117 );
118
119 for (key_expr, value_expr) in initializer_pair_list_expressions {
120 let initializer_pair_node = &key_expr.node;
121
122 if key_frame_location.ty().total_size.0 > 1 {
123 self.builder.add_frame_memory_clear(
124 key_frame_place.region(),
125 initializer_pair_node,
126 "clear key area each time, to make sure hash is calculated correctly",
127 );
128 }
129
130 self.emit_expression_into_target_memory(
131 key_frame_location.grab_memory_location(),
132 key_expr,
133 "store key to memory",
134 ctx,
135 );
136
137 self.builder.add_map_get_or_reserve_entry_location(
138 value_target_register.register(),
139 &safe_output_map_header_pointer_location,
140 &key_frame_location.grab_memory_location().base_ptr_reg,
141 initializer_pair_node,
142 "find existing or create a map entry to write into",
143 );
144
145 let value_memory_location = MemoryLocation {
146 base_ptr_reg: value_target_register.register().clone(),
147 offset: MemoryOffset(0),
148 ty: VmType::new_unknown_placement(value_type.clone()),
149 };
150
151 if value_type.is_aggregate() {
153 self.emit_initialize_memory_for_any_type(
154 &value_memory_location,
155 initializer_pair_node,
156 "initialize map entry completely",
157 );
158 }
159
160 self.emit_expression_into_target_memory(
161 &value_memory_location,
162 value_expr,
163 "put value into map entry value section",
164 ctx,
165 );
166 }
167
168 self.temp_registers.restore_to_mark(hwm);
169 }
170}