| 1 | module transform |
| 2 | |
| 3 | import v3.flat |
| 4 | |
| 5 | // transform_field_init_expr transforms transform field init expr data for transform. |
| 6 | fn (mut t Transformer) transform_field_init_expr(id flat.NodeId, node flat.Node) flat.NodeId { |
| 7 | if node.children_count == 0 { |
| 8 | return id |
| 9 | } |
| 10 | val_id := t.a.child(&node, 0) |
| 11 | val_node := t.a.nodes[int(val_id)] |
| 12 | new_val := if inferred_sum := t.sum_type_for_field_variant(node.value, val_id, val_node) { |
| 13 | t.wrap_sum_value(val_id, inferred_sum) |
| 14 | } else { |
| 15 | t.transform_expr(val_id) |
| 16 | } |
| 17 | start := t.a.children.len |
| 18 | t.a.children << new_val |
| 19 | return t.a.add_node(flat.Node{ |
| 20 | kind: .field_init |
| 21 | op: node.op |
| 22 | children_start: start |
| 23 | children_count: 1 |
| 24 | pos: node.pos |
| 25 | value: node.value |
| 26 | typ: node.typ |
| 27 | }) |
| 28 | } |
| 29 | |
| 30 | // transform_struct_fields transforms struct initialization fields with enum resolution. |
| 31 | // For each .field_init child, transforms the value expression. If the struct field type |
| 32 | // is a known enum, resolves shorthand enum values (e.g. `.red` -> `Color.red`). |
| 33 | fn (mut t Transformer) transform_struct_fields(id flat.NodeId, node flat.Node) flat.NodeId { |
| 34 | if node.children_count == 0 { |
| 35 | return t.add_missing_struct_defaults(id, node) |
| 36 | } |
| 37 | info := t.lookup_struct_info(node.value) or { |
| 38 | // Unknown struct: fall back to generic child transform |
| 39 | return t.transform_struct_children(id, node) |
| 40 | } |
| 41 | // Build a field name -> type lookup from the struct definition |
| 42 | mut field_types := map[string]string{} |
| 43 | mut field_order := []string{cap: info.fields.len} |
| 44 | for f in info.fields { |
| 45 | field_types[f.name] = f.typ |
| 46 | field_order << f.name |
| 47 | } |
| 48 | mut field_ids := []flat.NodeId{} |
| 49 | mut promoted_fields := map[string][]flat.NodeId{} |
| 50 | mut promoted_types := map[string]string{} |
| 51 | mut prelude := []flat.NodeId{} |
| 52 | t.drain_pending(mut prelude) |
| 53 | for i in 0 .. node.children_count { |
| 54 | child_id := t.a.child(&node, i) |
| 55 | child := t.a.nodes[int(child_id)] |
| 56 | if child.kind == .field_init && child.children_count > 0 { |
| 57 | val_id := t.a.child(&child, 0) |
| 58 | val_node := t.a.nodes[int(val_id)] |
| 59 | field_name := if child.value.len > 0 { |
| 60 | child.value |
| 61 | } else if i < field_order.len { |
| 62 | field_order[i] |
| 63 | } else { |
| 64 | '' |
| 65 | } |
| 66 | mut target_field_name := field_name |
| 67 | mut field_type := field_types[field_name] or { '' } |
| 68 | mut promoted_parent := '' |
| 69 | if field_type.len == 0 { |
| 70 | if embedded := t.embedded_field_for_promoted_field(info, field_name) { |
| 71 | promoted_parent = embedded.name |
| 72 | promoted_types[promoted_parent] = embedded.typ |
| 73 | if embedded_info := t.lookup_struct_info(embedded.typ) { |
| 74 | if promoted_type := t.struct_field_type(embedded_info, field_name) { |
| 75 | field_type = promoted_type |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | if val_node.kind == .array_literal && t.is_fixed_array_type(field_type) { |
| 81 | t.a.nodes[int(val_id)].typ = field_type |
| 82 | } |
| 83 | value_type := t.node_type(val_id) |
| 84 | sum_field_type := t.struct_field_sum_type(field_type, info.module) |
| 85 | enum_field_type := t.enum_type_name_for_expected(field_type, info.module) |
| 86 | // Check if the value is an enum shorthand and the field type is an enum |
| 87 | mut new_val := if val_node.kind == .enum_val && enum_field_type.len > 0 { |
| 88 | t.transform_enum_shorthand(val_id, val_node, enum_field_type) |
| 89 | } else if field_type.starts_with('[]') && t.is_fixed_array_type(value_type) { |
| 90 | t.fixed_array_value_to_array(val_id, value_type, field_type) |
| 91 | } else if sum_field_type.len > 0 { |
| 92 | t.wrap_sum_value(val_id, sum_field_type) |
| 93 | } else if inferred_sum := t.sum_type_for_field_variant(field_name, val_id, val_node) { |
| 94 | t.wrap_sum_value(val_id, inferred_sum) |
| 95 | } else if field_type.starts_with('&') { |
| 96 | t.transform_expr_for_type(val_id, field_type) |
| 97 | } else if field_type.len > 0 { |
| 98 | t.transform_expr_for_type(val_id, field_type) |
| 99 | } else { |
| 100 | t.transform_expr(val_id) |
| 101 | } |
| 102 | if sum_field_type.len == 0 && field_type.len > 0 { |
| 103 | new_val = t.coerce_transformed_expr_to_type(new_val, val_id, field_type) |
| 104 | } |
| 105 | t.drain_pending(mut prelude) |
| 106 | fi_start := t.a.children.len |
| 107 | t.a.children << new_val |
| 108 | new_field := t.a.add_node(flat.Node{ |
| 109 | kind: .field_init |
| 110 | op: child.op |
| 111 | children_start: fi_start |
| 112 | children_count: 1 |
| 113 | pos: child.pos |
| 114 | value: target_field_name |
| 115 | typ: child.typ |
| 116 | }) |
| 117 | if promoted_parent.len > 0 { |
| 118 | mut promoted := promoted_fields[promoted_parent] or { []flat.NodeId{} } |
| 119 | promoted << new_field |
| 120 | promoted_fields[promoted_parent] = promoted |
| 121 | } else { |
| 122 | field_ids << new_field |
| 123 | } |
| 124 | } else { |
| 125 | field_ids << child_id |
| 126 | } |
| 127 | } |
| 128 | for parent, promoted in promoted_fields { |
| 129 | promoted_start := t.a.children.len |
| 130 | for fid in promoted { |
| 131 | t.a.children << fid |
| 132 | } |
| 133 | embedded_type := promoted_types[parent] or { parent } |
| 134 | embedded_init := t.a.add_node(flat.Node{ |
| 135 | kind: .struct_init |
| 136 | children_start: promoted_start |
| 137 | children_count: flat.child_count(promoted.len) |
| 138 | value: embedded_type |
| 139 | typ: embedded_type |
| 140 | }) |
| 141 | fi_start := t.a.children.len |
| 142 | t.a.children << embedded_init |
| 143 | field_ids << t.a.add_node(flat.Node{ |
| 144 | kind: .field_init |
| 145 | children_start: fi_start |
| 146 | children_count: 1 |
| 147 | value: parent |
| 148 | typ: embedded_type |
| 149 | }) |
| 150 | } |
| 151 | start := t.a.children.len |
| 152 | for fid in field_ids { |
| 153 | t.a.children << fid |
| 154 | } |
| 155 | new_id := t.a.add_node(flat.Node{ |
| 156 | kind: .struct_init |
| 157 | op: node.op |
| 158 | children_start: start |
| 159 | children_count: flat.child_count(field_ids.len) |
| 160 | pos: node.pos |
| 161 | value: node.value |
| 162 | typ: node.typ |
| 163 | }) |
| 164 | final_id := t.add_missing_struct_defaults(new_id, t.a.nodes[int(new_id)]) |
| 165 | for stmt in prelude { |
| 166 | t.pending_stmts << stmt |
| 167 | } |
| 168 | return final_id |
| 169 | } |
| 170 | |
| 171 | // transform_struct_children is a fallback for struct inits where the struct type is unknown. |
| 172 | // Transforms all field_init value expressions without enum resolution. |
| 173 | fn (mut t Transformer) transform_struct_children(id flat.NodeId, node flat.Node) flat.NodeId { |
| 174 | if node.children_count == 0 { |
| 175 | return id |
| 176 | } |
| 177 | mut field_ids := []flat.NodeId{} |
| 178 | for i in 0 .. node.children_count { |
| 179 | child_id := t.a.child(&node, i) |
| 180 | child := t.a.nodes[int(child_id)] |
| 181 | if child.kind == .field_init && child.children_count > 0 { |
| 182 | val_id := t.a.child(&child, 0) |
| 183 | new_val := t.transform_expr(val_id) |
| 184 | fi_start := t.a.children.len |
| 185 | t.a.children << new_val |
| 186 | field_ids << t.a.add_node(flat.Node{ |
| 187 | kind: .field_init |
| 188 | op: child.op |
| 189 | children_start: fi_start |
| 190 | children_count: 1 |
| 191 | pos: child.pos |
| 192 | value: child.value |
| 193 | typ: child.typ |
| 194 | }) |
| 195 | } else { |
| 196 | field_ids << child_id |
| 197 | } |
| 198 | } |
| 199 | start := t.a.children.len |
| 200 | for fid in field_ids { |
| 201 | t.a.children << fid |
| 202 | } |
| 203 | return t.a.add_node(flat.Node{ |
| 204 | kind: .struct_init |
| 205 | op: node.op |
| 206 | children_start: start |
| 207 | children_count: flat.child_count(field_ids.len) |
| 208 | pos: node.pos |
| 209 | value: node.value |
| 210 | typ: node.typ |
| 211 | }) |
| 212 | } |
| 213 | |
| 214 | // add_missing_struct_defaults checks if any fields with default values are missing |
| 215 | // from the struct initialization. This is a hook point for future default-fill logic. |
| 216 | // Currently returns the node unchanged because StructInfo does not yet store default values. |
| 217 | fn (mut t Transformer) add_missing_struct_defaults(id flat.NodeId, node flat.Node) flat.NodeId { |
| 218 | if node.value.len == 0 { |
| 219 | return id |
| 220 | } |
| 221 | info := t.lookup_struct_info(node.value) or { return id } |
| 222 | mut provided := map[string]bool{} |
| 223 | mut field_ids := []flat.NodeId{cap: int(node.children_count) + info.fields.len} |
| 224 | mut prelude := []flat.NodeId{} |
| 225 | t.drain_pending(mut prelude) |
| 226 | for i in 0 .. node.children_count { |
| 227 | child_id := t.a.child(&node, i) |
| 228 | child := t.a.nodes[int(child_id)] |
| 229 | if child.kind == .field_init { |
| 230 | provided[child.value] = true |
| 231 | } |
| 232 | field_ids << child_id |
| 233 | } |
| 234 | old_module := t.cur_module |
| 235 | if info.module.len > 0 { |
| 236 | t.cur_module = info.module |
| 237 | } |
| 238 | mut added := false |
| 239 | for field in info.fields { |
| 240 | if field.name in provided || int(field.default_expr) < 0 { |
| 241 | continue |
| 242 | } |
| 243 | default_node := t.a.nodes[int(field.default_expr)] |
| 244 | enum_field_type := t.enum_type_name_for_expected(field.typ, info.module) |
| 245 | new_val := if default_node.kind == .enum_val && enum_field_type.len > 0 { |
| 246 | t.transform_enum_shorthand(field.default_expr, default_node, enum_field_type) |
| 247 | } else if t.is_sum_type_name(field.typ) { |
| 248 | // A sum-type field default (e.g. `typ_expr Expr = EmptyExpr{}`) must be |
| 249 | // wrapped into the sum, not emitted as the bare variant. wrap_sum_value |
| 250 | // is a no-op when the value already is the sum type. |
| 251 | t.wrap_sum_value(field.default_expr, field.typ) |
| 252 | } else { |
| 253 | t.transform_expr_for_type(field.default_expr, field.typ) |
| 254 | } |
| 255 | t.drain_pending(mut prelude) |
| 256 | fi_start := t.a.children.len |
| 257 | t.a.children << new_val |
| 258 | field_ids << t.a.add_node(flat.Node{ |
| 259 | kind: .field_init |
| 260 | children_start: fi_start |
| 261 | children_count: 1 |
| 262 | value: field.name |
| 263 | typ: field.typ |
| 264 | }) |
| 265 | provided[field.name] = true |
| 266 | added = true |
| 267 | } |
| 268 | t.cur_module = old_module |
| 269 | if !added { |
| 270 | for stmt in prelude { |
| 271 | t.pending_stmts << stmt |
| 272 | } |
| 273 | return id |
| 274 | } |
| 275 | start := t.a.children.len |
| 276 | for fid in field_ids { |
| 277 | t.a.children << fid |
| 278 | } |
| 279 | final_id := t.a.add_node(flat.Node{ |
| 280 | kind: .struct_init |
| 281 | op: node.op |
| 282 | children_start: start |
| 283 | children_count: flat.child_count(field_ids.len) |
| 284 | pos: node.pos |
| 285 | value: node.value |
| 286 | typ: node.typ |
| 287 | }) |
| 288 | for stmt in prelude { |
| 289 | t.pending_stmts << stmt |
| 290 | } |
| 291 | return final_id |
| 292 | } |
| 293 | |
| 294 | // lookup_struct_info resolves lookup struct info information for transform. |
| 295 | fn (t &Transformer) lookup_struct_info(name string) ?StructInfo { |
| 296 | if info := t.lookup_struct_info_preferred(name) { |
| 297 | return info |
| 298 | } |
| 299 | normalized := t.normalize_type_alias(name) |
| 300 | if normalized != name { |
| 301 | return t.lookup_struct_info_direct(normalized) |
| 302 | } |
| 303 | return none |
| 304 | } |
| 305 | |
| 306 | fn (t &Transformer) lookup_struct_info_preferred(name string) ?StructInfo { |
| 307 | if name.contains('.') { |
| 308 | if name in t.structs { |
| 309 | return t.structs[name] |
| 310 | } |
| 311 | } else if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' { |
| 312 | qname := '${t.cur_module}.${name}' |
| 313 | if qname in t.structs { |
| 314 | return t.structs[qname] |
| 315 | } |
| 316 | } else if name in t.structs { |
| 317 | return t.structs[name] |
| 318 | } |
| 319 | return none |
| 320 | } |
| 321 | |
| 322 | fn (t &Transformer) lookup_struct_info_direct(name string) ?StructInfo { |
| 323 | if name.contains('.') { |
| 324 | if name in t.structs { |
| 325 | return t.structs[name] |
| 326 | } |
| 327 | } else if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' { |
| 328 | qname := '${t.cur_module}.${name}' |
| 329 | if qname in t.structs { |
| 330 | return t.structs[qname] |
| 331 | } |
| 332 | } |
| 333 | if name in t.structs { |
| 334 | return t.structs[name] |
| 335 | } |
| 336 | if name.contains('.') { |
| 337 | short_name := name.all_after_last('.') |
| 338 | if short_name in t.structs { |
| 339 | return t.structs[short_name] |
| 340 | } |
| 341 | } |
| 342 | return none |
| 343 | } |
| 344 | |
| 345 | // struct_field_type supports struct field type handling for Transformer. |
| 346 | fn (t &Transformer) struct_field_type(info StructInfo, field_name string) ?string { |
| 347 | for field in info.fields { |
| 348 | if field.name == field_name { |
| 349 | return field.typ |
| 350 | } |
| 351 | } |
| 352 | return none |
| 353 | } |
| 354 | |
| 355 | // embedded_field_for_promoted_field |
| 356 | // supports helper handling in transform. |
| 357 | fn (t &Transformer) embedded_field_for_promoted_field(info StructInfo, field_name string) ?FieldInfo { |
| 358 | for field in info.fields { |
| 359 | if !t.is_embedded_field(field) { |
| 360 | continue |
| 361 | } |
| 362 | embedded_info := t.lookup_struct_info(field.typ) or { continue } |
| 363 | if _ := t.struct_field_type(embedded_info, field_name) { |
| 364 | return field |
| 365 | } |
| 366 | } |
| 367 | return none |
| 368 | } |
| 369 | |
| 370 | // is_embedded_field reports whether is embedded field applies in transform. |
| 371 | fn (t &Transformer) is_embedded_field(field FieldInfo) bool { |
| 372 | if field.name.len == 0 || field.typ.len == 0 { |
| 373 | return false |
| 374 | } |
| 375 | short_typ := if field.typ.contains('.') { field.typ.all_after_last('.') } else { field.typ } |
| 376 | short_name := if field.name.contains('.') { field.name.all_after_last('.') } else { field.name } |
| 377 | return short_name == short_typ |
| 378 | } |
| 379 | |
| 380 | // transform_assoc_expr transforms transform assoc expr data for transform. |
| 381 | fn (mut t Transformer) transform_assoc_expr(id flat.NodeId, node flat.Node) flat.NodeId { |
| 382 | if node.kind != .assoc || node.children_count == 0 { |
| 383 | return id |
| 384 | } |
| 385 | base_id := t.a.child(&node, 0) |
| 386 | base_type := t.node_type(base_id) |
| 387 | mut assoc_type := node.value |
| 388 | if assoc_type.len == 0 { |
| 389 | assoc_type = base_type |
| 390 | } |
| 391 | if assoc_type.starts_with('&') { |
| 392 | assoc_type = assoc_type[1..] |
| 393 | } |
| 394 | mut field_types := map[string]string{} |
| 395 | mut assoc_module := '' |
| 396 | if info := t.lookup_struct_info(assoc_type) { |
| 397 | assoc_module = info.module |
| 398 | for field in info.fields { |
| 399 | field_types[field.name] = field.typ |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | tmp_name := t.new_temp('assoc') |
| 404 | outer_pending := t.pending_stmts.clone() |
| 405 | t.pending_stmts.clear() |
| 406 | |
| 407 | mut prelude := []flat.NodeId{} |
| 408 | transformed_base := t.transform_expr(base_id) |
| 409 | base := if base_type.starts_with('&') { |
| 410 | t.make_prefix(.mul, transformed_base) |
| 411 | } else { |
| 412 | transformed_base |
| 413 | } |
| 414 | t.drain_pending(mut prelude) |
| 415 | prelude << t.make_decl_assign_typed(tmp_name, base, assoc_type) |
| 416 | |
| 417 | for i in 1 .. node.children_count { |
| 418 | field_id := t.a.child(&node, i) |
| 419 | field := t.a.nodes[int(field_id)] |
| 420 | if field.kind != .field_init || field.children_count == 0 { |
| 421 | continue |
| 422 | } |
| 423 | value_id := t.a.child(&field, 0) |
| 424 | value_node := t.a.nodes[int(value_id)] |
| 425 | field_type := field_types[field.value] or { '' } |
| 426 | if value_node.kind == .array_literal && t.is_fixed_array_type(field_type) { |
| 427 | t.a.nodes[int(value_id)].typ = field_type |
| 428 | } |
| 429 | value_type := t.node_type(value_id) |
| 430 | enum_field_type := t.enum_type_name_for_expected(field_type, assoc_module) |
| 431 | value := if value_node.kind == .enum_val && enum_field_type.len > 0 { |
| 432 | t.transform_enum_shorthand(value_id, value_node, enum_field_type) |
| 433 | } else if field_type.starts_with('[]') && t.is_fixed_array_type(value_type) { |
| 434 | t.fixed_array_value_to_array(value_id, value_type, field_type) |
| 435 | } else if t.is_sum_type_name(field_type) { |
| 436 | t.wrap_sum_value(value_id, field_type) |
| 437 | } else if field_type.len > 0 { |
| 438 | t.transform_expr_for_type(value_id, field_type) |
| 439 | } else { |
| 440 | t.transform_expr(value_id) |
| 441 | } |
| 442 | t.drain_pending(mut prelude) |
| 443 | prelude << t.make_assign(t.make_selector(t.make_ident(tmp_name), field.value, field_type), |
| 444 | value) |
| 445 | } |
| 446 | |
| 447 | t.pending_stmts = outer_pending |
| 448 | for stmt in prelude { |
| 449 | t.pending_stmts << stmt |
| 450 | } |
| 451 | result := t.make_ident(tmp_name) |
| 452 | t.a.nodes[int(result)].typ = assoc_type |
| 453 | return result |
| 454 | } |
| 455 | |
| 456 | // transform_amp_assoc_expr_for_type supports transform_amp_assoc_expr_for_type handling. |
| 457 | fn (mut t Transformer) transform_amp_assoc_expr_for_type(_id flat.NodeId, node flat.Node, target_type string) ?flat.NodeId { |
| 458 | if node.kind != .prefix || node.op != .amp || node.children_count != 1 { |
| 459 | return none |
| 460 | } |
| 461 | child_id := t.a.child(&node, 0) |
| 462 | child := t.a.nodes[int(child_id)] |
| 463 | if child.kind != .assoc { |
| 464 | return none |
| 465 | } |
| 466 | value := t.transform_assoc_expr(child_id, child) |
| 467 | mut value_type := t.node_type(value) |
| 468 | if value_type.len == 0 { |
| 469 | value_type = t.node_type(child_id) |
| 470 | } |
| 471 | if value_type.starts_with('&') { |
| 472 | value_type = value_type[1..] |
| 473 | } |
| 474 | if value_type.len == 0 { |
| 475 | return none |
| 476 | } |
| 477 | addr := t.make_prefix(.amp, value) |
| 478 | size := t.make_sizeof_type(value_type) |
| 479 | dup := t.make_call_typed('memdup', arr2(addr, size), 'voidptr') |
| 480 | mut ptr_type := target_type |
| 481 | if ptr_type.len == 0 { |
| 482 | ptr_type = node.typ |
| 483 | } |
| 484 | if !ptr_type.starts_with('&') { |
| 485 | ptr_type = '&${value_type}' |
| 486 | } |
| 487 | cast := t.make_cast(ptr_type, dup, ptr_type) |
| 488 | t.a.nodes[int(cast)].typ = ptr_type |
| 489 | return cast |
| 490 | } |
| 491 | |
| 492 | // struct_field_sum_type supports struct field sum type handling for Transformer. |
| 493 | fn (t &Transformer) struct_field_sum_type(field_type string, owner_module string) string { |
| 494 | if t.is_sum_type_name(field_type) { |
| 495 | return field_type |
| 496 | } |
| 497 | if field_type.len == 0 || field_type.contains('.') || owner_module.len == 0 { |
| 498 | return '' |
| 499 | } |
| 500 | qname := '${owner_module}.${field_type}' |
| 501 | if qname in t.sum_types { |
| 502 | return qname |
| 503 | } |
| 504 | return '' |
| 505 | } |
| 506 | |
| 507 | // sum_type_for_field_variant supports sum type for field variant handling for Transformer. |
| 508 | fn (t &Transformer) sum_type_for_field_variant(field_name string, val_id flat.NodeId, val_node flat.Node) ?string { |
| 509 | if field_name != 'info' { |
| 510 | return none |
| 511 | } |
| 512 | mut variant := if val_node.kind in [.struct_init, .cast_expr, .assoc] && val_node.value.len > 0 { |
| 513 | val_node.value |
| 514 | } else if val_node.kind == .assoc && val_node.children_count > 0 { |
| 515 | t.node_type(t.a.child(&val_node, 0)) |
| 516 | } else { |
| 517 | t.node_type(val_id) |
| 518 | } |
| 519 | if variant.starts_with('&') { |
| 520 | variant = variant[1..] |
| 521 | } |
| 522 | if variant.len == 0 { |
| 523 | return none |
| 524 | } |
| 525 | short_variant := if variant.contains('.') { variant.all_after_last('.') } else { variant } |
| 526 | for sum_name, variants in t.sum_types { |
| 527 | if sum_name != 'TypeInfo' && !sum_name.ends_with('.TypeInfo') { |
| 528 | continue |
| 529 | } |
| 530 | for v in variants { |
| 531 | short_v := if v.contains('.') { v.all_after_last('.') } else { v } |
| 532 | if v == variant || short_v == short_variant { |
| 533 | return sum_name |
| 534 | } |
| 535 | } |
| 536 | } |
| 537 | return none |
| 538 | } |
| 539 | |
| 540 | // fixed_array_value_to_array converts fixed array value to array data for transform. |
| 541 | fn (mut t Transformer) fixed_array_value_to_array(value_id flat.NodeId, fixed_type string, array_type string) flat.NodeId { |
| 542 | elem_type := fixed_array_elem_type(fixed_type) |
| 543 | len_expr := t.make_fixed_array_len_expr(fixed_type) |
| 544 | return t.make_call_typed('new_array_from_c_array', [ |
| 545 | len_expr, |
| 546 | len_expr, |
| 547 | t.make_sizeof_type(elem_type), |
| 548 | t.transform_expr(value_id), |
| 549 | ], array_type) |
| 550 | } |
| 551 | |
| 552 | // transform_array_init_expr transforms .array_init nodes (e.g. `[]int{len: n}`). |
| 553 | // Recursively transforms any child expressions (len, cap, init values). |
| 554 | fn (mut t Transformer) transform_array_init_expr(id flat.NodeId, node flat.Node) flat.NodeId { |
| 555 | if fixed := t.transform_fixed_array_init_expr(node) { |
| 556 | return fixed |
| 557 | } |
| 558 | lowered := t.lower_array_init_to_runtime(id, node) |
| 559 | if lowered != id { |
| 560 | return lowered |
| 561 | } |
| 562 | if node.children_count == 0 { |
| 563 | return id |
| 564 | } |
| 565 | mut new_children := []flat.NodeId{cap: int(node.children_count)} |
| 566 | for i in 0 .. node.children_count { |
| 567 | child_id := t.a.child(&node, i) |
| 568 | new_children << t.transform_expr(child_id) |
| 569 | } |
| 570 | start := t.a.children.len |
| 571 | for nc in new_children { |
| 572 | t.a.children << nc |
| 573 | } |
| 574 | return t.a.add_node(flat.Node{ |
| 575 | kind: .array_init |
| 576 | op: node.op |
| 577 | children_start: start |
| 578 | children_count: node.children_count |
| 579 | pos: node.pos |
| 580 | value: node.value |
| 581 | typ: node.typ |
| 582 | }) |
| 583 | } |
| 584 | |
| 585 | // transform_map_init_expr transforms .map_init nodes. |
| 586 | // Recursively transforms all child key/value expressions. |
| 587 | fn (mut t Transformer) transform_map_init_expr(id flat.NodeId, node flat.Node) flat.NodeId { |
| 588 | if node.value.starts_with('map[') || node.typ.starts_with('map[') { |
| 589 | return t.lower_map_init_to_runtime(id, node) |
| 590 | } |
| 591 | if node.children_count == 0 { |
| 592 | return id |
| 593 | } |
| 594 | mut new_children := []flat.NodeId{cap: int(node.children_count)} |
| 595 | for i in 0 .. node.children_count { |
| 596 | child_id := t.a.child(&node, i) |
| 597 | new_children << t.transform_expr(child_id) |
| 598 | } |
| 599 | start := t.a.children.len |
| 600 | for nc in new_children { |
| 601 | t.a.children << nc |
| 602 | } |
| 603 | return t.a.add_node(flat.Node{ |
| 604 | kind: .map_init |
| 605 | op: node.op |
| 606 | children_start: start |
| 607 | children_count: node.children_count |
| 608 | pos: node.pos |
| 609 | value: node.value |
| 610 | typ: node.typ |
| 611 | }) |
| 612 | } |
| 613 | |