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