vxx2 / vlib / v3 / transform / struct.v
612 lines · 590 sloc · 18.72 KB · 2b81918e62db9ab38787518603a7f93bee80868c
Raw
1module transform
2
3import v3.flat
4
5// transform_field_init_expr transforms transform field init expr data for transform.
6fn (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`).
33fn (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.
173fn (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.
217fn (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.
295fn (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
306fn (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
322fn (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.
346fn (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.
357fn (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.
371fn (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.
381fn (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.
457fn (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.
493fn (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.
508fn (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.
541fn (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).
554fn (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.
587fn (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