v4 / vlib / v3 / gen / c / struct.v
1857 lines · 1782 sloc · 55.72 KB · bd87753646a4c2ae1384399584858dc14cb90b28
Raw
1module c
2
3import v3.flat
4import v3.types
5
6// c_field_name supports c field name handling for c.
7fn c_field_name(name string) string {
8 if name.starts_with('&') {
9 return c_field_name(name[1..])
10 }
11 if name.starts_with('ptr') && name.len > 3 && name[3..].contains('__') {
12 return c_name(name[3..])
13 }
14 if name.starts_with('ptr') && name.len > 3 && name[3..].contains('.') {
15 return c_name(name[3..])
16 }
17 return c_name(name)
18}
19
20// struct_init_fields_key returns the key under which the initialized struct's checked fields
21// (and their concrete types) live. For a bare generic literal that adopts a concrete instance
22// (`Box{..}` where `Box[int]` is expected) that is the instance key `Box[int]`; the bare `Box`
23// entry is removed by monomorphization, so field-type lookups and omitted default-field
24// emission must use the instance key or they miss fields like `items []T` (leaving invalid
25// zeroed array/map metadata). Falls back to the given key for non-generic structs.
26fn (g &FlatGen) struct_init_fields_key(type_name string, fallback string) string {
27 if inst := g.generic_struct_init_instance_name(type_name) {
28 if inst in g.tc.structs {
29 return inst
30 }
31 }
32 return fallback
33}
34
35fn (mut g FlatGen) gen_struct_field_expr(value_id flat.NodeId, expected types.Type) {
36 if g.gen_callback_fn_value_for_expected_type(value_id, expected) {
37 return
38 }
39 g.gen_expr_with_expected_type(value_id, expected)
40}
41
42fn (mut g FlatGen) gen_struct_field_expr_for_field(value_id flat.NodeId, struct_name string, field_name string, expected types.Type) {
43 if c_abi_fn := g.struct_field_c_abi_fn_ptr_type(struct_name, field_name) {
44 if g.gen_callback_fn_value_for_field_c_abi(value_id, expected, c_abi_fn) {
45 return
46 }
47 }
48 g.gen_struct_field_expr(value_id, expected)
49}
50
51// gen_struct_init emits struct init output for c.
52fn (mut g FlatGen) gen_struct_init(node flat.Node) {
53 init_module := g.tc.cur_module
54 if node.value.starts_with('chan ') {
55 g.gen_channel_init(node)
56 return
57 }
58 if g.gen_lowered_sum_init(node) {
59 return
60 }
61 mut name := g.struct_init_c_type_name(node.value)
62 // A bare generic struct literal (`Vec4{..}`) carries no type args; when the
63 // surrounding expected type fixes them (e.g. a `Vec4[f32]` return), emit the
64 // concrete instance name so it matches the materialized struct.
65 if inst := g.generic_struct_init_instance_ct(node.value) {
66 name = inst
67 }
68 // A bare generic literal stores its fields under the concrete instance key (`Box[int]`);
69 // the bare `node.value` (`Box`) entry is removed by monomorphization, so resolve the
70 // instance for the fixed-array-field test, field-type lookups, and omitted-default emission.
71 lookup_name := g.struct_init_fields_key(node.value, node.value)
72 if node.children_count == 0 && g.is_scalar_zero_init_type(node.value, name) {
73 g.write(g.scalar_zero_init(name))
74 return
75 }
76 if !g.is_interface_type_name(node.value)
77 && g.struct_init_has_fixed_array_field(node, lookup_name) {
78 g.gen_struct_init_with_fixed_array_fields(node, name, init_module)
79 return
80 }
81 g.write('(${name}){')
82 mut allowed_fields := map[string]bool{}
83 if fields := g.struct_fields_for_type(lookup_name) {
84 for f in fields {
85 allowed_fields[f.name] = true
86 }
87 }
88 mut set_fields := map[string]bool{}
89 mut has_field := false
90 if g.is_interface_type_name(node.value) {
91 if tid := g.interface_init_typ_id(node) {
92 g.write('._typ = ${tid}')
93 has_field = true
94 }
95 }
96 for i in 0 .. node.children_count {
97 field := g.a.child_node(&node, i)
98 if field.value.len > 0 && allowed_fields.len > 0 && field.value !in allowed_fields {
99 continue
100 }
101 if has_field {
102 g.write(', ')
103 }
104 value_id := g.a.child(field, 0)
105 if field.value.len == 0 {
106 if sf := g.struct_field_at(lookup_name, i) {
107 if heap_copy_type := g.heap_copy_type_for_sum_pointer_field(node.value, sf.name,
108 value_id)
109 {
110 inner_ct := g.tc.c_type(heap_copy_type)
111 g.write('(${inner_ct}*)memdup(')
112 g.gen_expr(value_id)
113 g.write(', sizeof(${inner_ct}))')
114 } else {
115 g.gen_struct_field_expr_for_field(value_id, node.value, sf.name, sf.typ)
116 }
117 set_fields[sf.name] = true
118 } else {
119 g.gen_expr(value_id)
120 }
121 } else {
122 g.write('.${c_field_name(field.value)} = ')
123 if heap_copy_type := g.heap_copy_type_for_sum_pointer_field(node.value, field.value,
124 value_id)
125 {
126 inner_ct := g.tc.c_type(heap_copy_type)
127 g.write('(${inner_ct}*)memdup(')
128 g.gen_expr(value_id)
129 g.write(', sizeof(${inner_ct}))')
130 } else {
131 if ftyp := g.struct_field_type(lookup_name, field.value) {
132 if g.struct_field_value_is_plainly_incompatible(value_id, ftyp) {
133 g.gen_default_value_for_type(ftyp)
134 } else {
135 g.gen_struct_field_expr_for_field(value_id, node.value, field.value, ftyp)
136 }
137 } else {
138 g.gen_expr(value_id)
139 }
140 }
141 set_fields[field.value] = true
142 }
143 has_field = true
144 }
145 after_fields_module := g.tc.cur_module
146 g.tc.cur_module = init_module
147 sname := g.struct_init_resolved_decl_name(node.value)
148 g.tc.cur_module = after_fields_module
149 has_field = g.gen_struct_default_fields(sname, mut set_fields, has_field)
150 defaults_key := if lookup_name in g.tc.structs { lookup_name } else { sname }
151 if defaults_key in g.tc.structs {
152 for f in g.tc.structs[defaults_key] {
153 if f.name in set_fields {
154 continue
155 }
156 if f.typ is types.Map {
157 if has_field {
158 g.write(', ')
159 }
160 g.write('.${c_field_name(f.name)} = ')
161 g.write_new_map(f.typ.key_type, f.typ.value_type)
162 has_field = true
163 } else if f.typ is types.Array {
164 c_elem := g.tc.c_type(f.typ.elem_type)
165 if has_field {
166 g.write(', ')
167 }
168 g.write('.${c_field_name(f.name)} = array_new(sizeof(${c_elem}), 0, 0)')
169 has_field = true
170 } else if g.field_needs_default_init(f.typ) {
171 if has_field {
172 g.write(', ')
173 }
174 g.write('.${c_field_name(f.name)} = ')
175 g.gen_default_value_for_type(f.typ)
176 has_field = true
177 }
178 }
179 }
180 g.write('}')
181}
182
183fn (mut g FlatGen) struct_init_has_fixed_array_field(node flat.Node, type_name string) bool {
184 for i in 0 .. node.children_count {
185 field := g.a.child_node(&node, i)
186 if field.value.len == 0 {
187 if sf := g.struct_field_at(type_name, i) {
188 if sf.typ is types.ArrayFixed {
189 return true
190 }
191 }
192 continue
193 }
194 if ftyp := g.struct_field_type(type_name, field.value) {
195 if ftyp is types.ArrayFixed {
196 return true
197 }
198 }
199 }
200 return false
201}
202
203fn (mut g FlatGen) gen_struct_init_with_fixed_array_fields(node flat.Node, name string, init_module string) {
204 g.gen_struct_init_with_fixed_array_fields_impl(node, name, init_module, false)
205}
206
207// gen_struct_init_with_fixed_array_fields_impl builds a struct that has fixed-array
208// fields via a temp + per-field `memcpy` (array members can't be assigned in a
209// compound literal). When `heap`, the temp is `memdup`'d and a pointer returned,
210// for `&Struct{...}` initializers.
211fn (mut g FlatGen) gen_struct_init_with_fixed_array_fields_impl(node flat.Node, name string, init_module string, heap bool) {
212 tmp := g.tmp_name()
213 if heap {
214 g.write('(${name}*)')
215 }
216 g.write('({${name} ${tmp} = (${name}){')
217 // A bare generic literal stores its fields under the concrete instance key (`Box[int]`);
218 // the bare `node.value` (`Box`) entry is removed by monomorphization, so resolve the
219 // instance for the field lookups and omitted-default emission below.
220 lookup_name := g.struct_init_fields_key(node.value, node.value)
221 mut allowed_fields := map[string]bool{}
222 if fields := g.struct_fields_for_type(lookup_name) {
223 for f in fields {
224 allowed_fields[f.name] = true
225 }
226 }
227 mut fixed_fields := []string{}
228 mut fixed_values := []flat.NodeId{}
229 mut fixed_field_types := []types.Type{}
230 mut set_fields := map[string]bool{}
231 mut has_field := false
232 for i in 0 .. node.children_count {
233 field := g.a.child_node(&node, i)
234 if field.value.len > 0 && allowed_fields.len > 0 && field.value !in allowed_fields {
235 continue
236 }
237 value_id := g.a.child(field, 0)
238 if field.value.len == 0 {
239 if sf := g.struct_field_at(lookup_name, i) {
240 if sf.typ is types.ArrayFixed {
241 fixed_fields << sf.name
242 fixed_values << value_id
243 fixed_field_types << sf.typ
244 set_fields[sf.name] = true
245 continue
246 }
247 if has_field {
248 g.write(', ')
249 }
250 g.write('.${c_field_name(sf.name)} = ')
251 g.gen_struct_field_expr_for_field(value_id, node.value, sf.name, sf.typ)
252 set_fields[sf.name] = true
253 has_field = true
254 } else {
255 if has_field {
256 g.write(', ')
257 }
258 g.gen_expr(value_id)
259 has_field = true
260 }
261 } else {
262 ftyp := g.struct_field_type(lookup_name, field.value) or { types.Type(types.void_) }
263 if ftyp is types.ArrayFixed {
264 fixed_fields << field.value
265 fixed_values << value_id
266 fixed_field_types << ftyp
267 set_fields[field.value] = true
268 continue
269 }
270 if has_field {
271 g.write(', ')
272 }
273 g.write('.${c_field_name(field.value)} = ')
274 if heap_copy_type := g.heap_copy_type_for_sum_pointer_field(node.value, field.value,
275 value_id)
276 {
277 inner_ct := g.tc.c_type(heap_copy_type)
278 g.write('(${inner_ct}*)memdup(')
279 g.gen_expr(value_id)
280 g.write(', sizeof(${inner_ct}))')
281 } else if ftyp !is types.Void {
282 if g.struct_field_value_is_plainly_incompatible(value_id, ftyp) {
283 g.gen_default_value_for_type(ftyp)
284 } else {
285 g.gen_struct_field_expr_for_field(value_id, node.value, field.value, ftyp)
286 }
287 } else {
288 g.gen_expr(value_id)
289 }
290 set_fields[field.value] = true
291 has_field = true
292 }
293 }
294 after_fields_module := g.tc.cur_module
295 g.tc.cur_module = init_module
296 sname := g.struct_init_resolved_decl_name(node.value)
297 g.tc.cur_module = after_fields_module
298 has_field = g.gen_struct_default_fields(sname, mut set_fields, has_field)
299 defaults_key := if lookup_name in g.tc.structs { lookup_name } else { sname }
300 if defaults_key in g.tc.structs {
301 for f in g.tc.structs[defaults_key] {
302 if f.name in set_fields {
303 continue
304 }
305 if f.typ is types.Map {
306 if has_field {
307 g.write(', ')
308 }
309 g.write('.${c_field_name(f.name)} = ')
310 g.write_new_map(f.typ.key_type, f.typ.value_type)
311 has_field = true
312 } else if f.typ is types.Array {
313 c_elem := g.tc.c_type(f.typ.elem_type)
314 if has_field {
315 g.write(', ')
316 }
317 g.write('.${c_field_name(f.name)} = array_new(sizeof(${c_elem}), 0, 0)')
318 has_field = true
319 } else if g.field_needs_default_init(f.typ) {
320 if has_field {
321 g.write(', ')
322 }
323 g.write('.${c_field_name(f.name)} = ')
324 g.gen_default_value_for_type(f.typ)
325 has_field = true
326 }
327 }
328 }
329 g.write('};')
330 for i in 0 .. fixed_fields.len {
331 cfield := c_field_name(fixed_fields[i])
332 g.write(' memcpy(${tmp}.${cfield}, ')
333 g.gen_fixed_array_copy_source(fixed_values[i], fixed_field_types[i])
334 g.write(', sizeof(${tmp}.${cfield}));')
335 }
336 if heap {
337 g.write(' memdup(&${tmp}, sizeof(${name}));})')
338 } else {
339 g.write(' ${tmp};})')
340 }
341}
342
343// gen_fixed_array_copy_source emits a `memcpy` source for assigning into a fixed
344// array. A raw array literal becomes a typed compound literal (a valid expression
345// that decays to a pointer); a dynamic array value copies from its `.data` buffer;
346// other fixed-array expressions (variables, fields, unwrapped calls) decay as-is.
347fn (mut g FlatGen) gen_fixed_array_copy_source(value_id flat.NodeId, field_type types.Type) {
348 val_node := g.a.node(value_id)
349 if val_node.kind == .array_literal {
350 g.write('(${g.tc.c_type(field_type)})')
351 g.gen_expr(value_id)
352 return
353 }
354 val_type := types.unwrap_pointer(g.usable_expr_type(value_id))
355 if val_type is types.Array {
356 g.write('(')
357 g.gen_expr(value_id)
358 g.write(').data')
359 return
360 }
361 g.gen_expr(value_id)
362}
363
364// gen_lowered_sum_init emits lowered sum init output for c.
365fn (mut g FlatGen) gen_lowered_sum_init(node flat.Node) bool {
366 sum_name := g.resolve_sum_name(node.value)
367 if sum_name !in g.tc.sum_types || node.children_count == 0 {
368 return false
369 }
370 name := g.struct_init_c_type_name(node.value)
371 g.write('(${name}){')
372 for i in 0 .. node.children_count {
373 field := g.a.child_node(&node, i)
374 if i > 0 {
375 g.write(', ')
376 }
377 g.write('.${c_field_name(field.value)} = ')
378 g.gen_lowered_sum_field_value(sum_name, field)
379 }
380 g.write('}')
381 return true
382}
383
384// gen_lowered_sum_field_value emits lowered sum field value output for c.
385fn (mut g FlatGen) gen_lowered_sum_field_value(sum_name string, field &flat.Node) {
386 child_id := g.a.child(field, 0)
387 if field.value != 'typ' {
388 mut variant := ''
389 if field.typ.starts_with('&') {
390 variant = field.typ[1..]
391 } else if field.typ.len > 0 {
392 variant = field.typ
393 } else {
394 for v in g.tc.sum_types[sum_name] {
395 if g.sum_field_name(v) == field.value {
396 variant = v
397 break
398 }
399 }
400 }
401 if variant.len > 0 {
402 variant = g.resolve_variant(sum_name, variant)
403 inner_type := g.tc.parse_type(variant)
404 inner_ct := g.tc.c_type(inner_type)
405 child_type := g.tc.resolve_type(child_id)
406 g.write('(${inner_ct}*)memdup(')
407 if child_type is types.Pointer && g.type_names_match(child_type.base_type, inner_type) {
408 g.gen_expr(child_id)
409 } else {
410 g.write('(${inner_ct}[]){')
411 g.gen_expr_with_expected_type(child_id, inner_type)
412 g.write('}')
413 }
414 g.write(', sizeof(${inner_ct}))')
415 return
416 }
417 }
418 if field.typ.len > 0 {
419 g.gen_expr_with_expected_type(child_id, g.tc.parse_type(field.typ))
420 } else {
421 g.gen_expr(child_id)
422 }
423}
424
425// gen_channel_init emits channel init output for c.
426fn (mut g FlatGen) gen_channel_init(node flat.Node) {
427 elem_type := g.tc.parse_type(node.value[5..])
428 elem_ct := g.tc.c_type(elem_type)
429 g.write('sync__new_channel_st((u32)(')
430 if cap_id := channel_init_field(node, g.a, 'cap') {
431 g.gen_expr(cap_id)
432 } else {
433 g.write('0')
434 }
435 g.write('), (u32)(sizeof(${elem_ct})))')
436}
437
438// channel_init_field supports channel init field handling for c.
439fn channel_init_field(node flat.Node, a &flat.FlatAst, name string) ?flat.NodeId {
440 for i in 0 .. node.children_count {
441 field := a.child_node(&node, i)
442 if field.kind == .field_init && field.value == name && field.children_count > 0 {
443 return a.child(field, 0)
444 }
445 }
446 return none
447}
448
449// gen_heap_struct_init emits heap struct init output for c.
450fn (mut g FlatGen) gen_heap_struct_init(node flat.Node) {
451 init_module := g.tc.cur_module
452 mut name := g.struct_init_c_type_name(node.value)
453 // A bare generic heap literal (`&Vec4{..}`) carries no type args; when the
454 // surrounding expected type fixes them (e.g. a `&Vec4[f32]` return), emit the
455 // concrete instance name so the materialized struct matches the value path.
456 if inst := g.generic_struct_init_instance_ct(node.value) {
457 name = inst
458 }
459 sum_name := g.resolve_sum_name(node.value)
460 is_sum_literal := sum_name in g.tc.sum_types
461 // A bare generic literal stores its fields under the concrete instance key (`Box[int]`);
462 // the bare `node.value` (`Box`) entry is removed by monomorphization, so resolve the
463 // instance for the fixed-array-field test, field-type lookups, and omitted-default emission.
464 lookup_name := g.struct_init_fields_key(node.value, node.value)
465 if !is_sum_literal && !g.is_interface_type_name(node.value)
466 && g.struct_init_has_fixed_array_field(node, lookup_name) {
467 // Fixed-array fields can't be set in the `&(T){...}` compound literal; build
468 // via a temp + memcpy and memdup the result.
469 g.gen_struct_init_with_fixed_array_fields_impl(node, name, init_module, true)
470 return
471 }
472 g.write('(${name}*)memdup(&(${name}){')
473 mut allowed_fields := map[string]bool{}
474 if fields := g.struct_fields_for_type(lookup_name) {
475 for f in fields {
476 allowed_fields[f.name] = true
477 }
478 }
479 mut set_fields := map[string]bool{}
480 mut has_field := false
481 if g.is_interface_type_name(node.value) {
482 if tid := g.interface_init_typ_id(node) {
483 g.write('._typ = ${tid}')
484 has_field = true
485 }
486 }
487 for i in 0 .. node.children_count {
488 field := g.a.child_node(&node, i)
489 if field.value.len > 0 && allowed_fields.len > 0 && field.value !in allowed_fields {
490 continue
491 }
492 if has_field {
493 g.write(', ')
494 }
495 value_id := g.a.child(field, 0)
496 if field.value.len == 0 {
497 // Positional initializer (empty field name): emit a positional C value mapped
498 // to the field at this index (mirrors gen_struct_init); a `. = v` designator
499 // is invalid C.
500 if sf := g.struct_field_at(lookup_name, i) {
501 if heap_copy_type := g.heap_copy_type_for_sum_pointer_field(lookup_name, sf.name,
502 value_id)
503 {
504 inner_ct := g.tc.c_type(heap_copy_type)
505 g.write('(${inner_ct}*)memdup(')
506 g.gen_expr(value_id)
507 g.write(', sizeof(${inner_ct}))')
508 } else {
509 g.gen_struct_field_expr_for_field(value_id, node.value, sf.name, sf.typ)
510 }
511 set_fields[sf.name] = true
512 } else {
513 g.gen_expr(value_id)
514 }
515 has_field = true
516 continue
517 }
518 g.write('.${c_field_name(field.value)} = ')
519 if is_sum_literal {
520 g.gen_lowered_sum_field_value(sum_name, field)
521 } else if heap_copy_type := g.heap_copy_type_for_sum_pointer_field(node.value, field.value,
522 value_id)
523 {
524 inner_ct := g.tc.c_type(heap_copy_type)
525 g.write('(${inner_ct}*)memdup(')
526 g.gen_expr(value_id)
527 g.write(', sizeof(${inner_ct}))')
528 } else {
529 if ftyp := g.struct_field_type(lookup_name, field.value) {
530 if g.struct_field_value_is_plainly_incompatible(value_id, ftyp) {
531 g.gen_default_value_for_type(ftyp)
532 } else {
533 g.gen_struct_field_expr_for_field(value_id, node.value, field.value, ftyp)
534 }
535 } else {
536 g.gen_expr(value_id)
537 }
538 }
539 set_fields[field.value] = true
540 has_field = true
541 }
542 after_fields_module := g.tc.cur_module
543 g.tc.cur_module = init_module
544 sname := g.struct_init_resolved_decl_name(node.value)
545 g.tc.cur_module = after_fields_module
546 has_field = g.gen_struct_default_fields(sname, mut set_fields, has_field)
547 defaults_key := if lookup_name in g.tc.structs { lookup_name } else { sname }
548 if defaults_key in g.tc.structs {
549 for f in g.tc.structs[defaults_key] {
550 if f.name in set_fields {
551 continue
552 }
553 if f.typ is types.Map {
554 if has_field {
555 g.write(', ')
556 }
557 g.write('.${c_field_name(f.name)} = ')
558 g.write_new_map(f.typ.key_type, f.typ.value_type)
559 has_field = true
560 } else if f.typ is types.Array {
561 c_elem := g.tc.c_type(f.typ.elem_type)
562 if has_field {
563 g.write(', ')
564 }
565 g.write('.${c_field_name(f.name)} = array_new(sizeof(${c_elem}), 0, 0)')
566 has_field = true
567 } else if g.field_needs_default_init(f.typ) {
568 if has_field {
569 g.write(', ')
570 }
571 g.write('.${c_field_name(f.name)} = ')
572 g.gen_default_value_for_type(f.typ)
573 has_field = true
574 }
575 }
576 }
577 g.write('}, sizeof(${name}))')
578}
579
580// heap_copy_type_for_sum_pointer_field supports heap_copy_type_for_sum_pointer_field handling in c.
581fn (g &FlatGen) heap_copy_type_for_sum_pointer_field(type_name string, field_name string, value_id flat.NodeId) ?types.Type {
582 resolved_sum := g.resolve_sum_name(type_name)
583 if resolved_sum !in g.tc.sum_types || int(value_id) < 0 {
584 return none
585 }
586 value := g.a.nodes[int(value_id)]
587 if !g.pointer_variant_arg_needs_heap_copy(value) {
588 return none
589 }
590 for variant in g.tc.sum_types[resolved_sum] {
591 if g.sum_field_name(variant) != field_name
592 || !g.variant_references_sum(variant, resolved_sum) {
593 continue
594 }
595 variant_type := g.tc.parse_type(g.resolve_variant(resolved_sum, variant))
596 return variant_type
597 }
598 return none
599}
600
601// gen_struct_default_fields emits struct default fields output for c.
602fn (mut g FlatGen) gen_struct_default_fields(type_name string, mut set_fields map[string]bool, has_field bool) bool {
603 mut has := has_field
604 info := g.find_struct_decl(type_name) or { return has }
605 old_module := g.tc.cur_module
606 g.tc.cur_module = info.module
607 for i in 0 .. info.node.children_count {
608 field := g.a.child_node(&info.node, i)
609 if field.kind != .field_decl || field.children_count == 0 || field.value in set_fields {
610 continue
611 }
612 if has {
613 g.write(', ')
614 }
615 g.write('.${c_name(field.value)} = ')
616 g.gen_struct_field_expr_for_field(g.a.child(field, 0), info.full_name, field.value, g.struct_default_field_type(info,
617 field))
618 set_fields[field.value] = true
619 has = true
620 }
621 g.tc.cur_module = old_module
622 return has
623}
624
625fn (mut g FlatGen) struct_default_field_type(info StructDeclInfo, field flat.Node) types.Type {
626 if field.typ.len > 0 && !field.typ.contains('.') && info.module.len > 0 && info.module != 'main'
627 && info.module != 'builtin' {
628 qtyp := '${info.module}.${field.typ}'
629 if qtyp in g.tc.enum_names || qtyp in g.tc.structs || qtyp in g.tc.sum_types
630 || qtyp in g.tc.interface_names {
631 return g.tc.parse_type(qtyp)
632 }
633 }
634 return g.tc.parse_type(field.typ)
635}
636
637// gen_default_value_for_type emits default value for type output for c.
638fn (mut g FlatGen) gen_default_value_for_type(typ types.Type) {
639 raw_typ := typ
640 if typ is types.OptionType || typ is types.ResultType {
641 ct := g.optional_type_name(typ)
642 g.write('(${ct}){0}')
643 return
644 }
645 if typ is types.Struct && !typ.name.starts_with('C.') {
646 ct := g.tc.c_type(raw_typ)
647 g.write('(${ct}){')
648 mut set_fields := map[string]bool{}
649 mut has_field := g.gen_struct_default_fields(typ.name, mut set_fields, false)
650 mut sname := g.tc.qualify_name(typ.name)
651 if typ.name in g.tc.structs {
652 sname = typ.name
653 }
654 if sname in g.tc.structs {
655 for f in g.tc.structs[sname] {
656 if f.name in set_fields {
657 continue
658 }
659 if f.typ is types.Map {
660 if has_field {
661 g.write(', ')
662 }
663 g.write('.${c_name(f.name)} = ')
664 g.write_new_map(f.typ.key_type, f.typ.value_type)
665 has_field = true
666 } else if f.typ is types.Array {
667 c_elem := g.tc.c_type(f.typ.elem_type)
668 if has_field {
669 g.write(', ')
670 }
671 g.write('.${c_name(f.name)} = array_new(sizeof(${c_elem}), 0, 0)')
672 has_field = true
673 } else if g.field_needs_default_init(f.typ) {
674 if has_field {
675 g.write(', ')
676 }
677 g.write('.${c_name(f.name)} = ')
678 g.gen_default_value_for_type(f.typ)
679 has_field = true
680 }
681 }
682 }
683 g.write('}')
684 return
685 }
686 ct := g.tc.c_type(typ)
687 if g.is_scalar_c_type(ct) {
688 g.write(g.scalar_zero_init(ct))
689 return
690 }
691 g.write('(${ct}){0}')
692}
693
694fn (g &FlatGen) struct_field_value_is_plainly_incompatible(value_id flat.NodeId, field_type types.Type) bool {
695 value_type := g.tc.resolve_type(value_id)
696 if field_type is types.Primitive && value_type is types.Struct {
697 return true
698 }
699 if field_type is types.Primitive && value_type is types.SumType {
700 return true
701 }
702 return false
703}
704
705// field_needs_default_init reports whether an unset field of type `typ` must be
706// explicitly default-initialized in a struct literal — i.e. it is a by-value
707// struct whose type carries field defaults that C's `{0}` would not apply
708// (e.g. `min_len int = 999999`).
709fn (mut g FlatGen) field_needs_default_init(typ types.Type) bool {
710 if typ is types.Struct && !typ.name.starts_with('C.') {
711 return g.struct_has_field_defaults(typ.name)
712 }
713 return false
714}
715
716// struct_has_field_defaults reports whether building `type_name` as a struct
717// literal would set any non-zero field: a field with an explicit default
718// (`x int = 5`), or a by-value struct field whose own type has such defaults.
719// Returns false for structs with interface/sum-typed field defaults, since the
720// codegen default path cannot box those values.
721fn (mut g FlatGen) struct_has_field_defaults(type_name string) bool {
722 mut visited := map[string]bool{}
723 return g.struct_has_field_defaults_inner(type_name, mut visited)
724}
725
726// struct_has_field_defaults_inner converts struct has field defaults inner data for c.
727fn (mut g FlatGen) struct_has_field_defaults_inner(type_name string, mut visited map[string]bool) bool {
728 if type_name in visited {
729 return false
730 }
731 visited[type_name] = true
732 info := g.find_struct_decl(type_name) or { return false }
733 old_module := g.tc.cur_module
734 g.tc.cur_module = info.module
735 defer {
736 g.tc.cur_module = old_module
737 }
738 mut found := false
739 for i in 0 .. info.node.children_count {
740 field := g.a.child_node(&info.node, i)
741 if field.kind != .field_decl {
742 continue
743 }
744 ftyp := g.tc.parse_type(field.typ)
745 if field.children_count > 0 {
746 // Defaults for interface/sum-typed fields require boxing the value into
747 // the interface/sum representation, which the codegen default path cannot
748 // do. Treat the whole struct as unsafe to default-emit (leave it
749 // zero-initialized, as before) rather than emit an unboxed value.
750 if ftyp is types.SumType || ftyp is types.Interface {
751 return false
752 }
753 found = true
754 }
755 if ftyp is types.Struct && !ftyp.name.starts_with('C.') {
756 if g.struct_has_field_defaults_inner(ftyp.name, mut visited) {
757 found = true
758 }
759 }
760 }
761 return found
762}
763
764// gen_params_struct_arg emits a struct literal for a `@[params]` argument passed as
765// trailing `key: value` call args (e.g. `atof64(s, allow_extra_chars: true)`).
766// `node` is the call node; field_init children are read from `field_start` onward.
767fn (mut g FlatGen) gen_params_struct_arg(typ types.Type, node flat.Node, field_start int) {
768 raw_typ := typ
769 if typ is types.Struct {
770 ct := g.tc.c_type(raw_typ)
771 g.write('(${ct}){')
772 mut set_fields := map[string]bool{}
773 mut has_field := false
774 for i in field_start .. node.children_count {
775 field := g.a.child_node(&node, i)
776 if field.kind != .field_init || field.children_count == 0 {
777 continue
778 }
779 if has_field {
780 g.write(', ')
781 }
782 g.write('.${c_name(field.value)} = ')
783 if ftyp := g.struct_field_type(typ.name, field.value) {
784 g.gen_struct_field_expr_for_field(g.a.child(field, 0), typ.name, field.value, ftyp)
785 } else {
786 g.gen_expr(g.a.child(field, 0))
787 }
788 set_fields[field.value] = true
789 has_field = true
790 }
791 mut sname := g.tc.qualify_name(typ.name)
792 if typ.name in g.tc.structs {
793 sname = typ.name
794 }
795 has_field = g.gen_struct_default_fields(typ.name, mut set_fields, has_field)
796 if sname in g.tc.structs {
797 for f in g.tc.structs[sname] {
798 if f.name in set_fields {
799 continue
800 }
801 if f.typ is types.Map {
802 if has_field {
803 g.write(', ')
804 }
805 g.write('.${c_name(f.name)} = ')
806 g.write_new_map(f.typ.key_type, f.typ.value_type)
807 has_field = true
808 } else if f.typ is types.Array {
809 c_elem := g.tc.c_type(f.typ.elem_type)
810 if has_field {
811 g.write(', ')
812 }
813 g.write('.${c_name(f.name)} = array_new(sizeof(${c_elem}), 0, 0)')
814 has_field = true
815 } else if g.field_needs_default_init(f.typ) {
816 if has_field {
817 g.write(', ')
818 }
819 g.write('.${c_name(f.name)} = ')
820 g.gen_default_value_for_type(f.typ)
821 has_field = true
822 }
823 }
824 }
825 g.write('}')
826 return
827 }
828 g.gen_default_value_for_type(typ)
829}
830
831// is_scalar_zero_init_type reports whether is scalar zero init type applies in c.
832fn (g &FlatGen) is_scalar_zero_init_type(type_name string, c_type string) bool {
833 if type_name in g.tc.structs || g.tc.qualify_name(type_name) in g.tc.structs {
834 return false
835 }
836 if _ := g.find_struct_decl(type_name) {
837 return false
838 }
839 return g.is_scalar_c_type(c_type)
840}
841
842// is_scalar_c_type reports whether is scalar c type applies in c.
843fn (g &FlatGen) is_scalar_c_type(c_type string) bool {
844 if c_type.ends_with('*') {
845 return true
846 }
847 return c_type in ['bool', 'char', 'byte', 'u8', 'i8', 'u16', 'i16', 'u32', 'i32', 'u64', 'i64',
848 'int', 'isize', 'usize', 'size_t', 'ptrdiff_t', 'float', 'double', 'voidptr']
849}
850
851// is_aggregate_zero_init_type reports whether is aggregate zero init type applies in c.
852fn (g &FlatGen) is_aggregate_zero_init_type(typ types.Type, c_type string) bool {
853 if g.is_scalar_c_type(c_type) {
854 return false
855 }
856 return match typ {
857 types.Alias {
858 g.is_aggregate_zero_init_type(typ.base_type, c_type)
859 }
860 types.Array, types.ArrayFixed, types.Channel, types.Map, types.String, types.Struct,
861 types.Interface, types.SumType, types.OptionType, types.ResultType, types.MultiReturn {
862 true
863 }
864 else {
865 false
866 }
867 }
868}
869
870// can_use_global_brace_zero_init reports whether can use global brace zero init applies in c.
871fn (mut g FlatGen) can_use_global_brace_zero_init(typ types.Type, c_type string) bool {
872 return g.is_aggregate_zero_init_type(typ, c_type) && !g.has_zero_sized_leading_init_slot(typ)
873}
874
875// has_zero_sized_leading_init_slot reports whether has zero sized leading init slot applies in c.
876fn (mut g FlatGen) has_zero_sized_leading_init_slot(typ types.Type) bool {
877 mut visited := map[string]bool{}
878 return g.has_zero_sized_leading_init_slot_inner(typ, mut visited)
879}
880
881// has_zero_sized_leading_init_slot_inner reports has_zero_sized_leading_init_slot_inner logic in c.
882fn (mut g FlatGen) has_zero_sized_leading_init_slot_inner(typ types.Type, mut visited map[string]bool) bool {
883 return match typ {
884 types.Alias {
885 g.has_zero_sized_leading_init_slot_inner(typ.base_type, mut visited)
886 }
887 types.ArrayFixed {
888 if g.fixed_array_len_is_zero(typ) {
889 true
890 } else {
891 g.has_zero_sized_leading_init_slot_inner(typ.elem_type, mut visited)
892 }
893 }
894 types.Struct {
895 if info := g.find_struct_decl(typ.name) {
896 if info.full_name in visited {
897 false
898 } else {
899 visited[info.full_name] = true
900 old_module := g.tc.cur_module
901 g.tc.cur_module = info.module
902 first := g.struct_field_at(info.full_name, 0) or {
903 g.tc.cur_module = old_module
904 return false
905 }
906 has := g.has_zero_sized_leading_init_slot_inner(first.typ, mut visited)
907 g.tc.cur_module = old_module
908 has
909 }
910 } else {
911 if typ.name in visited {
912 false
913 } else {
914 visited[typ.name] = true
915 first := g.struct_field_at(typ.name, 0) or { return false }
916 g.has_zero_sized_leading_init_slot_inner(first.typ, mut visited)
917 }
918 }
919 }
920 else {
921 false
922 }
923 }
924}
925
926// scalar_zero_init supports scalar zero init handling for FlatGen.
927fn (g &FlatGen) scalar_zero_init(c_type string) string {
928 if c_type in ['float', 'double'] {
929 return '0.0'
930 }
931 return '0'
932}
933
934// StructDeclInfo stores struct decl info metadata used by c.
935struct StructDeclInfo {
936 node flat.Node
937 module string
938 full_name string
939}
940
941// struct_init_c_type_name supports struct init c type name handling for FlatGen.
942// generic_struct_init_instance_ct returns the concrete-instance C type name for a
943// bare generic struct literal whose type args are pinned by the surrounding expected
944// type (e.g. `Vec4{..}` written where a `Vec4[f32]` is expected). Returns none when
945// the literal is already specialized, the base is not a generic struct, or the
946// expected type is not a matching concrete instance.
947fn (g &FlatGen) generic_struct_init_instance_ct(type_name string) ?string {
948 return g.tc.c_type(g.generic_struct_init_instance_type(type_name)?)
949}
950
951// generic_struct_init_instance_name is the concrete-instance V type name (`Box[int]`)
952// for a bare generic struct literal, so field and default lookups use the materialized
953// key under which the struct's fields are stored (the bare `Box` entry is removed by
954// monomorphization), not just the emitted C type.
955fn (g &FlatGen) generic_struct_init_instance_name(type_name string) ?string {
956 return g.generic_struct_init_instance_type(type_name)?.name()
957}
958
959// generic_struct_init_instance_type resolves the concrete generic instance a bare literal
960// adopts from the surrounding expected/return type (e.g. `Vec4{..}` -> `Vec4[f32]`).
961// Returns none when the literal is already specialized, the base is not a generic struct,
962// or the expected type is not a matching concrete instance.
963fn (g &FlatGen) generic_struct_init_instance_type(type_name string) ?types.Type {
964 if type_name.contains('[') {
965 return none
966 }
967 short := type_name.all_after_last('.')
968 // Prefer the explicit expected type; fall back to the enclosing function's return
969 // type ONLY for a literal in return position (a bare generic literal there carries
970 // no expected_expr_type) — otherwise a `Box{...}` in a local decl / argument whose
971 // expected type is the bare `Box` would be wrongly materialised as `Box_int`. Only
972 // adopt a candidate whose generic base matches the literal's base, so unrelated
973 // expected types never rename the struct.
974 //
975 // Note: `tc.struct_generic_params` is empty by cgen time, so the candidate's
976 // shape (a `Base[args]` instance whose base short-name equals the literal's) is
977 // the sole evidence that this bare literal is a generic struct instantiation.
978 mut candidates := [g.expected_expr_type]
979 if g.in_return {
980 candidates << g.cur_fn_ret
981 }
982 for cand in candidates {
983 // Unwrap a pointer so a `&Box[int]` expected type still matches a bare `Box`
984 // literal — the heap path (`&Box{..}`) needs the struct (`Box_int`), not the
985 // pointer, type name.
986 base_cand := types.unwrap_pointer(cand)
987 // A fixed/dynamic array type is not a generic struct instance even though its
988 // `.name()` renders like one (`[2]Foo` -> `Foo[2]`); skip it so a `Foo{..}` element
989 // of a `[2]Foo` literal keeps its element type instead of adopting the array type.
990 if base_cand is types.ArrayFixed || base_cand is types.Array {
991 continue
992 }
993 cand_name := base_cand.name()
994 if !cand_name.contains('[') {
995 continue
996 }
997 cand_base := cand_name.all_before('[')
998 if cand_base.len == 0 || cand_base.all_after_last('.') != short {
999 continue
1000 }
1001 return base_cand
1002 }
1003 return none
1004}
1005
1006fn (mut g FlatGen) struct_init_c_type_name(type_name string) string {
1007 typ := g.tc.parse_type(type_name)
1008 if typ is types.OptionType || typ is types.ResultType {
1009 return g.optional_type_name(typ)
1010 }
1011 info := g.find_struct_decl(type_name) or { return g.tc.c_type(g.tc.parse_type(type_name)) }
1012 if info.full_name.starts_with('C.') {
1013 return g.tc.c_type(g.tc.parse_type(info.full_name))
1014 }
1015 return c_name(info.full_name)
1016}
1017
1018// find_struct_decl resolves find struct decl information for c.
1019fn (g &FlatGen) find_struct_decl(type_name string) ?StructDeclInfo {
1020 if info := g.find_struct_decl_preferred(type_name) {
1021 return info
1022 }
1023 if alias_target := g.struct_type_alias_target(type_name) {
1024 if info := g.find_struct_decl_preferred(alias_target) {
1025 return info
1026 }
1027 if info := g.find_struct_decl_fallback(alias_target) {
1028 return info
1029 }
1030 }
1031 return g.find_struct_decl_fallback(type_name)
1032}
1033
1034fn (g &FlatGen) find_struct_decl_preferred(type_name string) ?StructDeclInfo {
1035 short_name := if type_name.contains('.') { type_name.all_after_last('.') } else { type_name }
1036 preferred_name := if !type_name.contains('.') && g.tc.cur_module.len > 0
1037 && g.tc.cur_module != 'main' && g.tc.cur_module != 'builtin' {
1038 '${g.tc.cur_module}.${type_name}'
1039 } else {
1040 type_name
1041 }
1042 if info := g.struct_decl_infos[preferred_name] {
1043 if info.node.value == short_name {
1044 return info
1045 }
1046 }
1047 if type_name.contains('.') {
1048 if info := g.struct_decl_infos[type_name] {
1049 return info
1050 }
1051 }
1052 return none
1053}
1054
1055fn (g &FlatGen) find_struct_decl_fallback(type_name string) ?StructDeclInfo {
1056 if type_name.contains('.') {
1057 return none
1058 }
1059 if info := g.struct_decl_short_infos[type_name] {
1060 return info
1061 }
1062 return none
1063}
1064
1065fn (g &FlatGen) struct_type_alias_target(type_name string) ?string {
1066 qname := g.tc.qualify_name(type_name)
1067 if target := g.tc.type_aliases[qname] {
1068 return target
1069 }
1070 if target := g.tc.type_aliases[type_name] {
1071 return target
1072 }
1073 return none
1074}
1075
1076fn (g &FlatGen) struct_init_resolved_decl_name(type_name string) string {
1077 if info := g.find_struct_decl(type_name) {
1078 return info.full_name
1079 }
1080 qname := g.tc.qualify_name(type_name)
1081 if qname in g.tc.structs {
1082 return qname
1083 }
1084 return type_name
1085}
1086
1087// struct_field_type supports struct field type handling for FlatGen.
1088fn (g &FlatGen) struct_field_type(type_name string, field_name string) ?types.Type {
1089 fields := g.struct_fields_for_type(type_name) or { return none }
1090 for f in fields {
1091 if f.name == field_name {
1092 return f.typ
1093 }
1094 }
1095 return none
1096}
1097
1098fn (g &FlatGen) struct_field_c_abi_fn_ptr_type(type_name string, field_name string) ?string {
1099 if info := g.find_struct_decl(type_name) {
1100 if typ := g.tc.struct_field_c_abi_fn_ptr_type(info.full_name, field_name) {
1101 return typ
1102 }
1103 }
1104 if typ := g.tc.struct_field_c_abi_fn_ptr_type(type_name, field_name) {
1105 return typ
1106 }
1107 if !type_name.contains('.') {
1108 qname := g.tc.qualify_name(type_name)
1109 if qname != type_name {
1110 if typ := g.tc.struct_field_c_abi_fn_ptr_type(qname, field_name) {
1111 return typ
1112 }
1113 }
1114 }
1115 return none
1116}
1117
1118// precompute_embedded_fields records, per struct type, only its embedded fields (those
1119// whose field name is the embedded type name). Most structs have none. Done once so the
1120// per-selector embedded-field resolution doesn't rescan (and re-c_name) every field of
1121// the receiver struct on every field access — a major cgen cost after #27538.
1122fn (mut g FlatGen) precompute_embedded_fields() {
1123 for type_name, fields in g.tc.structs {
1124 mut emb := []types.StructField{}
1125 for field in fields {
1126 if g.embedded_field_type_name(field).len > 0 {
1127 emb << field
1128 }
1129 }
1130 g.embedded_fields_by_type[type_name] = emb
1131 }
1132}
1133
1134// struct_embedded_fields returns the embedded fields of a type (mirrors
1135// struct_fields_for_type's key resolution against the precomputed map). Returns an empty
1136// slice for non-embedding structs, which is the common case.
1137fn (g &FlatGen) struct_embedded_fields(type_name string) []types.StructField {
1138 if emb := g.embedded_fields_by_type[type_name] {
1139 return emb
1140 }
1141 qname := g.tc.qualify_name(type_name)
1142 if emb := g.embedded_fields_by_type[qname] {
1143 return emb
1144 }
1145 if info := g.find_struct_decl(type_name) {
1146 if emb := g.embedded_fields_by_type[info.full_name] {
1147 return emb
1148 }
1149 }
1150 if type_name.contains('.') {
1151 short_name := type_name.all_after_last('.')
1152 if emb := g.embedded_fields_by_type[short_name] {
1153 return emb
1154 }
1155 }
1156 return []
1157}
1158
1159fn (g &FlatGen) struct_fields_for_type(type_name string) ?[]types.StructField {
1160 if info := g.find_struct_decl(type_name) {
1161 if fields := g.tc.structs[info.full_name] {
1162 return fields
1163 }
1164 }
1165 if type_name.contains('.') {
1166 if fields := g.tc.structs[type_name] {
1167 return fields
1168 }
1169 } else {
1170 qname := g.tc.qualify_name(type_name)
1171 if qname != type_name {
1172 if fields := g.tc.structs[qname] {
1173 return fields
1174 }
1175 }
1176 }
1177 if fields := g.tc.structs[type_name] {
1178 return fields
1179 }
1180 if type_name.contains('.') {
1181 short_name := type_name.all_after_last('.')
1182 if fields := g.tc.structs[short_name] {
1183 return fields
1184 }
1185 }
1186 return none
1187}
1188
1189fn (g &FlatGen) embedded_field_type_name(field types.StructField) string {
1190 clean_type := types.unwrap_pointer(field.typ)
1191 field_type_name := clean_type.name()
1192 if field_type_name.len == 0 {
1193 return ''
1194 }
1195 mut names := [field_type_name]
1196 base_name := types.generic_base_name(field_type_name)
1197 if base_name != field_type_name {
1198 names << base_name
1199 }
1200 short_field := if field.name.contains('.') { field.name.all_after_last('.') } else { field.name }
1201 for name in names {
1202 short_type := if name.contains('.') { name.all_after_last('.') } else { name }
1203 if field.name == name || short_field == short_type || c_name(field.name) == c_name(name) {
1204 return field_type_name
1205 }
1206 }
1207 return ''
1208}
1209
1210fn (g &FlatGen) direct_struct_field_exists(type_name string, field_name string) bool {
1211 fields := g.struct_fields_for_type(type_name) or { return false }
1212 for field in fields {
1213 if field.name == field_name {
1214 return true
1215 }
1216 }
1217 return false
1218}
1219
1220fn (g &FlatGen) embedded_field_for_promoted_field(type_name string, field_name string) ?types.StructField {
1221 path := g.embedded_field_path_for_promoted_field(type_name, field_name) or { return none }
1222 if path.len == 0 {
1223 return none
1224 }
1225 return path[0]
1226}
1227
1228fn (g &FlatGen) direct_embedded_field_for_selector(base_type types.Type, field_name string) ?types.StructField {
1229 type_name := g.type_lookup_name(base_type)
1230 if type_name.len == 0 {
1231 return none
1232 }
1233 // Only the embedded fields (precomputed) can match — no need to scan every field.
1234 for field in g.struct_embedded_fields(type_name) {
1235 embedded_type_name := g.embedded_field_type_name(field)
1236 if embedded_type_name.len == 0 {
1237 continue
1238 }
1239 short_type := if embedded_type_name.contains('.') {
1240 embedded_type_name.all_after_last('.')
1241 } else {
1242 embedded_type_name
1243 }
1244 if field_name == embedded_type_name || field_name == short_type
1245 || c_name(field_name) == c_name(embedded_type_name) {
1246 return field
1247 }
1248 }
1249 return none
1250}
1251
1252fn (g &FlatGen) embedded_field_path_for_promoted_field(type_name string, field_name string) ?[]types.StructField {
1253 for field in g.struct_embedded_fields(type_name) {
1254 embedded_type_name := g.embedded_field_type_name(field)
1255 if embedded_type_name.len == 0 {
1256 continue
1257 }
1258 if g.direct_struct_field_exists(embedded_type_name, field_name) {
1259 return [field]
1260 }
1261 if nested := g.embedded_field_path_for_promoted_field(embedded_type_name, field_name) {
1262 mut path := [field]
1263 path << nested
1264 return path
1265 }
1266 }
1267 return none
1268}
1269
1270fn (g &FlatGen) embedded_field_path_for_promoted_selector(base_type types.Type, field_name string) ?[]types.StructField {
1271 type_name := g.type_lookup_name(base_type)
1272 if type_name.len == 0 {
1273 return none
1274 }
1275 return g.embedded_field_path_for_promoted_field(type_name, field_name)
1276}
1277
1278fn (g &FlatGen) embedded_field_for_promoted_selector(base_type types.Type, field_name string) ?types.StructField {
1279 type_name := g.type_lookup_name(base_type)
1280 if type_name.len == 0 {
1281 return none
1282 }
1283 return g.embedded_field_for_promoted_field(type_name, field_name)
1284}
1285
1286fn (g &FlatGen) type_lookup_name(typ types.Type) string {
1287 clean_type := types.unwrap_pointer(typ)
1288 if clean_type is types.Alias {
1289 return clean_type.base_type.name()
1290 }
1291 return clean_type.name()
1292}
1293
1294// struct_field_at supports struct field at handling for FlatGen.
1295fn (g &FlatGen) struct_field_at(type_name string, index int) ?types.StructField {
1296 if index < 0 {
1297 return none
1298 }
1299 fields := g.struct_fields_for_type(type_name) or { return none }
1300 if index < fields.len {
1301 return fields[index]
1302 }
1303 return none
1304}
1305
1306// struct_field_type_at supports struct field type at handling for FlatGen.
1307fn (g &FlatGen) struct_field_type_at(type_name string, index int) ?types.Type {
1308 if field := g.struct_field_at(type_name, index) {
1309 return field.typ
1310 }
1311 return none
1312}
1313
1314// gen_return_assoc emits return assoc output for c.
1315fn (mut g FlatGen) gen_return_assoc(node flat.Node) {
1316 tmp := g.tmp_name()
1317 g.gen_assoc_return_tmp(node, tmp)
1318 g.writeln('return ${tmp};')
1319}
1320
1321fn (mut g FlatGen) gen_assoc_return_tmp(node flat.Node, tmp string) {
1322 ct := g.tc.c_type(g.tc.parse_type(node.value))
1323 g.write('${ct} ${tmp} = ')
1324 g.gen_expr(g.a.child(&node, 0))
1325 g.writeln(';')
1326 for i in 1 .. node.children_count {
1327 field := g.a.child_node(&node, i)
1328 if field.kind == .field_init && field.children_count > 0 {
1329 g.write('${tmp}.${c_name(field.value)} = ')
1330 if ftyp := g.struct_field_type(node.value, field.value) {
1331 g.gen_struct_field_expr_for_field(g.a.child(field, 0), node.value, field.value,
1332 ftyp)
1333 } else {
1334 g.gen_expr(g.a.child(field, 0))
1335 }
1336 g.writeln(';')
1337 }
1338 }
1339}
1340
1341// gen_assoc_expr emits assoc expr output for c.
1342fn (mut g FlatGen) gen_assoc_expr(node flat.Node) {
1343 ct := g.tc.c_type(g.tc.parse_type(node.value))
1344 tmp := g.tmp_name()
1345 g.write('({${ct} ${tmp} = ')
1346 g.gen_expr(g.a.child(&node, 0))
1347 g.write(';')
1348 for i in 1 .. node.children_count {
1349 field := g.a.child_node(&node, i)
1350 if field.kind == .field_init && field.children_count > 0 {
1351 g.write(' ${tmp}.${c_name(field.value)} = ')
1352 if ftyp := g.struct_field_type(node.value, field.value) {
1353 g.gen_struct_field_expr_for_field(g.a.child(field, 0), node.value, field.value,
1354 ftyp)
1355 } else {
1356 g.gen_expr(g.a.child(field, 0))
1357 }
1358 g.write(';')
1359 }
1360 }
1361 g.write(' ${tmp};})')
1362}
1363
1364// gen_heap_assoc_expr emits heap assoc expr output for c.
1365fn (mut g FlatGen) gen_heap_assoc_expr(node flat.Node) {
1366 ct := g.tc.c_type(g.tc.parse_type(node.value))
1367 tmp := g.tmp_name()
1368 g.write('({${ct} ${tmp} = ')
1369 g.gen_expr(g.a.child(&node, 0))
1370 g.write(';')
1371 for i in 1 .. node.children_count {
1372 field := g.a.child_node(&node, i)
1373 if field.kind == .field_init && field.children_count > 0 {
1374 g.write(' ${tmp}.${c_name(field.value)} = ')
1375 if ftyp := g.struct_field_type(node.value, field.value) {
1376 g.gen_struct_field_expr_for_field(g.a.child(field, 0), node.value, field.value,
1377 ftyp)
1378 } else {
1379 g.gen_expr(g.a.child(field, 0))
1380 }
1381 g.write(';')
1382 }
1383 }
1384 g.write(' (${ct}*)memdup(&${tmp}, sizeof(${ct}));})')
1385}
1386
1387// gen_map_init emits map init output for c.
1388fn (mut g FlatGen) gen_map_init(id flat.NodeId, node flat.Node) {
1389 if node.value.len > 0 {
1390 map_type := g.tc.parse_type(node.value)
1391 if map_type is types.Map {
1392 g.write_new_map(map_type.key_type, map_type.value_type)
1393 return
1394 }
1395 }
1396 if node.typ.len > 0 {
1397 map_type := g.tc.parse_type(node.typ)
1398 if map_type is types.Map {
1399 g.write_new_map(map_type.key_type, map_type.value_type)
1400 return
1401 }
1402 }
1403 if g.expected_expr_type is types.Map {
1404 g.write_new_map(g.expected_expr_type.key_type, g.expected_expr_type.value_type)
1405 return
1406 }
1407 resolved_type := g.tc.resolve_type(id)
1408 if resolved_type is types.Map {
1409 g.write_new_map(resolved_type.key_type, resolved_type.value_type)
1410 return
1411 }
1412 g.write('new_map(sizeof(int), sizeof(int), 0, 0, 0, 0)')
1413}
1414
1415// write_new_map writes new map output for c.
1416fn (mut g FlatGen) write_new_map(key_type types.Type, value_type types.Type) {
1417 mut c_key := g.tc.c_type(key_type)
1418 mut c_val := g.tc.c_type(value_type)
1419 if c_key.starts_with('fn_ptr:') {
1420 c_key = g.resolve_fn_ptr_type(c_key)
1421 }
1422 if c_val.starts_with('fn_ptr:') {
1423 c_val = g.resolve_fn_ptr_type(c_val)
1424 }
1425 hash_fn, eq_fn, clone_fn, free_fn := g.map_callback_names(key_type)
1426 g.write('new_map(sizeof(${c_key}), sizeof(${c_val}), ${hash_fn}, ${eq_fn}, ${clone_fn}, ${free_fn})')
1427}
1428
1429// map_callback_names supports map callback names handling for FlatGen.
1430fn (g &FlatGen) map_callback_names(key_type types.Type) (string, string, string, string) {
1431 if key_type is types.String {
1432 return 'map_hash_string', 'map_eq_string', 'map_clone_string', 'map_free_string'
1433 }
1434 c_key := g.tc.c_type(key_type)
1435 size_suffix := match c_key {
1436 'u8', 'i8', 'bool', 'char' { '1' }
1437 'u16', 'i16' { '2' }
1438 'i64', 'u64', 'isize', 'usize', 'voidptr' { '8' }
1439 else { '4' }
1440 }
1441
1442 return 'map_hash_int_${size_suffix}', 'map_eq_int_${size_suffix}', 'map_clone_int_${size_suffix}', 'map_free_nop'
1443}
1444
1445// skip_builtin_struct supports skip builtin struct handling for FlatGen.
1446fn (g &FlatGen) skip_builtin_struct(name string) bool {
1447 _ = g
1448 if name.starts_with('C.') {
1449 return true
1450 }
1451 return false
1452}
1453
1454// emit_interface_struct emits emit interface struct output for c.
1455fn (mut g FlatGen) emit_interface_struct(name string) {
1456 cn := c_name(name)
1457 g.writeln('struct ${cn} {')
1458 g.writeln('\tint _typ;')
1459 if cn == 'IError' {
1460 g.writeln('\tvoid* _object;')
1461 g.writeln('\tstring message;')
1462 g.writeln('\tint code;')
1463 } else {
1464 // pointer to the boxed concrete value, used by method dispatch
1465 g.writeln('\tvoid* _object;')
1466 }
1467 for field in g.tc.interface_fields[name] or { []types.StructField{} } {
1468 ct := g.tc.c_type(field.typ)
1469 g.writeln('\t${ct} ${c_name(field.name)};')
1470 }
1471 g.writeln('};')
1472 g.writeln('')
1473}
1474
1475// struct_decls supports struct decls handling for FlatGen.
1476fn (mut g FlatGen) struct_decls() {
1477 // Fixed-array typedefs whose element is a struct are emitted interleaved with the
1478 // structs below (right after the element struct is defined), so struct fields that
1479 // reference them resolve. Primitive-element ones were already emitted earlier.
1480 fixed_array_needed := g.collect_fixed_array_typedefs_needed()
1481 for name, _ in g.tc.structs {
1482 if g.skip_builtin_struct(name) {
1483 continue
1484 }
1485 tag := if name in g.tc.unions { 'union' } else { 'struct' }
1486 g.writeln('typedef ${tag} ${c_name(name)} ${c_name(name)};')
1487 }
1488 for name, variants in g.tc.sum_types {
1489 g.writeln('typedef struct ${c_name(name)} ${c_name(name)};')
1490 _ = variants
1491 }
1492 for name, _ in g.interfaces {
1493 g.writeln('typedef struct ${c_name(name)} ${c_name(name)};')
1494 }
1495 if g.has_builtins {
1496 g.writeln('typedef array Array;')
1497 }
1498 mut emitted := map[string]bool{}
1499 mut remaining := map[string]bool{}
1500 mut remaining_cnames := map[string]bool{}
1501 mut iface_remaining := map[string]bool{}
1502 for name, _ in g.interfaces {
1503 iface_remaining[name] = true
1504 remaining_cnames[c_name(name)] = true
1505 }
1506 for name, _ in g.tc.structs {
1507 if g.skip_builtin_struct(name) {
1508 continue
1509 }
1510 remaining[name] = true
1511 remaining_cnames[c_name(name)] = true
1512 }
1513 mut sum_remaining := map[string]bool{}
1514 for name, _ in g.tc.sum_types {
1515 sum_remaining[name] = true
1516 remaining_cnames[c_name(name)] = true
1517 }
1518 if 'string' in remaining {
1519 g.emit_struct('string')
1520 emitted['string'] = true
1521 remaining.delete('string')
1522 remaining_cnames.delete('string')
1523 }
1524 mut has_ierror := false
1525 for name, _ in iface_remaining {
1526 if c_name(name) == 'IError' {
1527 g.emit_interface_struct(name)
1528 emitted['IError'] = true
1529 iface_remaining.delete(name)
1530 remaining_cnames.delete('IError')
1531 has_ierror = true
1532 break
1533 }
1534 }
1535 err_field := if has_ierror { 'IError err; ' } else { '' }
1536 g.writeln('typedef struct Optional { bool ok; ${err_field}int value; } Optional;')
1537 g.writeln('')
1538 if g.has_builtins && 'array' in remaining {
1539 g.emit_struct('array')
1540 emitted['array'] = true
1541 emitted['Array'] = true
1542 remaining.delete('array')
1543 remaining_cnames.delete('array')
1544 }
1545 for _ in 0 .. 30 {
1546 if remaining.len == 0 && iface_remaining.len == 0 && sum_remaining.len == 0 {
1547 break
1548 }
1549 mut progress := false
1550 mut emitted_ifaces := []string{}
1551 for name, _ in iface_remaining {
1552 cn := c_name(name)
1553 mut can_emit := true
1554 if cn == 'IError' {
1555 if 'string' !in emitted && 'string' in remaining_cnames {
1556 can_emit = false
1557 }
1558 }
1559 // An interface struct embeds its declared data fields by value, so the
1560 // field types must be fully defined first (same constraint as structs).
1561 for field in g.tc.interface_fields[name] or { []types.StructField{} } {
1562 if field.typ is types.Pointer {
1563 continue
1564 }
1565 fct := g.tc.c_type(field.typ)
1566 if fct !in emitted && fct != cn && fct in remaining_cnames {
1567 can_emit = false
1568 break
1569 }
1570 }
1571 if can_emit {
1572 g.emit_interface_struct(name)
1573 emitted[cn] = true
1574 remaining_cnames.delete(cn)
1575 emitted_ifaces << name
1576 progress = true
1577 }
1578 }
1579 for name in emitted_ifaces {
1580 iface_remaining.delete(name)
1581 }
1582 mut emitted_structs := []string{}
1583 for name, _ in remaining {
1584 cn := c_name(name)
1585 if cn in emitted {
1586 remaining_cnames.delete(cn)
1587 emitted_structs << name
1588 progress = true
1589 continue
1590 }
1591 mut can_emit := true
1592 if name in g.tc.structs {
1593 for f in g.tc.structs[name] {
1594 if f.typ is types.Pointer {
1595 continue
1596 }
1597 mut ct := ''
1598 if f.typ is types.ArrayFixed {
1599 ct = g.tc.c_type(f.typ.elem_type)
1600 } else if f.typ is types.OptionType {
1601 ct = g.tc.c_type(f.typ.base_type)
1602 } else if f.typ is types.ResultType {
1603 ct = g.tc.c_type(f.typ.base_type)
1604 } else {
1605 ct = g.tc.c_type(f.typ)
1606 }
1607 if ct !in emitted && ct != cn && ct in remaining_cnames {
1608 can_emit = false
1609 break
1610 }
1611 }
1612 }
1613 if can_emit {
1614 if fields := g.tc.structs[name] {
1615 g.emit_struct_option_typedefs(fields)
1616 }
1617 g.emit_struct(name)
1618 emitted[cn] = true
1619 g.emit_ready_fixed_array_typedefs(fixed_array_needed, emitted)
1620 remaining_cnames.delete(cn)
1621 emitted_structs << name
1622 progress = true
1623 }
1624 }
1625 for name in emitted_structs {
1626 remaining.delete(name)
1627 }
1628 mut emitted_sums := []string{}
1629 for name, _ in sum_remaining {
1630 cn := c_name(name)
1631 mut can_emit_sum := true
1632 if name in g.tc.sum_types {
1633 for v in g.tc.sum_types[name] {
1634 if g.variant_references_sum(v, name) {
1635 continue
1636 }
1637 vt := g.tc.parse_type(v)
1638 if vt is types.SumType {
1639 if vt.name in sum_remaining {
1640 can_emit_sum = false
1641 break
1642 }
1643 }
1644 vct := g.tc.c_type(vt)
1645 if vct !in emitted && vct in remaining_cnames {
1646 can_emit_sum = false
1647 break
1648 }
1649 }
1650 }
1651 if can_emit_sum {
1652 g.emit_sum_type(name)
1653 emitted[cn] = true
1654 remaining_cnames.delete(cn)
1655 emitted_sums << name
1656 progress = true
1657 }
1658 }
1659 for name in emitted_sums {
1660 sum_remaining.delete(name)
1661 }
1662 if !progress {
1663 break
1664 }
1665 }
1666 for name, _ in iface_remaining {
1667 cn := c_name(name)
1668 g.emit_interface_struct(name)
1669 emitted[cn] = true
1670 }
1671 for name, _ in sum_remaining {
1672 g.emit_sum_type(name)
1673 }
1674 for name, _ in remaining {
1675 if fields := g.tc.structs[name] {
1676 g.emit_struct_option_typedefs(fields)
1677 }
1678 g.emit_struct(name)
1679 }
1680}
1681
1682// type_forward_decls returns type forward decls data for FlatGen.
1683fn (mut g FlatGen) type_forward_decls() {
1684 for name, _ in g.tc.structs {
1685 if g.skip_builtin_struct(name) {
1686 continue
1687 }
1688 tag := if name in g.tc.unions { 'union' } else { 'struct' }
1689 g.writeln('typedef ${tag} ${c_name(name)} ${c_name(name)};')
1690 }
1691 for name, _ in g.tc.sum_types {
1692 g.writeln('typedef struct ${c_name(name)} ${c_name(name)};')
1693 }
1694 for name, _ in g.interfaces {
1695 g.writeln('typedef struct ${c_name(name)} ${c_name(name)};')
1696 }
1697 if g.has_builtins {
1698 g.writeln('typedef array Array;')
1699 }
1700 g.writeln('')
1701}
1702
1703// emit_struct emits emit struct output for c.
1704fn (mut g FlatGen) emit_struct(name string) {
1705 old_module := g.tc.cur_module
1706 g.tc.cur_module = module_from_qualified_name(name)
1707 if name in g.tc.structs {
1708 fields := g.tc.structs[name]
1709 tag := if name in g.tc.unions { 'union' } else { 'struct' }
1710 g.writeln('${tag} ${c_name(name)} {')
1711 if fields.len == 0 {
1712 g.writeln('\tint _dummy;')
1713 }
1714 for f in fields {
1715 g.write_struct_field(name, f)
1716 }
1717 g.writeln('};')
1718 g.writeln('')
1719 }
1720 g.tc.cur_module = old_module
1721}
1722
1723// is_generic_struct reports whether is generic struct applies in c.
1724fn (g &FlatGen) is_generic_struct(name string) bool {
1725 if info := g.struct_decl_infos[name] {
1726 return info.node.typ.contains('generic')
1727 }
1728 short_name := if name.contains('.') { name.all_after_last('.') } else { name }
1729 if info := g.struct_decl_short_infos[short_name] {
1730 return info.full_name == name && info.node.typ.contains('generic')
1731 }
1732 return false
1733}
1734
1735// write_struct_field writes struct field output for c.
1736fn (mut g FlatGen) write_struct_field(_struct_name string, f types.StructField) {
1737 if f.typ is types.Void {
1738 g.writeln('\tint ${c_name(f.name)};')
1739 return
1740 }
1741 mut field_type := f.typ
1742 if f.typ is types.Alias {
1743 field_type = f.typ.base_type
1744 }
1745 raw_field_type := field_type
1746 if field_type is types.FnType {
1747 c_abi_fn := g.struct_field_c_abi_fn_ptr_type(_struct_name, f.name) or {
1748 g.tc.c_type(raw_field_type)
1749 }
1750 ct := g.resolve_fn_ptr_type(c_abi_fn)
1751 g.writeln('\t${ct} ${c_name(f.name)};')
1752 } else if f.typ is types.ArrayFixed {
1753 c_elem, dims := g.fixed_array_decl_parts(f.typ)
1754 g.writeln('\t${c_elem} ${c_name(f.name)}${dims};')
1755 } else {
1756 mut ct := if f.typ is types.OptionType || f.typ is types.ResultType {
1757 g.optional_type_name(f.typ)
1758 } else {
1759 g.tc.c_type(f.typ)
1760 }
1761 if ct.starts_with('fn_ptr:') {
1762 ct = g.resolve_fn_ptr_type(ct)
1763 }
1764 if ct == 'void' {
1765 ct = 'int'
1766 }
1767 g.writeln('\t${ct} ${c_name(f.name)};')
1768 }
1769}
1770
1771// preseed_struct_fn_ptr_types supports preseed struct fn ptr types handling for FlatGen.
1772fn (mut g FlatGen) preseed_struct_fn_ptr_types() {
1773 for struct_name, fields in g.tc.structs {
1774 for f in fields {
1775 if c_abi_fn := g.struct_field_c_abi_fn_ptr_type(struct_name, f.name) {
1776 g.resolve_fn_ptr_type(c_abi_fn)
1777 continue
1778 }
1779 g.preseed_fn_ptr_type(f.typ)
1780 }
1781 }
1782}
1783
1784fn (mut g FlatGen) preseed_global_fn_ptr_types() {
1785 for _, typ in g.global_types {
1786 g.preseed_fn_ptr_type(typ)
1787 }
1788}
1789
1790fn (mut g FlatGen) preseed_fn_ptr_type(typ types.Type) {
1791 if typ is types.Alias {
1792 g.preseed_fn_ptr_type(typ.base_type)
1793 return
1794 }
1795 if typ is types.FnType {
1796 ct := g.tc.c_type(typ)
1797 g.resolve_fn_ptr_type(ct)
1798 for param in typ.params {
1799 g.preseed_fn_ptr_type(param)
1800 }
1801 g.preseed_fn_ptr_type(typ.return_type)
1802 return
1803 }
1804 if typ is types.Array {
1805 g.preseed_fn_ptr_type(typ.elem_type)
1806 return
1807 }
1808 if typ is types.ArrayFixed {
1809 g.preseed_fn_ptr_type(typ.elem_type)
1810 return
1811 }
1812 if typ is types.Map {
1813 g.preseed_fn_ptr_type(typ.key_type)
1814 g.preseed_fn_ptr_type(typ.value_type)
1815 return
1816 }
1817 if typ is types.Pointer {
1818 g.preseed_fn_ptr_type(typ.base_type)
1819 return
1820 }
1821 if typ is types.OptionType {
1822 g.optional_type_name(typ)
1823 g.preseed_fn_ptr_type(typ.base_type)
1824 return
1825 }
1826 if typ is types.ResultType {
1827 g.optional_type_name(typ)
1828 g.preseed_fn_ptr_type(typ.base_type)
1829 return
1830 }
1831 if typ is types.MultiReturn {
1832 for item in typ.types {
1833 g.preseed_fn_ptr_type(item)
1834 }
1835 }
1836}
1837
1838// emit_struct_option_typedefs emits emit struct option typedefs output for c.
1839fn (mut g FlatGen) emit_struct_option_typedefs(fields []types.StructField) {
1840 mut wrote := false
1841 for f in fields {
1842 if f.typ is types.OptionType || f.typ is types.ResultType {
1843 opt_name := g.optional_type_name(f.typ)
1844 if opt_name == 'Optional' {
1845 continue
1846 }
1847 if val_type := g.needed_optional_types[opt_name] {
1848 if g.emit_optional_typedef(opt_name, val_type) {
1849 wrote = true
1850 }
1851 }
1852 }
1853 }
1854 if wrote {
1855 g.writeln('')
1856 }
1857}
1858