| 1 | module transform |
| 2 | |
| 3 | import v3.flat |
| 4 | |
| 5 | // MapIndexInfo stores map index info metadata used by transform. |
| 6 | struct MapIndexInfo { |
| 7 | base_id flat.NodeId |
| 8 | key_id flat.NodeId |
| 9 | base_type string |
| 10 | key_type string |
| 11 | value_type string |
| 12 | } |
| 13 | |
| 14 | // map_type_parts supports map type parts handling for Transformer. |
| 15 | fn (mut t Transformer) map_type_parts(map_type string) (string, string) { |
| 16 | clean := t.clean_map_type(map_type) |
| 17 | if !clean.starts_with('map[') { |
| 18 | return '', '' |
| 19 | } |
| 20 | return t.map_key_type(clean), t.map_value_type(clean) |
| 21 | } |
| 22 | |
| 23 | // make_new_map_call builds make new map call data for transform. |
| 24 | fn (mut t Transformer) make_new_map_call(map_type string) flat.NodeId { |
| 25 | key_type, value_type := t.map_type_parts(map_type) |
| 26 | hash_fn, eq_fn, clone_fn, free_fn := map_callback_names(key_type) |
| 27 | mut args := []flat.NodeId{} |
| 28 | args << t.make_sizeof_type(key_type) |
| 29 | args << t.make_sizeof_type(value_type) |
| 30 | args << t.make_ident(hash_fn) |
| 31 | args << t.make_ident(eq_fn) |
| 32 | args << t.make_ident(clone_fn) |
| 33 | args << t.make_ident(free_fn) |
| 34 | return t.make_call_typed('new_map', args, map_type) |
| 35 | } |
| 36 | |
| 37 | // map_callback_names supports map callback names handling for transform. |
| 38 | fn map_callback_names(key_type string) (string, string, string, string) { |
| 39 | if key_type == 'string' { |
| 40 | return 'map_hash_string', 'map_eq_string', 'map_clone_string', 'map_free_string' |
| 41 | } |
| 42 | size_suffix := match key_type { |
| 43 | 'u8', 'i8', 'bool', 'char' { '1' } |
| 44 | 'u16', 'i16' { '2' } |
| 45 | 'i64', 'u64', 'isize', 'usize', 'voidptr' { '8' } |
| 46 | else { '4' } |
| 47 | } |
| 48 | |
| 49 | return 'map_hash_int_${size_suffix}', 'map_eq_int_${size_suffix}', 'map_clone_int_${size_suffix}', 'map_free_nop' |
| 50 | } |
| 51 | |
| 52 | // map_index_info supports map index info handling for Transformer. |
| 53 | fn (mut t Transformer) map_index_info(index_id flat.NodeId) ?MapIndexInfo { |
| 54 | if int(index_id) < 0 { |
| 55 | return none |
| 56 | } |
| 57 | lhs := t.a.nodes[int(index_id)] |
| 58 | if lhs.kind != .index || lhs.children_count < 2 || lhs.value == 'range' { |
| 59 | return none |
| 60 | } |
| 61 | base_id := t.a.child(&lhs, 0) |
| 62 | key_id := t.a.child(&lhs, 1) |
| 63 | base_type := t.node_type(base_id) |
| 64 | map_type := t.clean_map_type(base_type) |
| 65 | if !map_type.starts_with('map[') { |
| 66 | return none |
| 67 | } |
| 68 | key_type, raw_value_type := t.map_type_parts(map_type) |
| 69 | if key_type.len == 0 || raw_value_type.len == 0 { |
| 70 | return none |
| 71 | } |
| 72 | // Qualify a bare local sum type (`Value` -> `eval.Value`). A bare name can clash |
| 73 | // with an imported type of the same name and resolve to the wrong sum type when the |
| 74 | // value is later wrapped into the map element type. |
| 75 | mut value_type := raw_value_type |
| 76 | if !value_type.contains('.') && !value_type.contains('[') && !value_type.starts_with('&') |
| 77 | && t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' { |
| 78 | qualified := '${t.cur_module}.${value_type}' |
| 79 | if qualified in t.sum_types || (!isnil(t.tc) && qualified in t.tc.sum_types) { |
| 80 | value_type = qualified |
| 81 | } |
| 82 | } |
| 83 | return MapIndexInfo{ |
| 84 | base_id: base_id |
| 85 | key_id: key_id |
| 86 | base_type: base_type |
| 87 | key_type: key_type |
| 88 | value_type: value_type |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // make_map_get_expr builds make map get expr data for transform. |
| 93 | fn (mut t Transformer) make_map_get_expr(map_expr flat.NodeId, base_type string, key_name string, zero_name string, value_type string) flat.NodeId { |
| 94 | call := t.make_call_typed('map__get', arr3(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp, |
| 95 | t.make_ident(key_name)), t.make_prefix(.amp, t.make_ident(zero_name))), 'voidptr') |
| 96 | cast := t.make_cast('&${value_type}', call, '&${value_type}') |
| 97 | return t.make_prefix(.mul, cast) |
| 98 | } |
| 99 | |
| 100 | // make_map_get_check_expr builds make map get check expr data for transform. |
| 101 | fn (mut t Transformer) make_map_get_check_expr(map_expr flat.NodeId, base_type string, key_name string) flat.NodeId { |
| 102 | return t.make_call_typed('map__get_check', arr2(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp, |
| 103 | t.make_ident(key_name))), 'voidptr') |
| 104 | } |
| 105 | |
| 106 | // make_map_exists_expr builds make map exists expr data for transform. |
| 107 | fn (mut t Transformer) make_map_exists_expr(map_expr flat.NodeId, base_type string, key_name string) flat.NodeId { |
| 108 | return t.make_call_typed('map__exists', arr2(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp, |
| 109 | t.make_ident(key_name))), 'bool') |
| 110 | } |
| 111 | |
| 112 | // make_map_set_stmt builds make map set stmt data for transform. |
| 113 | fn (mut t Transformer) make_map_set_stmt(map_expr flat.NodeId, base_type string, key_name string, value_name string) flat.NodeId { |
| 114 | call := t.make_call_typed('map__set', arr3(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp, |
| 115 | t.make_ident(key_name)), t.make_prefix(.amp, t.make_ident(value_name))), 'void') |
| 116 | return t.make_expr_stmt(call) |
| 117 | } |
| 118 | |
| 119 | // const_expr_for_ident supports const expr for ident handling for Transformer. |
| 120 | fn (t &Transformer) const_expr_for_ident(id flat.NodeId) ?flat.NodeId { |
| 121 | if int(id) < 0 || isnil(t.tc) { |
| 122 | return none |
| 123 | } |
| 124 | node := t.a.nodes[int(id)] |
| 125 | if node.kind != .ident || node.value.len == 0 { |
| 126 | return none |
| 127 | } |
| 128 | if t.var_type(node.value).len > 0 { |
| 129 | return none |
| 130 | } |
| 131 | if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' { |
| 132 | qname := '${t.cur_module}.${node.value}' |
| 133 | if expr_id := t.tc.const_exprs[qname] { |
| 134 | return expr_id |
| 135 | } |
| 136 | } |
| 137 | if expr_id := t.tc.const_exprs[node.value] { |
| 138 | return expr_id |
| 139 | } |
| 140 | return none |
| 141 | } |
| 142 | |
| 143 | // lower_map_membership_expr builds lower map membership expr data for transform. |
| 144 | fn (mut t Transformer) lower_map_membership_expr(map_id flat.NodeId, key_id flat.NodeId, map_type string) ?flat.NodeId { |
| 145 | clean_type := t.clean_map_type(map_type) |
| 146 | mut key_type := '' |
| 147 | if clean_type.starts_with('map[') { |
| 148 | key_type = t.map_key_type(clean_type) |
| 149 | } |
| 150 | if key_type.len == 0 { |
| 151 | key_type = t.node_type(key_id) |
| 152 | } |
| 153 | if key_type.len == 0 { |
| 154 | key := t.a.nodes[int(key_id)] |
| 155 | if key.kind == .selector { |
| 156 | key_type = t.selector_field_type(key) |
| 157 | } |
| 158 | } |
| 159 | if key_type.len == 0 { |
| 160 | return none |
| 161 | } |
| 162 | map_source_id := t.const_expr_for_ident(map_id) or { map_id } |
| 163 | map_expr := t.stable_expr_for_reuse(map_source_id) |
| 164 | key_name := t.new_temp('map_key') |
| 165 | t.pending_stmts << t.make_decl_assign_typed(key_name, t.transform_expr(key_id), key_type) |
| 166 | return t.make_map_exists_expr(map_expr, map_type, key_name) |
| 167 | } |
| 168 | |
| 169 | // try_lower_map_index_expr supports try lower map index expr handling for Transformer. |
| 170 | fn (mut t Transformer) try_lower_map_index_expr(_id flat.NodeId, node flat.Node) ?flat.NodeId { |
| 171 | if node.kind != .index || node.children_count < 2 || node.value == 'range' { |
| 172 | return none |
| 173 | } |
| 174 | base_id := t.a.child(&node, 0) |
| 175 | key_id := t.a.child(&node, 1) |
| 176 | base_type := t.node_type(base_id) |
| 177 | map_type := t.clean_map_type(base_type) |
| 178 | if !map_type.starts_with('map[') { |
| 179 | return none |
| 180 | } |
| 181 | key_type, value_type := t.map_type_parts(map_type) |
| 182 | if key_type.len == 0 || value_type.len == 0 { |
| 183 | return none |
| 184 | } |
| 185 | map_source_id := t.const_expr_for_ident(base_id) or { base_id } |
| 186 | map_expr := t.stable_expr_for_reuse(map_source_id) |
| 187 | key_name := t.new_temp('map_key') |
| 188 | zero_name := t.new_temp('map_zero') |
| 189 | t.pending_stmts << t.make_decl_assign_typed(key_name, t.transform_expr(key_id), key_type) |
| 190 | t.pending_stmts << t.make_decl_assign_typed(zero_name, t.zero_value_for_type(value_type), |
| 191 | value_type) |
| 192 | return t.make_map_get_expr(map_expr, base_type, key_name, zero_name, value_type) |
| 193 | } |
| 194 | |
| 195 | // is_map_index_or_expr reports whether is map index or expr applies in transform. |
| 196 | fn (mut t Transformer) is_map_index_or_expr(node flat.Node) bool { |
| 197 | if node.kind != .or_expr || node.children_count < 2 { |
| 198 | return false |
| 199 | } |
| 200 | expr := t.a.child_node(&node, 0) |
| 201 | if expr.kind != .index || expr.children_count < 2 || expr.value == 'range' { |
| 202 | return false |
| 203 | } |
| 204 | base_id := t.a.child(expr, 0) |
| 205 | base_type := t.node_type(base_id) |
| 206 | return t.clean_map_type(base_type).starts_with('map[') |
| 207 | } |
| 208 | |
| 209 | // transform_map_index_or_expr transforms transform map index or expr data for transform. |
| 210 | fn (mut t Transformer) transform_map_index_or_expr(id flat.NodeId, node flat.Node) flat.NodeId { |
| 211 | if node.children_count < 2 { |
| 212 | return id |
| 213 | } |
| 214 | expr_id := t.a.child(&node, 0) |
| 215 | body_id := t.a.child(&node, 1) |
| 216 | info := t.map_index_info(expr_id) or { return id } |
| 217 | map_expr := t.stable_expr_for_reuse(info.base_id) |
| 218 | key_name := t.new_temp('map_key') |
| 219 | ptr_name := t.new_temp('map_ptr') |
| 220 | val_name := t.new_temp('map_val') |
| 221 | outer_pending := t.pending_stmts.clone() |
| 222 | t.pending_stmts.clear() |
| 223 | key_expr := t.transform_expr(info.key_id) |
| 224 | mut prelude := []flat.NodeId{} |
| 225 | t.drain_pending(mut prelude) |
| 226 | prelude << t.make_decl_assign_typed(key_name, key_expr, info.key_type) |
| 227 | prelude << t.make_decl_assign_typed(ptr_name, t.make_map_get_check_expr(map_expr, |
| 228 | info.base_type, key_name), 'voidptr') |
| 229 | prelude << t.make_decl_assign_typed(val_name, t.zero_value_for_type(info.value_type), |
| 230 | info.value_type) |
| 231 | |
| 232 | ptr_ident := t.make_ident(ptr_name) |
| 233 | found_cond := t.make_infix(.ne, ptr_ident, t.a.add(.nil_literal)) |
| 234 | ptr_value := t.make_prefix(.mul, t.make_cast('&${info.value_type}', t.make_ident(ptr_name), |
| 235 | '&${info.value_type}')) |
| 236 | then_block := t.make_block(arr1(t.make_assign(t.make_ident(val_name), ptr_value))) |
| 237 | else_block := t.make_block(t.lower_map_or_body_to_stmts(body_id, val_name, info.value_type, |
| 238 | node.value)) |
| 239 | t.pending_stmts = outer_pending |
| 240 | for stmt in prelude { |
| 241 | t.pending_stmts << stmt |
| 242 | } |
| 243 | t.pending_stmts << t.make_if(found_cond, then_block, else_block) |
| 244 | return t.make_ident(val_name) |
| 245 | } |
| 246 | |
| 247 | // lower_map_or_body_to_stmts converts lower map or body to stmts data for transform. |
| 248 | fn (mut t Transformer) lower_map_or_body_to_stmts(body_id flat.NodeId, target_name string, target_type string, mode string) []flat.NodeId { |
| 249 | if mode == '!' || mode == '?' { |
| 250 | if t.is_optional_type_name(t.cur_fn_ret_type) { |
| 251 | return arr1(t.make_none_return_stmt()) |
| 252 | } |
| 253 | return arr1(t.make_panic_stmt('option/result propagation failed')) |
| 254 | } |
| 255 | if int(body_id) < 0 { |
| 256 | return []flat.NodeId{} |
| 257 | } |
| 258 | body := t.a.nodes[int(body_id)] |
| 259 | if body.kind != .block { |
| 260 | if body.kind == .none_expr && !t.is_optional_type_name(target_type) |
| 261 | && t.is_optional_type_name(t.cur_fn_ret_type) { |
| 262 | return arr1(t.make_none_return_stmt()) |
| 263 | } |
| 264 | return arr1(t.make_assign(t.make_ident(target_name), t.transform_expr(body_id))) |
| 265 | } |
| 266 | mut result := []flat.NodeId{} |
| 267 | for i in 0 .. body.children_count { |
| 268 | child_id := t.a.child(&body, i) |
| 269 | child := t.a.nodes[int(child_id)] |
| 270 | is_last := i == body.children_count - 1 |
| 271 | if is_last && child.kind == .expr_stmt && child.children_count > 0 { |
| 272 | inner_id := t.a.child(&child, 0) |
| 273 | inner := t.a.nodes[int(inner_id)] |
| 274 | if inner.kind == .none_expr && !t.is_optional_type_name(target_type) |
| 275 | && t.is_optional_type_name(t.cur_fn_ret_type) { |
| 276 | result << t.make_none_return_stmt() |
| 277 | continue |
| 278 | } |
| 279 | if t.node_type(inner_id) == 'void' { |
| 280 | expanded := t.transform_stmt(child_id) |
| 281 | t.drain_pending(mut result) |
| 282 | for eid in expanded { |
| 283 | result << eid |
| 284 | } |
| 285 | } else { |
| 286 | value := t.transform_expr(inner_id) |
| 287 | t.drain_pending(mut result) |
| 288 | result << t.make_assign(t.make_ident(target_name), value) |
| 289 | } |
| 290 | } else { |
| 291 | expanded := t.transform_stmt(child_id) |
| 292 | t.drain_pending(mut result) |
| 293 | for eid in expanded { |
| 294 | result << eid |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | _ = target_type |
| 299 | return result |
| 300 | } |
| 301 | |
| 302 | // try_lower_map_index_assign supports try lower map index assign handling for Transformer. |
| 303 | fn (mut t Transformer) try_lower_map_index_assign(node flat.Node) ?[]flat.NodeId { |
| 304 | if node.kind !in [.assign, .index_assign] || node.children_count < 2 { |
| 305 | return none |
| 306 | } |
| 307 | info := t.map_index_info(t.a.child(&node, 0)) or { return none } |
| 308 | map_expr := t.stable_expr_for_reuse(info.base_id) |
| 309 | key_name := t.new_temp('map_key') |
| 310 | mut result := []flat.NodeId{} |
| 311 | t.drain_pending(mut result) |
| 312 | result << t.make_decl_assign_typed(key_name, t.transform_expr(info.key_id), info.key_type) |
| 313 | rhs_id := t.a.child(&node, 1) |
| 314 | if node.op == .assign { |
| 315 | value_name := t.new_temp('map_val') |
| 316 | value := if info.value_type.starts_with('&') && t.is_sum_type_name(info.value_type[1..]) { |
| 317 | t.transform_expr_for_type(rhs_id, info.value_type) |
| 318 | } else if info.value_type in t.sum_types |
| 319 | || t.resolve_sum_name(info.value_type) in t.sum_types { |
| 320 | t.wrap_sum_value(rhs_id, info.value_type) |
| 321 | } else { |
| 322 | t.transform_expr(rhs_id) |
| 323 | } |
| 324 | result << t.make_decl_assign_typed(value_name, value, info.value_type) |
| 325 | result << t.make_map_set_stmt(map_expr, info.base_type, key_name, value_name) |
| 326 | return result |
| 327 | } |
| 328 | if node.op == .left_shift_assign && info.value_type.starts_with('[]') { |
| 329 | t.lower_map_index_append_with_info(info, map_expr, key_name, rhs_id, mut result) |
| 330 | return result |
| 331 | } |
| 332 | op := map_compound_to_infix_op(node.op) or { return none } |
| 333 | t.lower_map_index_compound_with_info(info, map_expr, key_name, op, rhs_id, mut result) |
| 334 | return result |
| 335 | } |
| 336 | |
| 337 | // map_compound_to_infix_op converts map compound to infix op data for transform. |
| 338 | fn map_compound_to_infix_op(op flat.Op) ?flat.Op { |
| 339 | match op { |
| 340 | .plus_assign { return flat.Op.plus } |
| 341 | .minus_assign { return flat.Op.minus } |
| 342 | .mul_assign { return flat.Op.mul } |
| 343 | .div_assign { return flat.Op.div } |
| 344 | .mod_assign { return flat.Op.mod } |
| 345 | .amp_assign { return flat.Op.amp } |
| 346 | .pipe_assign { return flat.Op.pipe } |
| 347 | .xor_assign { return flat.Op.xor } |
| 348 | .left_shift_assign { return flat.Op.left_shift } |
| 349 | .right_shift_assign { return flat.Op.right_shift } |
| 350 | else { return none } |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | // load_map_index_current reads load map index current input for transform. |
| 355 | fn (mut t Transformer) load_map_index_current(info MapIndexInfo, map_expr flat.NodeId, key_name string, mut result []flat.NodeId) string { |
| 356 | zero_name := t.new_temp('map_zero') |
| 357 | current_name := t.new_temp('map_val') |
| 358 | result << t.make_decl_assign_typed(zero_name, t.zero_value_for_type(info.value_type), |
| 359 | info.value_type) |
| 360 | get_expr := t.make_map_get_expr(map_expr, info.base_type, key_name, zero_name, info.value_type) |
| 361 | result << t.make_decl_assign_typed(current_name, get_expr, info.value_type) |
| 362 | return current_name |
| 363 | } |
| 364 | |
| 365 | // lower_map_index_compound_with_info builds lower map index compound with info data for transform. |
| 366 | fn (mut t Transformer) lower_map_index_compound_with_info(info MapIndexInfo, map_expr flat.NodeId, key_name string, op flat.Op, rhs_id flat.NodeId, mut result []flat.NodeId) { |
| 367 | current_name := t.load_map_index_current(info, map_expr, key_name, mut result) |
| 368 | rhs := t.transform_expr(rhs_id) |
| 369 | new_value := if info.value_type == 'string' && op == .plus { |
| 370 | t.make_call_typed('string__plus', arr2(t.make_ident(current_name), rhs), 'string') |
| 371 | } else { |
| 372 | t.make_infix(op, t.make_ident(current_name), rhs) |
| 373 | } |
| 374 | result << t.make_assign(t.make_ident(current_name), new_value) |
| 375 | result << t.make_map_set_stmt(map_expr, info.base_type, key_name, current_name) |
| 376 | } |
| 377 | |
| 378 | // lower_map_index_postfix_with_info builds lower map index postfix with info data for transform. |
| 379 | fn (mut t Transformer) lower_map_index_postfix_with_info(info MapIndexInfo, map_expr flat.NodeId, key_name string, op flat.Op, mut result []flat.NodeId) { |
| 380 | current_name := t.load_map_index_current(info, map_expr, key_name, mut result) |
| 381 | infix_op := if op == .dec { flat.Op.minus } else { flat.Op.plus } |
| 382 | new_value := t.make_infix(infix_op, t.make_ident(current_name), t.make_int_literal(1)) |
| 383 | result << t.make_assign(t.make_ident(current_name), new_value) |
| 384 | result << t.make_map_set_stmt(map_expr, info.base_type, key_name, current_name) |
| 385 | } |
| 386 | |
| 387 | // lower_map_index_append_with_info builds lower map index append with info data for transform. |
| 388 | fn (mut t Transformer) lower_map_index_append_with_info(info MapIndexInfo, map_expr flat.NodeId, key_name string, rhs_id flat.NodeId, mut result []flat.NodeId) { |
| 389 | current_name := t.load_map_index_current(info, map_expr, key_name, mut result) |
| 390 | append := t.make_infix(.left_shift, t.make_ident(current_name), t.transform_expr(rhs_id)) |
| 391 | t.annotate_left_shift(append) |
| 392 | result << t.make_expr_stmt(append) |
| 393 | result << t.make_map_set_stmt(map_expr, info.base_type, key_name, current_name) |
| 394 | } |
| 395 | |
| 396 | // try_lower_map_index_postfix_stmt |
| 397 | // supports helper handling in transform. |
| 398 | fn (mut t Transformer) try_lower_map_index_postfix_stmt(id flat.NodeId) ?[]flat.NodeId { |
| 399 | if int(id) < 0 { |
| 400 | return none |
| 401 | } |
| 402 | node := t.a.nodes[int(id)] |
| 403 | if node.kind != .postfix || node.children_count == 0 || node.op !in [.inc, .dec] { |
| 404 | return none |
| 405 | } |
| 406 | info := t.map_index_info(t.a.child(&node, 0)) or { return none } |
| 407 | map_expr := t.stable_expr_for_reuse(info.base_id) |
| 408 | key_name := t.new_temp('map_key') |
| 409 | mut result := []flat.NodeId{} |
| 410 | t.drain_pending(mut result) |
| 411 | result << t.make_decl_assign_typed(key_name, t.transform_expr(info.key_id), info.key_type) |
| 412 | t.lower_map_index_postfix_with_info(info, map_expr, key_name, node.op, mut result) |
| 413 | return result |
| 414 | } |
| 415 | |
| 416 | // try_lower_map_index_append_stmt |
| 417 | // supports helper handling in transform. |
| 418 | fn (mut t Transformer) try_lower_map_index_append_stmt(id flat.NodeId) ?[]flat.NodeId { |
| 419 | if int(id) < 0 { |
| 420 | return none |
| 421 | } |
| 422 | node := t.a.nodes[int(id)] |
| 423 | if node.kind != .infix || node.op != .left_shift || node.children_count < 2 { |
| 424 | return none |
| 425 | } |
| 426 | info := t.map_index_info(t.a.child(&node, 0)) or { return none } |
| 427 | if !info.value_type.starts_with('[]') { |
| 428 | return none |
| 429 | } |
| 430 | map_expr := t.stable_expr_for_reuse(info.base_id) |
| 431 | key_name := t.new_temp('map_key') |
| 432 | mut result := []flat.NodeId{} |
| 433 | t.drain_pending(mut result) |
| 434 | result << t.make_decl_assign_typed(key_name, t.transform_expr(info.key_id), info.key_type) |
| 435 | t.lower_map_index_append_with_info(info, map_expr, key_name, t.a.child(&node, 1), mut result) |
| 436 | return result |
| 437 | } |
| 438 | |
| 439 | // lower_map_init_to_runtime converts lower map init to runtime data for transform. |
| 440 | fn (mut t Transformer) lower_map_init_to_runtime(id flat.NodeId, node flat.Node) flat.NodeId { |
| 441 | map_type := if node.value.len > 0 { |
| 442 | node.value |
| 443 | } else if node.typ.len > 0 { |
| 444 | node.typ |
| 445 | } else { |
| 446 | t.node_type(id) |
| 447 | } |
| 448 | if !map_type.starts_with('map[') { |
| 449 | return id |
| 450 | } |
| 451 | init_call := t.make_new_map_call(map_type) |
| 452 | if node.children_count == 0 { |
| 453 | return init_call |
| 454 | } |
| 455 | tmp_name := t.new_temp('map_lit') |
| 456 | t.pending_stmts << t.make_decl_assign_typed(tmp_name, init_call, map_type) |
| 457 | key_type, value_type := t.map_type_parts(map_type) |
| 458 | for i := 0; i + 1 < node.children_count; i += 2 { |
| 459 | key_name := t.new_temp('map_key') |
| 460 | value_name := t.new_temp('map_val') |
| 461 | t.pending_stmts << t.make_decl_assign_typed(key_name, |
| 462 | t.transform_expr(t.a.child(&node, i)), key_type) |
| 463 | value_id := t.a.child(&node, i + 1) |
| 464 | value := if value_type.starts_with('&') && t.is_sum_type_name(value_type[1..]) { |
| 465 | t.transform_expr_for_type(value_id, value_type) |
| 466 | } else if value_type in t.sum_types || t.resolve_sum_name(value_type) in t.sum_types { |
| 467 | t.wrap_sum_value(value_id, value_type) |
| 468 | } else { |
| 469 | t.transform_expr(value_id) |
| 470 | } |
| 471 | t.pending_stmts << t.make_decl_assign_typed(value_name, value, value_type) |
| 472 | call := t.make_call_typed('map__set', arr3(t.make_prefix(.amp, t.make_ident(tmp_name)), t.make_prefix(.amp, |
| 473 | t.make_ident(key_name)), t.make_prefix(.amp, t.make_ident(value_name))), 'void') |
| 474 | t.pending_stmts << t.make_expr_stmt(call) |
| 475 | } |
| 476 | return t.make_ident(tmp_name) |
| 477 | } |
| 478 | |