vxx2 / vlib / v3 / gen / c / stmt.v
2322 lines · 2251 sloc · 69.93 KB · 2b81918e62db9ab38787518603a7f93bee80868c
Raw
1module c
2
3import strings
4import v3.flat
5import v3.types
6
7// gen_expr_lvalue emits expr lvalue output for c.
8fn gen_expr_lvalue(mut g FlatGen, id flat.NodeId) {
9 node := g.a.nodes[int(id)]
10 if node.kind == .index {
11 base_id := g.a.child(&node, 0)
12 base_type := g.tc.resolve_type(base_id)
13 if base_type is types.Map {
14 c_key := g.tc.c_type(base_type.key_type)
15 c_val := g.tc.c_type(base_type.value_type)
16 zero := if base_type.value_type is types.Array {
17 c_elem := g.tc.c_type(base_type.value_type.elem_type)
18 '&(${c_val}[]){array_new(sizeof(${c_elem}), 0, 0)}'
19 } else {
20 '&(${c_val}[]){0}'
21 }
22 g.write('(*(${c_val}*)map__get_or_set(&')
23 g.gen_expr(base_id)
24 g.write(', &(${c_key}[]){')
25 g.gen_expr(g.a.child(&node, 1))
26 g.write('}, ${zero}))')
27 return
28 }
29 }
30 g.gen_expr(id)
31}
32
33fn (mut g FlatGen) gen_split_array_append_expr_stmt(node flat.Node) bool {
34 if node.kind != .infix || node.op != .pipe || node.children_count < 2 {
35 return false
36 }
37 append_id := g.a.child(&node, 0)
38 append := g.a.nodes[int(append_id)]
39 if append.kind != .infix || append.op != .left_shift || append.children_count < 2 {
40 return false
41 }
42 lhs_id := g.a.child(&append, 0)
43 lhs_arr_type := types.unwrap_pointer(g.tc.resolve_type(lhs_id))
44 lhs_arr := array_like_type(lhs_arr_type) or { return false }
45 lhs_is_ptr := g.tc.resolve_type(lhs_id) is types.Pointer
46 amp := if lhs_is_ptr { '' } else { '&' }
47 c_elem := g.tc.c_type(lhs_arr.elem_type)
48 g.write('array_push(${amp}')
49 gen_expr_lvalue(mut g, lhs_id)
50 g.write(', &(${c_elem}[]){(')
51 g.gen_expr(g.a.child(&append, 1))
52 g.write(' ${g.op_str(node.op)} ')
53 g.gen_expr(g.a.child(&node, 1))
54 g.writeln(')});')
55 return true
56}
57
58// gen_node emits node output for c.
59fn (mut g FlatGen) gen_node(id flat.NodeId) {
60 if int(id) < 0 || int(id) >= g.a.nodes.len {
61 return
62 }
63 node := g.a.nodes[int(id)]
64 g.in_return = false
65 match node.kind {
66 .fn_decl, .c_fn_decl {
67 return
68 }
69 .expr_stmt {
70 child_id := g.a.child(&node, 0)
71 if int(child_id) < 0 || int(child_id) >= g.a.nodes.len {
72 return
73 }
74 child := g.a.nodes[int(child_id)]
75 if g.is_runtime_array_flags_stmt(child_id) {
76 return
77 }
78 if child.kind == .or_expr {
79 g.gen_or_expr_stmt(child)
80 return
81 } else if g.gen_split_array_append_expr_stmt(child) {
82 return
83 } else if child.kind == .infix && child.op == .left_shift {
84 lhs_id := g.a.child(&child, 0)
85 if child.value == 'push_many' {
86 g.gen_array_push_many_stmt(lhs_id, g.a.child(&child, 1))
87 } else if child.value == 'push' {
88 push_rhs_id := g.a.child(&child, 1)
89 mut c_elem := if child.typ.len > 0 {
90 g.tc.c_type(g.tc.parse_type(child.typ))
91 } else {
92 'string'
93 }
94 lhs_arr_type := types.unwrap_pointer(g.usable_expr_type(lhs_id))
95 if lhs_arr := array_like_type(lhs_arr_type) {
96 push_rhs_clean := types.unwrap_pointer(g.usable_expr_type(push_rhs_id))
97 if rhs_arr := array_like_type(push_rhs_clean) {
98 if g.tc.c_type(lhs_arr.elem_type) !in ['array', 'Array']
99 && g.tc.c_type(lhs_arr.elem_type) == g.tc.c_type(rhs_arr.elem_type) {
100 g.gen_array_push_many_stmt(lhs_id, push_rhs_id)
101 return
102 }
103 } else if rhs_fixed := array_fixed_type(push_rhs_clean) {
104 if g.tc.c_type(lhs_arr.elem_type) !in ['array', 'Array']
105 && g.tc.c_type(lhs_arr.elem_type) == g.tc.c_type(rhs_fixed.elem_type) {
106 g.gen_array_push_many_stmt(lhs_id, push_rhs_id)
107 return
108 }
109 }
110 c_elem = g.tc.c_type(lhs_arr.elem_type)
111 }
112 lhs_is_ptr := g.tc.resolve_type(lhs_id) is types.Pointer
113 amp := if lhs_is_ptr { '' } else { '&' }
114 g.write('array_push(${amp}')
115 gen_expr_lvalue(mut g, lhs_id)
116 g.write(', &(${c_elem}[]){')
117 if lhs_arr := array_like_type(lhs_arr_type) {
118 g.gen_expr_with_expected_type(push_rhs_id, lhs_arr.elem_type)
119 } else {
120 g.gen_expr(push_rhs_id)
121 }
122 g.writeln('});')
123 } else {
124 lhs_type := g.usable_expr_type(lhs_id)
125 clean := types.unwrap_pointer(lhs_type)
126 if lhs_arr := array_like_type(clean) {
127 rhs_id := g.a.child(&child, 1)
128 rhs_type := g.usable_expr_type(rhs_id)
129 rhs_clean := types.unwrap_pointer(rhs_type)
130 if rhs_arr := array_like_type(rhs_clean) {
131 if g.tc.c_type(lhs_arr.elem_type) !in ['array', 'Array']
132 && g.tc.c_type(lhs_arr.elem_type) == g.tc.c_type(rhs_arr.elem_type) {
133 g.gen_array_push_many_stmt(lhs_id, rhs_id)
134 } else {
135 c_elem := g.tc.c_type(lhs_arr.elem_type)
136 lhs_is_ptr := g.tc.resolve_type(lhs_id) is types.Pointer
137 amp := if lhs_is_ptr { '' } else { '&' }
138 g.write('array_push(${amp}')
139 gen_expr_lvalue(mut g, lhs_id)
140 g.write(', &(${c_elem}[]){')
141 g.gen_expr_with_expected_type(rhs_id, lhs_arr.elem_type)
142 g.writeln('});')
143 }
144 } else if rhs_fixed := array_fixed_type(rhs_clean) {
145 if g.tc.c_type(lhs_arr.elem_type) !in ['array', 'Array']
146 && g.tc.c_type(lhs_arr.elem_type) == g.tc.c_type(rhs_fixed.elem_type) {
147 g.gen_array_push_many_stmt(lhs_id, rhs_id)
148 } else {
149 c_elem := g.tc.c_type(lhs_arr.elem_type)
150 lhs_is_ptr := g.tc.resolve_type(lhs_id) is types.Pointer
151 amp := if lhs_is_ptr { '' } else { '&' }
152 g.write('array_push(${amp}')
153 gen_expr_lvalue(mut g, lhs_id)
154 g.write(', &(${c_elem}[]){')
155 g.gen_expr_with_expected_type(rhs_id, lhs_arr.elem_type)
156 g.writeln('});')
157 }
158 } else {
159 c_elem := g.tc.c_type(lhs_arr.elem_type)
160 lhs_is_ptr := g.tc.resolve_type(lhs_id) is types.Pointer
161 amp := if lhs_is_ptr { '' } else { '&' }
162 g.write('array_push(${amp}')
163 gen_expr_lvalue(mut g, lhs_id)
164 g.write(', &(${c_elem}[]){')
165 g.gen_expr(rhs_id)
166 g.writeln('});')
167 }
168 } else {
169 g.gen_expr(child_id)
170 g.writeln(';')
171 }
172 }
173 } else {
174 g.gen_expr(child_id)
175 g.writeln(';')
176 }
177 }
178 .decl_assign {
179 g.gen_decl_assign(node)
180 }
181 .assign, .selector_assign {
182 g.gen_assign(node)
183 }
184 .index_assign {
185 g.gen_index_assign(node)
186 }
187 .return_stmt {
188 g.in_return = true
189 if g.cur_fn_ret is types.Enum {
190 g.expected_enum = g.cur_fn_ret.name
191 }
192 if node.children_count > 0 && g.has_pending_defers() {
193 g.gen_return_with_defers(node)
194 g.expected_enum = ''
195 return
196 }
197 g.gen_all_defers()
198 if node.children_count > 0 {
199 ret_id := g.a.child(&node, 0)
200 if int(ret_id) < 0 || int(ret_id) >= g.a.nodes.len {
201 g.gen_default_return_stmt()
202 g.expected_enum = ''
203 return
204 }
205 ret_node := g.a.nodes[int(ret_id)]
206 if ret_node.kind == .call {
207 fn_n := g.a.child_node(&ret_node, 0)
208 if fn_n.value == 'error' || fn_n.value == 'error_with_code' {
209 if g.cur_fn_ret_is_optional {
210 ct := g.optional_type_name(g.cur_fn_ret)
211 g.write('return ')
212 g.gen_optional_error_from_call(ct, ret_node)
213 g.writeln(';')
214 } else {
215 g.write('return ')
216 g.gen_expr(ret_id)
217 g.writeln(';')
218 }
219 return
220 }
221 }
222 if g.cur_fn_ret_is_optional {
223 ct := g.optional_type_name(g.cur_fn_ret)
224 base := g.cur_fn_ret_base
225 if g.expr_is_optional_literal(ret_id, g.cur_fn_ret) {
226 g.write('return ')
227 g.gen_expr(ret_id)
228 g.writeln(';')
229 return
230 }
231 if base is types.MultiReturn && node.children_count > 1 {
232 base_ct := g.tc.c_type(base)
233 g.write('return (${ct}){.ok = true, .value = (${base_ct}){')
234 for i in 0 .. node.children_count {
235 if i > 0 {
236 g.write(', ')
237 }
238 child_id := g.a.child(&node, i)
239 if i < base.types.len {
240 g.gen_expr_with_expected_type(child_id, base.types[i])
241 } else {
242 g.gen_expr(child_id)
243 }
244 }
245 g.writeln('}};')
246 return
247 }
248 if ret_node.kind == .none_expr {
249 g.writeln('return (${ct}){.ok = false};')
250 return
251 }
252 if base is types.Void {
253 g.writeln('return (${ct}){.ok = false};')
254 } else if base is types.ArrayFixed {
255 // The optional's `.value` is a fixed-array member, which can't be set
256 // in the compound literal; build via a temp + memcpy.
257 g.write('return ({ ${ct} __opt = {.ok = true}; memcpy(__opt.value, ')
258 g.gen_fixed_array_copy_source(ret_id, base)
259 g.writeln(', sizeof(__opt.value)); __opt; });')
260 } else {
261 raw_expr_type := g.tc.resolve_type(ret_id)
262 expr_type := g.usable_expr_type(ret_id)
263 call_ret_type := g.local_fn_call_return_type(ret_id, ret_node)
264 decl_ret_type := g.declared_call_return_type(ret_id)
265 if g.optional_result_matches_base(raw_expr_type, base)
266 || g.optional_result_matches_base(expr_type, base)
267 || g.optional_result_matches_base(call_ret_type, base)
268 || g.optional_result_matches_base(decl_ret_type, base) {
269 g.write('return ')
270 g.gen_expr(ret_id)
271 g.writeln(';')
272 } else {
273 mut expr_value_type := expr_type
274 if expr_type is types.OptionType {
275 expr_value_type = expr_type.base_type
276 } else if expr_type is types.ResultType {
277 expr_value_type = expr_type.base_type
278 }
279 base_ct := g.tc.c_type(base)
280 expr_ct := g.tc.c_type(expr_value_type)
281 struct_init_ct := if ret_node.kind == .struct_init {
282 g.struct_init_c_type_name(ret_node.value)
283 } else {
284 ''
285 }
286 if expr_ct != base_ct && struct_init_ct != base_ct
287 && !g.type_names_match(expr_value_type, base)
288 && !g.expr_is_nil_pointer_payload(ret_id, base)
289 && !g.type_can_wrap_as_sum(expr_value_type, base)
290 && !g.types_numeric_compatible(expr_value_type, base)
291 && !g.call_constructs_type(ret_id, base)
292 && !g.clone_call_matches_base(ret_node, base)
293 && expr_value_type !is types.Primitive
294 && expr_value_type !is types.Unknown {
295 if err_expr := g.optional_error_return_expr(ret_id,
296 expr_value_type, ct)
297 {
298 g.writeln('return ${err_expr};')
299 } else {
300 g.writeln('return (${ct}){.ok = false};')
301 }
302 } else {
303 g.write('return (${ct}){.ok = true, .value = ')
304 if !g.gen_heap_local_address_expr(ret_id, base) {
305 g.gen_expr_with_expected_type(ret_id, base)
306 }
307 g.writeln('};')
308 }
309 }
310 }
311 } else if g.cur_fn_ret is types.MultiReturn {
312 if node.children_count > 1 {
313 ct := g.tc.c_type(g.cur_fn_ret)
314 ret_types := g.cur_fn_ret.types
315 if g.multi_return_types_have_fixed_array(ret_types) {
316 g.gen_multi_return_temp_return(ct, ret_types, node)
317 } else {
318 g.write('return (${ct}){')
319 for i in 0 .. node.children_count {
320 if i > 0 {
321 g.write(', ')
322 }
323 g.gen_expr(g.a.child(&node, i))
324 }
325 g.writeln('};')
326 }
327 } else {
328 expr_type := g.usable_expr_type(ret_id)
329 if expr_type is types.MultiReturn {
330 g.write('return ')
331 g.gen_expr(ret_id)
332 g.writeln(';')
333 } else {
334 ct := g.tc.c_type(g.cur_fn_ret)
335 g.write('return (${ct}){')
336 g.gen_expr(ret_id)
337 g.writeln('};')
338 }
339 }
340 } else if ret_node.kind == .assoc {
341 g.gen_return_assoc(ret_node)
342 } else if g.cur_fn_ret is types.ArrayFixed
343 && g.tc.c_type(g.cur_fn_ret) in g.fixed_array_ret_wrappers {
344 g.write('return ')
345 g.gen_fixed_array_return_wrap(g.cur_fn_ret, ret_id)
346 g.writeln(';')
347 } else {
348 g.write('return ')
349 // Most interface returns are already boxed by the transform pass into
350 // a `(Iface){._typ = N, ._object = ...}` literal, in which case
351 // gen_interface_value_expr is a no-op (the value is already an
352 // interface) and we emit it directly. IError is intentionally left
353 // unboxed by the transform, so box the concrete error here. Never emit
354 // a zeroed `(Iface){0}` — that drops `_typ`/`_object` and makes every
355 // dispatch through the returned interface panic as "not implemented".
356 if g.cur_fn_ret is types.Interface {
357 if !g.gen_interface_value_expr(ret_id, g.cur_fn_ret) {
358 g.gen_expr(ret_id)
359 }
360 } else if !g.gen_heap_local_address_expr(ret_id, g.cur_fn_ret) {
361 g.gen_expr(ret_id)
362 }
363 g.writeln(';')
364 }
365 } else {
366 g.gen_default_return_stmt()
367 }
368 g.expected_enum = ''
369 }
370 .defer_stmt {
371 if node.value == 'function' {
372 if count_name := g.fn_defer_counts[int(id)] {
373 g.writeln('${count_name}++;')
374 }
375 g.fn_defers << id
376 } else {
377 g.defers << g.a.child(&node, 0)
378 }
379 }
380 .for_stmt {
381 g.gen_for(node)
382 }
383 .for_in_stmt {
384 g.gen_for_in(node)
385 }
386 .break_stmt {
387 if node.value.len > 0 {
388 g.writeln('goto ${c_name(node.value)}_break;')
389 } else {
390 g.writeln('break;')
391 }
392 }
393 .continue_stmt {
394 if node.value.len > 0 {
395 g.writeln('goto ${c_name(node.value)}_continue;')
396 } else {
397 g.writeln('continue;')
398 }
399 }
400 .block {
401 g.writeln('{')
402 g.tc.push_scope()
403 defer_start := g.defers.len
404 g.indent++
405 for i in 0 .. node.children_count {
406 g.gen_node(g.a.child(&node, i))
407 }
408 g.gen_defers_from(defer_start)
409 g.trim_defers(defer_start)
410 g.indent--
411 g.tc.pop_scope()
412 g.writeln('}')
413 }
414 .if_expr {
415 g.gen_if(node)
416 }
417 .assert_stmt {
418 g.write('if (!(')
419 g.gen_expr(g.a.child(&node, 0))
420 g.writeln(')) {')
421 g.indent++
422 g.writeln('fprintf(stderr, "assert failed\\n");')
423 g.writeln('exit(1);')
424 g.indent--
425 g.writeln('}')
426 }
427 .goto_stmt {
428 g.writeln('goto ${c_name(node.value)};')
429 }
430 .label_stmt {
431 old_indent := g.indent
432 g.indent = 0
433 g.writeln('${c_name(node.value)}: ;')
434 g.indent = old_indent
435 }
436 .empty, .asm_stmt {}
437 else {
438 // NOTE: match_stmt is intentionally absent — the transformer lowers every
439 // match into an if/else-if chain (see transform.lower_match_stmts), so the
440 // backend never sees one. Match lowering lives in the transformer, not here.
441 eprintln('gen_node: unsupported node kind: ${node.kind}')
442 }
443 }
444}
445
446// has_pending_defers reports whether has pending defers applies in c.
447fn (g &FlatGen) has_pending_defers() bool {
448 return g.defers.len > 0 || g.fn_defers.len > 0
449}
450
451// gen_return_with_defers emits return with defers output for c.
452fn (mut g FlatGen) gen_return_with_defers(node flat.Node) {
453 ret_id := g.a.child(&node, 0)
454 if int(ret_id) < 0 || int(ret_id) >= g.a.nodes.len {
455 g.gen_all_defers()
456 g.gen_default_return_stmt()
457 return
458 }
459 ret_node := g.a.nodes[int(ret_id)]
460 if ret_node.kind == .assoc {
461 tmp := g.tmp_name()
462 g.gen_assoc_return_tmp(ret_node, tmp)
463 g.gen_all_defers()
464 g.writeln('return ${tmp};')
465 return
466 }
467 if g.cur_fn_ret is types.ArrayFixed && g.tc.c_type(g.cur_fn_ret) in g.fixed_array_ret_wrappers {
468 wrapper := fixed_array_ret_wrapper_name(g.tc.c_type(g.cur_fn_ret))
469 tmp := g.tmp_name()
470 g.write('${wrapper} ${tmp} = ')
471 g.gen_fixed_array_return_wrap(g.cur_fn_ret, ret_id)
472 g.writeln(';')
473 g.gen_all_defers()
474 g.writeln('return ${tmp};')
475 return
476 }
477 ct := g.return_c_type()
478 if g.cur_fn_ret is types.MultiReturn && node.children_count > 1 {
479 ret_types := g.cur_fn_ret.types
480 if g.multi_return_types_have_fixed_array(ret_types) {
481 tmp := g.gen_multi_return_temp(ct, ret_types, node)
482 g.gen_all_defers()
483 g.writeln('return ${tmp};')
484 return
485 }
486 }
487 expr := g.return_expr_string(node, ret_id, ret_node, ct)
488 tmp := g.tmp_name()
489 g.writeln('${ct} ${tmp} = ${expr};')
490 g.gen_all_defers()
491 g.writeln('return ${tmp};')
492}
493
494// gen_fixed_array_return_wrap emits a fixed-array return value wrapped in its
495// return-wrapper struct: `({ Wrapper __fa_ret; memcpy(__fa_ret.ret_arr, <expr>,
496// sizeof(...)); __fa_ret; })`. C cannot return raw arrays, so the array is copied
497// into the wrapper's `ret_arr` field and the struct is returned by value.
498fn (mut g FlatGen) gen_fixed_array_return_wrap(ret_type types.Type, ret_id flat.NodeId) {
499 wrapper := fixed_array_ret_wrapper_name(g.tc.c_type(ret_type))
500 g.write('({ ${wrapper} __fa_ret; memcpy(__fa_ret.ret_arr, ')
501 g.gen_fixed_array_copy_source(ret_id, ret_type)
502 g.write(', sizeof(__fa_ret.ret_arr)); __fa_ret; })')
503}
504
505fn (mut g FlatGen) gen_default_return_stmt() {
506 if g.cur_fn_ret_is_optional {
507 ct := g.optional_type_name(g.cur_fn_ret)
508 g.writeln('return (${ct}){.ok = true};')
509 } else if g.cur_fn_name == 'main' {
510 g.writeln('return 0;')
511 } else if g.cur_fn_ret is types.Void {
512 g.writeln('return;')
513 } else {
514 g.write('return ')
515 g.gen_default_value_for_type(g.cur_fn_ret)
516 g.writeln(';')
517 }
518}
519
520// return_c_type supports return c type handling for FlatGen.
521fn (mut g FlatGen) return_c_type() string {
522 if g.cur_fn_ret_is_optional {
523 return g.optional_type_name(g.cur_fn_ret)
524 }
525 return g.tc.c_type(g.cur_fn_ret)
526}
527
528// local_ident_type returns the type of an identifier that is local to the
529// currently emitted function body.
530fn (g &FlatGen) local_ident_type(name string) ?types.Type {
531 if typ := g.current_param_type(name) {
532 return typ
533 }
534 if typ := g.cur_param_types[name] {
535 return typ
536 }
537 if g.cur_scope_has_local_name(name) {
538 if typ := g.tc.cur_scope.lookup(name) {
539 if typ !is types.Void {
540 return typ
541 }
542 }
543 }
544 return none
545}
546
547// heap_local_address_expr returns a heap-copy expression for `&local` when the
548// surrounding return type is a pointer. V permits local address escapes; C needs
549// the local value copied out of the stack frame before returning.
550fn (mut g FlatGen) heap_local_address_expr(ret_id flat.NodeId, expected types.Type) ?string {
551 if int(ret_id) < 0 || int(ret_id) >= g.a.nodes.len {
552 return none
553 }
554 node := g.a.nodes[int(ret_id)]
555 if node.kind != .prefix || node.op != .amp || node.children_count == 0 {
556 return none
557 }
558 if expected !is types.Pointer {
559 return none
560 }
561 ptr := expected as types.Pointer
562 child_id := g.a.child(&node, 0)
563 child := g.a.nodes[int(child_id)]
564 if child.kind != .ident || child.value.len == 0 {
565 return none
566 }
567 local_type := g.local_ident_type(child.value) or { return none }
568 base_type := ptr.base_type
569 local_ct := g.tc.c_type(local_type)
570 base_ct := g.tc.c_type(base_type)
571 if base_ct.len == 0 || base_ct == 'void' {
572 return none
573 }
574 if local_ct != base_ct && !g.type_names_match(local_type, base_type) {
575 return none
576 }
577 local_expr := g.expr_to_string(child_id)
578 return '(${base_ct}*)memdup(&${local_expr}, sizeof(${base_ct}))'
579}
580
581fn (mut g FlatGen) gen_heap_local_address_expr(ret_id flat.NodeId, expected types.Type) bool {
582 if expr := g.heap_local_address_expr(ret_id, expected) {
583 g.write(expr)
584 return true
585 }
586 return false
587}
588
589// return_expr_string supports return expr string handling for FlatGen.
590fn (mut g FlatGen) return_expr_string(node flat.Node, ret_id flat.NodeId, ret_node flat.Node, ct string) string {
591 if ret_node.kind == .call {
592 fn_n := g.a.child_node(&ret_node, 0)
593 if fn_n.value == 'error' || fn_n.value == 'error_with_code' {
594 if g.cur_fn_ret_is_optional {
595 return g.optional_error_from_call_string(ct, ret_node)
596 }
597 return g.expr_to_string(ret_id)
598 }
599 }
600 if g.cur_fn_ret_is_optional {
601 base := g.cur_fn_ret_base
602 if g.expr_is_optional_literal(ret_id, g.cur_fn_ret) {
603 return g.expr_to_string(ret_id)
604 }
605 if base is types.MultiReturn && node.children_count > 1 {
606 base_ct := g.tc.c_type(base)
607 mut parts := []string{cap: int(node.children_count)}
608 for i in 0 .. node.children_count {
609 child_id := g.a.child(&node, i)
610 if i < base.types.len {
611 parts << g.expr_to_string_with_expected_type(child_id, base.types[i])
612 } else {
613 parts << g.expr_to_string(child_id)
614 }
615 }
616 return '(${ct}){.ok = true, .value = (${base_ct}){${parts.join(', ')}}}'
617 }
618 if ret_node.kind == .none_expr {
619 return '(${ct}){.ok = false}'
620 }
621 if base is types.Void {
622 return '(${ct}){.ok = false}'
623 }
624 if base is types.ArrayFixed {
625 // The optional's `.value` is a fixed-array member, which can't be set in a compound
626 // literal; build via a temp + memcpy (mirrors the direct return path) so a deferred
627 // return saves the array value instead of dropping it to `{.ok = false}`.
628 src := g.fixed_array_copy_source_string(ret_id, base)
629 return '({ ${ct} __opt = {.ok = true}; memcpy(__opt.value, ${src}, sizeof(__opt.value)); __opt; })'
630 }
631 raw_expr_type := g.tc.resolve_type(ret_id)
632 expr_type := g.usable_expr_type(ret_id)
633 call_ret_type := g.local_fn_call_return_type(ret_id, ret_node)
634 decl_ret_type := g.declared_call_return_type(ret_id)
635 if g.optional_result_matches_base(raw_expr_type, base)
636 || g.optional_result_matches_base(expr_type, base)
637 || g.optional_result_matches_base(call_ret_type, base)
638 || g.optional_result_matches_base(decl_ret_type, base) {
639 return g.expr_to_string(ret_id)
640 }
641 mut expr_value_type := expr_type
642 if expr_type is types.OptionType {
643 expr_value_type = expr_type.base_type
644 } else if expr_type is types.ResultType {
645 expr_value_type = expr_type.base_type
646 }
647 base_ct := g.tc.c_type(base)
648 expr_ct := g.tc.c_type(expr_value_type)
649 struct_init_ct := if ret_node.kind == .struct_init {
650 g.struct_init_c_type_name(ret_node.value)
651 } else {
652 ''
653 }
654 if expr_ct != base_ct && struct_init_ct != base_ct
655 && !g.type_names_match(expr_value_type, base)
656 && !g.expr_is_nil_pointer_payload(ret_id, base)
657 && !g.type_can_wrap_as_sum(expr_value_type, base)
658 && !g.types_numeric_compatible(expr_value_type, base)
659 && !g.call_constructs_type(ret_id, base) && !g.clone_call_matches_base(ret_node, base)
660 && expr_value_type !is types.Primitive && expr_value_type !is types.Unknown {
661 if err_expr := g.optional_error_return_expr(ret_id, expr_value_type, ct) {
662 return err_expr
663 }
664 return '(${ct}){.ok = false}'
665 }
666 value := g.heap_local_address_expr(ret_id, base) or {
667 g.expr_to_string_with_expected_type(ret_id, base)
668 }
669 return '(${ct}){.ok = true, .value = ${value}}'
670 }
671 if g.cur_fn_ret is types.MultiReturn {
672 if node.children_count > 1 {
673 mut parts := []string{cap: int(node.children_count)}
674 for i in 0 .. node.children_count {
675 parts << g.expr_to_string(g.a.child(&node, i))
676 }
677 return '(${ct}){${parts.join(', ')}}'
678 }
679 expr_type := g.usable_expr_type(ret_id)
680 if expr_type is types.MultiReturn {
681 return g.expr_to_string(ret_id)
682 }
683 return '(${ct}){${g.expr_to_string(ret_id)}}'
684 }
685 if g.cur_fn_ret is types.Interface {
686 // Box the concrete value the same way the direct return path does, so a deferred return
687 // preserves `_typ`/`_object` instead of zeroing the interface.
688 return g.interface_value_to_string(ret_id, g.cur_fn_ret)
689 }
690 return g.heap_local_address_expr(ret_id, g.cur_fn_ret) or { g.expr_to_string(ret_id) }
691}
692
693fn (mut g FlatGen) optional_error_return_expr(ret_id flat.NodeId, expr_type types.Type, ct string) ?string {
694 if !g.type_can_return_as_ierror(expr_type) {
695 return none
696 }
697 err := g.interface_value_to_string(ret_id, types.Type(types.Interface{
698 name: 'IError'
699 }))
700 return '(${ct}){.ok = false, .err = ${err}}'
701}
702
703fn (g &FlatGen) type_can_return_as_ierror(typ types.Type) bool {
704 clean := types.unwrap_pointer(typ)
705 if clean is types.Alias {
706 return g.type_can_return_as_ierror(clean.base_type)
707 }
708 if clean is types.Interface {
709 return clean.name == 'IError' || clean.name.ends_with('.IError')
710 }
711 if clean is types.Struct {
712 if clean.name == 'IError' || clean.name.ends_with('.IError') {
713 return true
714 }
715 if g.tc.named_type_implements_interface(clean.name, 'IError') {
716 return true
717 }
718 return g.struct_type_embeds_error(clean.name)
719 }
720 return false
721}
722
723fn (g &FlatGen) struct_type_embeds_error(type_name string) bool {
724 if type_name == 'Error' || type_name.ends_with('.Error') {
725 return true
726 }
727 for field in g.struct_embedded_fields(type_name) {
728 embedded_type_name := g.embedded_field_type_name(field)
729 if embedded_type_name.len == 0 {
730 continue
731 }
732 if g.struct_type_embeds_error(embedded_type_name) {
733 return true
734 }
735 }
736 return false
737}
738
739fn (g &FlatGen) local_fn_call_return_type(call_id flat.NodeId, call_node flat.Node) types.Type {
740 if call_node.kind != .call || call_node.children_count == 0 {
741 return types.Type(types.void_)
742 }
743 mut node_type := types.Type(types.void_)
744 if name := g.tc.resolved_call_name(call_id) {
745 if ret := g.tc.fn_ret_types[name] {
746 return ret
747 }
748 }
749 if call_node.typ.len > 0 {
750 node_type = g.tc.parse_type(call_node.typ)
751 if node_type is types.OptionType || node_type is types.ResultType {
752 return node_type
753 }
754 }
755 fn_node := g.a.child_node(&call_node, 0)
756 if fn_node.kind == .selector {
757 if ret := g.selector_call_return_type(fn_node) {
758 return ret
759 }
760 return node_type
761 }
762 if fn_node.kind != .ident {
763 return node_type
764 }
765 if ret := g.tc.fn_ret_types[fn_node.value] {
766 return ret
767 }
768 cfn := c_name(fn_node.value)
769 if cfn != fn_node.value {
770 if ret := g.tc.fn_ret_types[cfn] {
771 return ret
772 }
773 }
774 if ret := g.fn_decl_return_type_for_call_name(fn_node.value) {
775 return ret
776 }
777 if typ := g.tc.cur_scope.lookup(fn_node.value) {
778 return fn_type_return_type(typ)
779 }
780 typ := g.tc.resolve_type(g.a.child(&call_node, 0))
781 ret_type := fn_type_return_type(typ)
782 if ret_type !is types.Void {
783 return ret_type
784 }
785 return node_type
786}
787
788// declared_call_return_type returns the *declared* return type of a (possibly
789// lowered) call's target function, preserving type aliases. Method calls are
790// lowered to ident calls (`Recv__method(recv, ...)`) before codegen, and the
791// call node's own `.typ` annotation has aliases resolved away (e.g. `?NodeId`
792// becomes `?int`), which makes the optional C type name appear to differ from
793// the callee's signature. The declared type read from `fn_ret_types`/the fn decl
794// keeps the alias, so propagating `return call()` is recognised as valid.
795fn (g &FlatGen) declared_call_return_type(call_id flat.NodeId) types.Type {
796 if int(call_id) < 0 {
797 return types.Type(types.void_)
798 }
799 call_node := g.a.nodes[int(call_id)]
800 if call_node.kind != .call || call_node.children_count == 0 {
801 return types.Type(types.void_)
802 }
803 fn_node := g.a.child_node(&call_node, 0)
804 if fn_node.kind == .selector {
805 if ret := g.selector_call_return_type(fn_node) {
806 return ret
807 }
808 } else if fn_node.kind == .ident {
809 if ret := g.tc.fn_ret_types[fn_node.value] {
810 return ret
811 }
812 cfn := c_name(fn_node.value)
813 if cfn != fn_node.value {
814 if ret := g.tc.fn_ret_types[cfn] {
815 return ret
816 }
817 }
818 if ret := g.fn_decl_return_type_for_call_name(fn_node.value) {
819 return ret
820 }
821 }
822 // Indirect call through an fn-pointer value (local var, param, or struct field
823 // like `h.f()`): the target isn't a declared function/method, so resolve its type
824 // and read the fn type's return. Unwrap alias (`type MakeArr = fn () [2]string`)
825 // and pointer layers first. Lets fixed-array-returning callbacks unwrap `.ret_arr`
826 // at the call site whether reached through a local, a param, or a struct field.
827 mut callee_t := types.unwrap_pointer(g.tc.resolve_type(g.a.child(&call_node, 0)))
828 for callee_t is types.Alias {
829 callee_t = types.unwrap_pointer((callee_t as types.Alias).base_type)
830 }
831 if callee_t is types.FnType {
832 return callee_t.return_type
833 }
834 return types.Type(types.void_)
835}
836
837fn (g &FlatGen) selector_call_return_type(fn_node flat.Node) ?types.Type {
838 if fn_node.children_count == 0 || fn_node.value.len == 0 {
839 return none
840 }
841 base_id := g.a.child(&fn_node, 0)
842 base_node := g.a.nodes[int(base_id)]
843 // A selector whose base names a type or an imported module is not a receiver method but a
844 // static method (`Type.make()`) or import-qualified function (`mod.make()`); the base ident
845 // has no value type, so resolve it the same way gen_call does and read the declared return
846 // type. Without this a fixed-array such call's `_v_ret_*` wrapper is never unwrapped.
847 if base_node.kind == .ident && base_node.value.len > 0 {
848 base_is_local := g.tc.cur_scope.lookup(base_node.value) or { types.Type(types.void_) } !is types.Void
849 if !base_is_local {
850 if static_fn := g.static_method_fn_name(base_node.value, fn_node.value) {
851 if ret := g.tc.fn_ret_types[static_fn] {
852 return ret
853 }
854 }
855 if mod := g.import_alias_module(base_node.value) {
856 if ret := g.tc.fn_ret_types['${mod}.${fn_node.value}'] {
857 return ret
858 }
859 }
860 }
861 }
862 base_type0 := g.usable_expr_type(base_id)
863 base_type := if base_type0 is types.Unknown || base_type0 is types.Void {
864 g.tc.resolve_type(base_id)
865 } else {
866 base_type0
867 }
868 clean_type := types.unwrap_pointer(base_type)
869 if fn_node.value == 'clone' && (clean_type is types.Array || clean_type is types.Map) {
870 return base_type
871 }
872 mut receiver_name := clean_type.name()
873 if clean_type is types.Struct {
874 receiver_name = clean_type.name
875 } else if clean_type is types.Interface {
876 receiver_name = clean_type.name
877 } else if clean_type is types.Alias {
878 receiver_name = clean_type.name
879 }
880 if receiver_name.len == 0 {
881 return none
882 }
883 if decl_key := g.interface_method_signature_key(receiver_name, fn_node.value) {
884 if ret := g.tc.fn_ret_types[decl_key] {
885 return ret
886 }
887 }
888 method_name := '${receiver_name}.${fn_node.value}'
889 if ret := g.tc.fn_ret_types[method_name] {
890 return ret
891 }
892 if receiver_name.contains('.') {
893 short_name := receiver_name.all_after_last('.')
894 short_method := '${short_name}.${fn_node.value}'
895 if ret := g.tc.fn_ret_types[short_method] {
896 return ret
897 }
898 }
899 return none
900}
901
902fn (g &FlatGen) fn_decl_return_type_for_call_name(name string) ?types.Type {
903 if name.len == 0 {
904 return none
905 }
906 // Indexed in collect_gen_info (register_fn_decl_ret_type); previously this scanned
907 // every AST node per call (O(n^2)) and re-mangled each decl name with c_name.
908 if rt := g.fn_decl_ret_types[name] {
909 return rt
910 }
911 cname := c_name(name)
912 if cname != name {
913 if rt := g.fn_decl_ret_types[cname] {
914 return rt
915 }
916 }
917 return none
918}
919
920fn fn_type_return_type(typ types.Type) types.Type {
921 if typ is types.FnType {
922 return typ.return_type
923 }
924 if typ is types.Alias {
925 return fn_type_return_type(typ.base_type)
926 }
927 return types.Type(types.void_)
928}
929
930// optional_error_from_call_string converts optional error from call string data for c.
931fn (mut g FlatGen) optional_error_from_call_string(ct string, node flat.Node) string {
932 orig := g.sb
933 orig_line_start := g.line_start
934 g.sb = strings.new_builder(64)
935 g.line_start = true
936 g.gen_optional_error_from_call(ct, node)
937 result := g.sb.str()
938 g.sb = orig
939 g.line_start = orig_line_start
940 return result
941}
942
943// expr_really_returns_optional supports expr really returns optional handling for FlatGen.
944fn (g &FlatGen) expr_really_returns_optional(id flat.NodeId) bool {
945 if int(id) < 0 {
946 return false
947 }
948 node := g.a.nodes[int(id)]
949 if node.kind == .none_expr {
950 return true
951 }
952 if node.kind == .call {
953 if fname := g.tc.resolved_call_name(id) {
954 ret_type := g.tc.fn_ret_types[fname] or { return false }
955 return ret_type is types.OptionType || ret_type is types.ResultType
956 }
957 }
958 return false
959}
960
961// optional_result_matches_base supports optional result matches base handling for FlatGen.
962fn (g &FlatGen) optional_result_matches_base(expr_type types.Type, base types.Type) bool {
963 mut inner := types.Type(types.void_)
964 if expr_type is types.OptionType {
965 inner = expr_type.base_type
966 } else if expr_type is types.ResultType {
967 inner = expr_type.base_type
968 } else {
969 return false
970 }
971 if g.type_names_match(inner, base) {
972 return true
973 }
974 // Aliases keep their declared name (e.g. `[]NodeId`) while `resolve_type` collapses
975 // them to the underlying type (`[]int`), so a structural name comparison spuriously
976 // fails. What actually matters for `return <call>;` is whether the C optional type
977 // emitted for the call equals the one this function returns — compare those instead.
978 return g.option_c_name_for_base(inner) == g.option_c_name_for_base(base)
979}
980
981fn (g &FlatGen) clone_call_matches_base(call_node flat.Node, base types.Type) bool {
982 mut node := call_node
983 for node.kind in [.expr_stmt, .paren] && node.children_count > 0 {
984 node = *g.a.child_node(&node, 0)
985 }
986 if node.kind != .call || node.children_count == 0 {
987 return false
988 }
989 fn_node := g.a.child_node(&node, 0)
990 if fn_node.kind == .ident {
991 base_ct := g.tc.c_type(types.unwrap_pointer(base))
992 return (fn_node.value == 'array__clone' && base_ct == 'Array')
993 || (fn_node.value == 'map__clone' && base_ct == 'map')
994 }
995 if fn_node.kind != .selector || fn_node.value != 'clone' || fn_node.children_count == 0 {
996 return false
997 }
998 base_id := g.a.child(fn_node, 0)
999 receiver_type0 := g.usable_expr_type(base_id)
1000 receiver_type := if receiver_type0 is types.Unknown || receiver_type0 is types.Void {
1001 g.tc.resolve_type(base_id)
1002 } else {
1003 receiver_type0
1004 }
1005 clean_receiver := types.unwrap_pointer(receiver_type)
1006 clean_base := types.unwrap_pointer(base)
1007 if g.type_names_match(clean_receiver, clean_base) {
1008 return true
1009 }
1010 receiver_ct0 := g.tc.c_type(clean_receiver)
1011 base_ct0 := g.tc.c_type(clean_base)
1012 if receiver_ct0.len > 0 && base_ct0.len > 0 && receiver_ct0 == base_ct0 {
1013 return true
1014 }
1015 receiver := if clean_receiver is types.Alias {
1016 clean_receiver.base_type
1017 } else {
1018 clean_receiver
1019 }
1020 expected := if clean_base is types.Alias {
1021 clean_base.base_type
1022 } else {
1023 clean_base
1024 }
1025 if expected is types.Array || expected is types.Map {
1026 receiver_ct := g.tc.c_type(receiver)
1027 expected_ct := g.tc.c_type(expected)
1028 if receiver_ct.len > 0 && receiver_ct == expected_ct {
1029 return true
1030 }
1031 }
1032 if receiver is types.Array && expected is types.Array {
1033 return g.type_names_match(receiver.elem_type, expected.elem_type)
1034 }
1035 if receiver is types.Map && expected is types.Map {
1036 return g.type_names_match(receiver.key_type, expected.key_type)
1037 && g.type_names_match(receiver.value_type, expected.value_type)
1038 }
1039 return false
1040}
1041
1042// option_c_name_for_base returns the C optional type name used for a `?base`/`!base`
1043// value, mirroring optional_type_name without its side effects.
1044fn (g &FlatGen) option_c_name_for_base(base types.Type) string {
1045 if base is types.Void {
1046 return 'Optional'
1047 }
1048 inner_ct := g.tc.c_type(base)
1049 if inner_ct == 'int' {
1050 return 'Optional'
1051 }
1052 return 'Optional_' + inner_ct.replace('*', 'ptr').replace(' ', '_')
1053}
1054
1055fn (g &FlatGen) expr_is_nil_pointer_payload(id flat.NodeId, base types.Type) bool {
1056 if !g.type_accepts_nil_pointer(base) {
1057 return false
1058 }
1059 return g.expr_is_nil_value(id)
1060}
1061
1062fn (g &FlatGen) type_accepts_nil_pointer(typ types.Type) bool {
1063 if typ is types.Pointer {
1064 return true
1065 }
1066 if typ is types.Alias {
1067 return g.type_accepts_nil_pointer(typ.base_type)
1068 }
1069 return false
1070}
1071
1072fn (g &FlatGen) expr_is_nil_value(id flat.NodeId) bool {
1073 if int(id) < 0 || int(id) >= g.a.nodes.len {
1074 return false
1075 }
1076 node := g.a.nodes[int(id)]
1077 match node.kind {
1078 .nil_literal {
1079 return true
1080 }
1081 .expr_stmt {
1082 if node.children_count == 0 {
1083 return false
1084 }
1085 return g.expr_is_nil_value(g.a.child(&node, 0))
1086 }
1087 .block {
1088 if node.children_count == 0 {
1089 return false
1090 }
1091 return g.expr_is_nil_value(g.a.child(&node, node.children_count - 1))
1092 }
1093 .cast_expr, .as_expr {
1094 if node.children_count == 0 {
1095 return false
1096 }
1097 return g.expr_is_nil_value(g.a.child(&node, 0))
1098 }
1099 else {
1100 return false
1101 }
1102 }
1103}
1104
1105// usable_expr_type supports usable expr type handling for FlatGen.
1106fn (g &FlatGen) usable_expr_type(id flat.NodeId) types.Type {
1107 if int(id) >= 0 && int(id) < g.a.nodes.len {
1108 node := g.a.nodes[int(id)]
1109 if node.kind in [.expr_stmt, .paren] && node.children_count > 0 {
1110 return g.usable_expr_type(g.a.child(&node, 0))
1111 }
1112 if node.kind == .ident {
1113 if typ := g.cur_param_types[node.value] {
1114 return typ
1115 }
1116 if typ := g.tc.cur_scope.lookup(node.value) {
1117 if typ !is types.Void {
1118 return typ
1119 }
1120 }
1121 }
1122 if node.kind == .index && node.children_count > 0 {
1123 base_type0 := g.usable_expr_type(g.a.child(&node, 0))
1124 base_type := types.unwrap_pointer(base_type0)
1125 is_slice := node.value == 'range'
1126 || (node.children_count > 1 && g.a.child_node(&node, 1).kind == .range)
1127 if is_slice {
1128 if base_type is types.Array {
1129 return base_type
1130 }
1131 if base_type is types.ArrayFixed {
1132 return types.Type(types.Array{
1133 elem_type: base_type.elem_type
1134 })
1135 }
1136 if base_type is types.String {
1137 return types.Type(types.String{})
1138 }
1139 }
1140 if base_type is types.Array {
1141 return base_type.elem_type
1142 }
1143 if base_type is types.ArrayFixed {
1144 return base_type.elem_type
1145 }
1146 if base_type is types.Map {
1147 return base_type.value_type
1148 }
1149 if base_type is types.String {
1150 return types.Type(types.u8_)
1151 }
1152 }
1153 if node.kind == .call && node.children_count > 0 {
1154 fn_node := g.a.child_node(&node, 0)
1155 if fn_node.kind == .ident {
1156 if typ := g.tc.cur_scope.lookup(fn_node.value) {
1157 ret := fn_type_return_type(typ)
1158 if ret !is types.Unknown && ret !is types.Void {
1159 return ret
1160 }
1161 }
1162 if ret := g.fn_decl_return_type_for_call_name(fn_node.value) {
1163 if ret !is types.Unknown && ret !is types.Void {
1164 return ret
1165 }
1166 }
1167 }
1168 }
1169 }
1170 if typ := g.tc.expr_type(id) {
1171 if typ !is types.Unknown && typ !is types.Void {
1172 return typ
1173 }
1174 }
1175 return g.tc.resolve_type(id)
1176}
1177
1178// type_names_match returns type names match data for FlatGen.
1179fn (g &FlatGen) type_names_match(a types.Type, b types.Type) bool {
1180 a_name := a.name()
1181 b_name := b.name()
1182 if a_name.len == 0 || b_name.len == 0 {
1183 return false
1184 }
1185 if a_name == b_name {
1186 return true
1187 }
1188 return a_name.all_after_last('.') == b_name.all_after_last('.')
1189}
1190
1191// type_can_wrap_as_sum returns type can wrap as sum data for FlatGen.
1192fn (g &FlatGen) type_can_wrap_as_sum(actual types.Type, expected types.Type) bool {
1193 expected0 := if expected is types.Alias { expected.base_type } else { expected }
1194 if expected0 !is types.SumType {
1195 return false
1196 }
1197 actual0 := if actual is types.Alias { actual.base_type } else { actual }
1198 if actual0 is types.SumType {
1199 return false
1200 }
1201 sum_type := expected0 as types.SumType
1202 sum_name := g.resolve_sum_name(sum_type.name)
1203 variant := g.resolve_variant(sum_name, actual0.name())
1204 variants := g.tc.sum_types[sum_name] or { return false }
1205 return variant in variants
1206}
1207
1208// types_numeric_compatible supports types numeric compatible handling for FlatGen.
1209fn (g &FlatGen) types_numeric_compatible(a types.Type, b types.Type) bool {
1210 _ = g
1211 return (a.is_integer() || a.is_float()) && (b.is_integer() || b.is_float())
1212}
1213
1214// call_constructs_type updates call constructs type state for FlatGen.
1215fn (g &FlatGen) call_constructs_type(id flat.NodeId, target types.Type) bool {
1216 if int(id) < 0 {
1217 return false
1218 }
1219 node := g.a.nodes[int(id)]
1220 if node.kind != .call || node.children_count == 0 {
1221 return false
1222 }
1223 fn_node := g.a.child_node(&node, 0)
1224 if fn_node.kind != .ident {
1225 return false
1226 }
1227 target_name := target.name()
1228 if target_name.len == 0 {
1229 return false
1230 }
1231 short_target := target_name.all_after_last('.')
1232 return fn_node.value == target_name || fn_node.value == short_target
1233}
1234
1235// is_runtime_array_flags_stmt reports whether is runtime array flags stmt applies in c.
1236fn (g &FlatGen) is_runtime_array_flags_stmt(id flat.NodeId) bool {
1237 if int(id) < 0 {
1238 return false
1239 }
1240 node := g.a.nodes[int(id)]
1241 if node.kind != .call || node.children_count == 0 {
1242 return false
1243 }
1244 fn_node := g.a.child_node(&node, 0)
1245 if fn_node.kind != .selector || fn_node.value !in ['set', 'clear']
1246 || fn_node.children_count == 0 {
1247 return false
1248 }
1249 flags_node := g.a.child_node(fn_node, 0)
1250 if flags_node.kind != .selector || flags_node.value != 'flags' || flags_node.children_count == 0 {
1251 return false
1252 }
1253 owner_id := g.a.child(flags_node, 0)
1254 owner_type := types.unwrap_pointer(g.tc.resolve_type(owner_id))
1255 return owner_type is types.Array || owner_type.name() == 'strings.Builder'
1256}
1257
1258fn (g &FlatGen) multi_return_expr_type(id flat.NodeId) ?types.MultiReturn {
1259 rtype := g.tc.resolve_type(id)
1260 if rtype is types.MultiReturn {
1261 return rtype
1262 }
1263 utype := g.usable_expr_type(id)
1264 if utype is types.MultiReturn {
1265 return utype
1266 }
1267 return none
1268}
1269
1270// gen_decl_assign emits decl assign output for c.
1271fn (mut g FlatGen) gen_decl_assign(node flat.Node) {
1272 if node.children_count >= 3 {
1273 if _ := g.multi_return_expr_type(g.a.child(&node, 1)) {
1274 g.gen_multi_return_decl(node)
1275 return
1276 }
1277 }
1278 mut bad_decl_child := node.children_count % 2 == 1
1279 for i in 0 .. node.children_count {
1280 if int(g.a.child(&node, i)) < 0 {
1281 bad_decl_child = true
1282 }
1283 }
1284 if bad_decl_child {
1285 mut parts := []string{}
1286 for i in 0 .. node.children_count {
1287 child_id := g.a.child(&node, i)
1288 if int(child_id) < 0 {
1289 parts << '${i}:empty'
1290 } else {
1291 child := g.a.nodes[int(child_id)]
1292 parts << '${i}:${child.kind}:${child.value}:${child.typ}'
1293 }
1294 }
1295 panic('internal error: odd decl_assign in ${g.cur_fn_name}: count=${node.children_count} typ=${node.typ} value=${node.value} children=${parts.join('|')}')
1296 }
1297 decl_prefix := if node.value == 'static' { 'static ' } else { '' }
1298 mut i := 0
1299 for i < node.children_count {
1300 lhs_id := g.a.child(&node, i)
1301 rhs_id := g.a.child(&node, i + 1)
1302 lhs := g.a.nodes[int(lhs_id)]
1303 rhs := g.a.nodes[int(rhs_id)]
1304 lhs_is_defer_capture := lhs.kind == .ident && lhs.value in g.defer_capture_types
1305 if rhs.kind == .array_literal {
1306 rhs_v_type := if rhs.typ.len > 0 {
1307 g.tc.parse_type(rhs.typ)
1308 } else {
1309 g.tc.resolve_type(rhs_id)
1310 }
1311 if fixed := array_fixed_type(rhs_v_type) {
1312 lhs_str := g.decl_lhs_str(lhs_id)
1313 if !lhs_is_defer_capture {
1314 c_elem, dims := g.fixed_array_decl_parts(fixed)
1315 g.writeln('${decl_prefix}${c_elem} ${lhs_str}${dims};')
1316 }
1317 g.gen_fixed_array_copy_from_node(lhs_str, rhs_id, fixed)
1318 if lhs.kind == .ident {
1319 g.tc.cur_scope.insert(lhs.value, rhs_v_type)
1320 }
1321 i += 2
1322 continue
1323 }
1324 elem_type := if rhs.children_count > 0 {
1325 g.tc.resolve_type(g.a.child(&rhs, 0))
1326 } else {
1327 types.Type(types.int_)
1328 }
1329 if !lhs_is_defer_capture {
1330 g.write('${decl_prefix}Array ')
1331 }
1332 g.gen_decl_lhs(lhs_id)
1333 g.write(' = ')
1334 g.gen_array_literal_value(rhs, elem_type)
1335 g.writeln(';')
1336 if lhs.kind == .ident {
1337 g.tc.cur_scope.insert(lhs.value, types.Type(types.Array{
1338 elem_type: elem_type
1339 }))
1340 }
1341 } else if rhs.kind == .or_expr {
1342 g.gen_decl_or_expr(lhs, rhs)
1343 } else if rhs.kind == .array_init {
1344 raw_init_type := g.tc.parse_type(rhs.value)
1345 init_type := raw_init_type
1346 if init_type is types.ArrayFixed {
1347 g.gen_fixed_array_zero_init_decl(lhs_id, init_type, decl_prefix,
1348 lhs_is_defer_capture)
1349 if lhs.kind == .ident {
1350 g.tc.cur_scope.insert(lhs.value, raw_init_type)
1351 }
1352 } else {
1353 c_elem := g.sizeof_target(rhs.value)
1354 mut init_len := '0'
1355 mut init_cap := '0'
1356 mut init_val := ''
1357 for j in 0 .. rhs.children_count {
1358 child := g.a.child_node(&rhs, j)
1359 if child.kind == .field_init {
1360 if child.value == 'len' {
1361 init_len = g.expr_to_string(g.a.child(child, 0))
1362 } else if child.value == 'cap' {
1363 init_cap = g.expr_to_string(g.a.child(child, 0))
1364 } else if child.value == 'init' {
1365 init_val = g.expr_to_string(g.a.child(child, 0))
1366 }
1367 }
1368 }
1369 lhs_str := g.decl_lhs_str(lhs_id)
1370 if lhs_is_defer_capture {
1371 g.writeln('${lhs_str} = array_new(sizeof(${c_elem}), ${init_len}, ${init_cap});')
1372 } else {
1373 g.writeln('${decl_prefix}Array ${lhs_str} = array_new(sizeof(${c_elem}), ${init_len}, ${init_cap});')
1374 }
1375 if init_val.len > 0 {
1376 g.writeln('for (int _ai = 0; _ai < ${lhs_str}.len; _ai++) ((${c_elem}*)${lhs_str}.data)[_ai] = ${init_val};')
1377 }
1378 if lhs.kind == .ident {
1379 g.tc.cur_scope.insert(lhs.value, types.Type(types.Array{
1380 elem_type: init_type
1381 }))
1382 }
1383 }
1384 } else if init_type := g.fixed_array_zero_init_block_type(rhs) {
1385 g.gen_fixed_array_zero_init_decl(lhs_id, init_type, decl_prefix, lhs_is_defer_capture)
1386 if lhs.kind == .ident {
1387 g.tc.cur_scope.insert(lhs.value, init_type)
1388 }
1389 } else if rhs.kind == .map_init {
1390 v_type := g.tc.resolve_type(rhs_id)
1391 c_typ := g.tc.c_type(v_type)
1392 if !lhs_is_defer_capture {
1393 g.write('${decl_prefix}${c_typ} ')
1394 }
1395 g.gen_decl_lhs(lhs_id)
1396 g.write(' = ')
1397 g.gen_expr_with_expected_type(rhs_id, v_type)
1398 g.writeln(';')
1399 if lhs.kind == .ident {
1400 g.tc.cur_scope.insert(lhs.value, v_type)
1401 }
1402 if rhs.children_count > 0 {
1403 if v_type is types.Map {
1404 c_key := g.tc.c_type(v_type.key_type)
1405 c_val := g.tc.c_type(v_type.value_type)
1406 for j := 0; j < rhs.children_count; j += 2 {
1407 g.write('map__set(&')
1408 g.gen_decl_lhs(lhs_id)
1409 g.write(', &(${c_key}[]){')
1410 g.gen_expr(g.a.child(&rhs, j))
1411 g.write('}, &(${c_val}[]){')
1412 g.gen_expr(g.a.child(&rhs, j + 1))
1413 g.writeln('});')
1414 }
1415 }
1416 }
1417 } else {
1418 mut v_type := if node.typ.len > 0 {
1419 decl_type := g.tc.parse_type(node.typ)
1420 if decl_type is types.Struct && decl_type.name == 'array' {
1421 g.usable_expr_type(rhs_id)
1422 } else if decl_annotation_is_unusable(decl_type, node.typ) {
1423 rhs_type := g.decl_rhs_fallback_type(rhs_id, rhs)
1424 if rhs_type is types.Unknown {
1425 types.Type(decl_type)
1426 } else {
1427 rhs_type
1428 }
1429 } else {
1430 decl_type
1431 }
1432 } else if rhs.kind == .if_expr {
1433 g.if_expr_type(&rhs)
1434 } else {
1435 g.usable_expr_type(rhs_id)
1436 }
1437 if fixed := array_fixed_type(v_type) {
1438 if g.fixed_array_decl_is_unusable(fixed) {
1439 rhs_type := g.decl_rhs_fallback_type(rhs_id, rhs)
1440 if rhs_type !is types.Unknown {
1441 v_type = rhs_type
1442 }
1443 }
1444 }
1445 if fixed := array_fixed_type(v_type) {
1446 lhs_str := g.decl_lhs_str(lhs_id)
1447 if !lhs_is_defer_capture {
1448 c_elem, dims := g.fixed_array_decl_parts(fixed)
1449 g.writeln('${decl_prefix}${c_elem} ${lhs_str}${dims};')
1450 }
1451 g.gen_fixed_array_copy_from_node(lhs_str, rhs_id, fixed)
1452 if lhs.kind == .ident {
1453 g.tc.cur_scope.insert(lhs.value, v_type)
1454 }
1455 i += 2
1456 continue
1457 }
1458 ct0 := g.tc.c_type(v_type)
1459 ct := if v_type is types.OptionType || v_type is types.ResultType {
1460 g.optional_type_name(v_type)
1461 } else {
1462 ct0
1463 }
1464 if ct.starts_with('fn_ptr:') {
1465 fp_name := g.resolve_fn_ptr_type(ct)
1466 if !lhs_is_defer_capture {
1467 g.write('${decl_prefix}${fp_name} ')
1468 }
1469 } else {
1470 if !lhs_is_defer_capture {
1471 g.write('${decl_prefix}${ct} ')
1472 }
1473 }
1474 g.gen_decl_lhs(lhs_id)
1475 g.write(' = ')
1476 g.gen_decl_init_expr(rhs_id, rhs, v_type, ct, !lhs_is_defer_capture)
1477 g.writeln(';')
1478 if lhs.kind == .ident {
1479 g.tc.cur_scope.insert(lhs.value, v_type)
1480 }
1481 }
1482 i += 2
1483 }
1484}
1485
1486fn (g &FlatGen) decl_rhs_fallback_type(rhs_id flat.NodeId, rhs flat.Node) types.Type {
1487 if rhs.kind == .index && rhs.value.len > 0 {
1488 index_type := g.tc.parse_type(rhs.value)
1489 if !decl_annotation_is_unusable(index_type, rhs.value) {
1490 return index_type
1491 }
1492 }
1493 if rhs.typ.len > 0 {
1494 rhs_type := g.tc.parse_type(rhs.typ)
1495 if !decl_annotation_is_unusable(rhs_type, rhs.typ) {
1496 return rhs_type
1497 }
1498 }
1499 if rhs.kind == .index && rhs.children_count > 0 {
1500 base_type := types.unwrap_pointer(g.usable_expr_type(g.a.child(&rhs, 0)))
1501 if base_type is types.Array {
1502 return base_type.elem_type
1503 }
1504 if base_type is types.ArrayFixed {
1505 return base_type.elem_type
1506 }
1507 if base_type is types.Map {
1508 return base_type.value_type
1509 }
1510 }
1511 return g.usable_expr_type(rhs_id)
1512}
1513
1514fn (mut g FlatGen) fixed_array_decl_is_unusable(typ types.ArrayFixed) bool {
1515 c_elem, _ := g.fixed_array_decl_parts(typ)
1516 return c_elem == 'void'
1517}
1518
1519fn decl_annotation_is_unusable(typ types.Type, raw string) bool {
1520 if typ is types.ArrayFixed && fixed_array_contains_void(typ) {
1521 return true
1522 }
1523 clean_raw := raw.replace(' ', '')
1524 return clean_raw == 'void' || clean_raw.starts_with('void[') || clean_raw.ends_with(']void')
1525 || clean_raw.contains(']void[')
1526}
1527
1528fn fixed_array_contains_void(typ types.Type) bool {
1529 if typ is types.ArrayFixed {
1530 return fixed_array_contains_void(typ.elem_type)
1531 }
1532 return typ is types.Void
1533}
1534
1535fn (mut g FlatGen) gen_fixed_array_zero_init_decl(lhs_id flat.NodeId, init_type types.ArrayFixed, decl_prefix string, lhs_is_defer_capture bool) {
1536 c_elem, dims := g.fixed_array_decl_parts(init_type)
1537 lhs_str := g.decl_lhs_str(lhs_id)
1538 if g.fixed_array_len_is_zero(init_type) {
1539 if !lhs_is_defer_capture {
1540 g.writeln('${decl_prefix}${c_elem} ${lhs_str}${dims};')
1541 }
1542 } else if lhs_is_defer_capture {
1543 g.writeln('memset(${lhs_str}, 0, sizeof(${lhs_str}));')
1544 } else {
1545 g.writeln('${decl_prefix}${c_elem} ${lhs_str}${dims} = {0};')
1546 }
1547}
1548
1549fn (mut g FlatGen) fixed_array_zero_init_block_type(node flat.Node) ?types.ArrayFixed {
1550 if node.kind != .block || node.children_count != 1 {
1551 return none
1552 }
1553 stmt_id := g.a.child(&node, 0)
1554 if int(stmt_id) < 0 {
1555 return none
1556 }
1557 stmt := g.a.nodes[int(stmt_id)]
1558 expr_id := if stmt.kind == .expr_stmt && stmt.children_count == 1 {
1559 g.a.child(&stmt, 0)
1560 } else {
1561 stmt_id
1562 }
1563 if int(expr_id) < 0 {
1564 return none
1565 }
1566 expr := g.a.nodes[int(expr_id)]
1567 if expr.kind != .array_init || expr.children_count != 0 {
1568 return none
1569 }
1570 typ := g.tc.parse_type(expr.value)
1571 if typ is types.ArrayFixed {
1572 return typ
1573 }
1574 return none
1575}
1576
1577// gen_decl_init_expr emits decl init expr output for c.
1578fn (mut g FlatGen) gen_decl_init_expr(rhs_id flat.NodeId, rhs flat.Node, v_type types.Type, c_type string, is_declaration bool) {
1579 if g.is_json_decode_call_expr(rhs_id) {
1580 g.write('(${c_type}){0}')
1581 return
1582 }
1583 if rhs.kind == .int_literal && rhs.value == '0' && g.is_aggregate_zero_init_type(v_type, c_type) {
1584 if is_declaration {
1585 g.write('{0}')
1586 } else {
1587 g.write('(${c_type}){0}')
1588 }
1589 return
1590 }
1591 g.gen_expr_with_expected_type(rhs_id, v_type)
1592}
1593
1594// gen_multi_return_decl emits multi return decl output for c.
1595fn (g &FlatGen) multi_return_types_have_fixed_array(ret_types []types.Type) bool {
1596 for typ in ret_types {
1597 if _ := array_fixed_type(typ) {
1598 return true
1599 }
1600 }
1601 return false
1602}
1603
1604fn (mut g FlatGen) gen_multi_return_temp(ct string, ret_types []types.Type, node flat.Node) string {
1605 tmp := g.tmp_name()
1606 g.writeln('${ct} ${tmp};')
1607 for i in 0 .. node.children_count {
1608 field := '${tmp}.arg${i}'
1609 child_id := g.a.child(&node, i)
1610 if i < ret_types.len {
1611 if fixed := array_fixed_type(ret_types[i]) {
1612 g.gen_fixed_array_copy_from_node(field, child_id, fixed)
1613 continue
1614 }
1615 g.write('${field} = ')
1616 g.gen_expr_with_expected_type(child_id, ret_types[i])
1617 g.writeln(';')
1618 continue
1619 }
1620 g.write('${field} = ')
1621 g.gen_expr(child_id)
1622 g.writeln(';')
1623 }
1624 return tmp
1625}
1626
1627fn (mut g FlatGen) gen_multi_return_temp_return(ct string, ret_types []types.Type, node flat.Node) {
1628 tmp := g.gen_multi_return_temp(ct, ret_types, node)
1629 g.writeln('return ${tmp};')
1630}
1631
1632fn (mut g FlatGen) gen_fixed_array_copy_from_node(dst string, rhs_id flat.NodeId, fixed types.ArrayFixed) {
1633 g.write('memmove(${dst}, ')
1634 g.gen_fixed_array_data_arg(rhs_id, fixed)
1635 g.writeln(', sizeof(${dst}));')
1636}
1637
1638fn (mut g FlatGen) gen_multi_return_decl(node flat.Node) {
1639 rhs_id := g.a.child(&node, 1)
1640 rhs_multi := g.multi_return_expr_type(rhs_id) or { return }
1641 rhs_type := types.Type(rhs_multi)
1642 ct := g.tc.c_type(rhs_type)
1643 tmp := g.tmp_name()
1644 g.write('${ct} ${tmp} = ')
1645 g.gen_expr_with_expected_type(rhs_id, rhs_type)
1646 g.writeln(';')
1647 num_lhs := node.children_count - 1
1648 multi_types := rhs_multi.types.clone()
1649 for j in 0 .. num_lhs {
1650 lhs_idx := if j == 0 { 0 } else { j + 1 }
1651 lhs_id := g.a.child(&node, lhs_idx)
1652 lhs := g.a.nodes[int(lhs_id)]
1653 if lhs.kind == .ident && lhs.value == '_' {
1654 continue
1655 }
1656 field_type := if j < multi_types.len {
1657 g.tc.c_type(multi_types[j])
1658 } else {
1659 'int'
1660 }
1661 lhs_name := c_name(lhs.value)
1662 if j < multi_types.len {
1663 if fixed := array_fixed_type(multi_types[j]) {
1664 c_elem, dims := g.fixed_array_decl_parts(fixed)
1665 g.writeln('${c_elem} ${lhs_name}${dims};')
1666 g.writeln('memmove(${lhs_name}, ${tmp}.arg${j}, sizeof(${lhs_name}));')
1667 if lhs.kind == .ident {
1668 g.tc.cur_scope.insert(lhs.value, multi_types[j])
1669 }
1670 continue
1671 }
1672 }
1673 g.writeln('${field_type} ${lhs_name} = ${tmp}.arg${j};')
1674 if lhs.kind == .ident {
1675 inner := if j < multi_types.len {
1676 multi_types[j]
1677 } else {
1678 types.Type(types.int_)
1679 }
1680 g.tc.cur_scope.insert(lhs.value, inner)
1681 }
1682 }
1683}
1684
1685// gen_assign emits assign output for c.
1686fn (mut g FlatGen) gen_assign(node flat.Node) {
1687 if node.children_count >= 3 {
1688 rhs_id := g.a.child(&node, 1)
1689 if _ := g.multi_return_expr_type(rhs_id) {
1690 g.gen_multi_return_assign(node)
1691 return
1692 }
1693 }
1694 mut i := 0
1695 for i < node.children_count {
1696 lhs := g.a.nodes[int(g.a.child(&node, i))]
1697 if lhs.kind == .ident && lhs.value == '_' {
1698 g.write('(void)(')
1699 g.gen_expr(g.a.child(&node, i + 1))
1700 g.writeln(');')
1701 } else if node.op == .left_shift_assign && lhs.kind == .ident
1702 && node.value in ['push', 'push_many'] {
1703 if node.value == 'push_many' {
1704 g.gen_array_push_many_stmt(g.a.child(&node, i), g.a.child(&node, i + 1))
1705 } else if node.value == 'push' {
1706 lhs_id := g.a.child(&node, i)
1707 rhs_id := g.a.child(&node, i + 1)
1708 lhs_arr_type := types.unwrap_pointer(g.usable_expr_type(lhs_id))
1709 if lhs_arr := array_like_type(lhs_arr_type) {
1710 push_rhs_clean := types.unwrap_pointer(g.tc.resolve_type(rhs_id))
1711 if rhs_arr := array_like_type(push_rhs_clean) {
1712 if g.tc.c_type(lhs_arr.elem_type) !in ['array', 'Array']
1713 && g.tc.c_type(lhs_arr.elem_type) == g.tc.c_type(rhs_arr.elem_type) {
1714 g.gen_array_push_many_stmt(lhs_id, rhs_id)
1715 i += 2
1716 continue
1717 }
1718 } else if rhs_fixed := array_fixed_type(push_rhs_clean) {
1719 if g.tc.c_type(lhs_arr.elem_type) !in ['array', 'Array']
1720 && g.tc.c_type(lhs_arr.elem_type) == g.tc.c_type(rhs_fixed.elem_type) {
1721 g.gen_array_push_many_stmt(lhs_id, rhs_id)
1722 i += 2
1723 continue
1724 }
1725 }
1726 lhs_is_ptr := g.tc.resolve_type(g.a.child(&node, i)) is types.Pointer
1727 amp := if lhs_is_ptr { '' } else { '&' }
1728 c_elem := g.tc.c_type(lhs_arr.elem_type)
1729 g.write('array_push(${amp}${c_name(lhs.value)}, &(${c_elem}[]){')
1730 g.gen_expr_with_expected_type(g.a.child(&node, i + 1), lhs_arr.elem_type)
1731 g.writeln('});')
1732 } else {
1733 // Array appends are annotated by the transformer; an un-annotated
1734 // `<<=` here is the integer bit-shift-assign operator.
1735 g.gen_expr(g.a.child(&node, i))
1736 g.write(' <<= ')
1737 g.gen_expr(g.a.child(&node, i + 1))
1738 g.writeln(';')
1739 }
1740 } else {
1741 g.gen_expr(g.a.child(&node, i))
1742 g.write(' <<= ')
1743 g.gen_expr(g.a.child(&node, i + 1))
1744 g.writeln(';')
1745 }
1746 } else {
1747 rhs_id := g.a.child(&node, i + 1)
1748 rhs_node := g.a.nodes[int(rhs_id)]
1749 if rhs_node.kind == .or_expr {
1750 g.gen_assign_or_expr(node, i, rhs_node)
1751 i += 2
1752 continue
1753 }
1754 lhs_id := g.a.child(&node, i)
1755 if rhs_node.kind == .array_literal {
1756 lhs_type := types.unwrap_pointer(g.tc.resolve_type(lhs_id))
1757 if lhs_type is types.ArrayFixed {
1758 // A fixed-array field/var can't be `=`-assigned an array literal (which
1759 // lowers to a dynamic `Array`); memcpy the element bytes instead.
1760 g.write('memcpy(')
1761 g.gen_expr(lhs_id)
1762 g.write(', ')
1763 g.gen_fixed_array_data_arg(rhs_id, lhs_type)
1764 g.write(', sizeof(')
1765 g.gen_expr(lhs_id)
1766 g.writeln('));')
1767 i += 2
1768 continue
1769 }
1770 elem_type := if rhs_node.children_count > 0 {
1771 g.tc.resolve_type(g.a.child(&rhs_node, 0))
1772 } else if lhs_arr := array_like_type(lhs_type) {
1773 lhs_arr.elem_type
1774 } else {
1775 types.Type(types.int_)
1776 }
1777 g.gen_expr(g.a.child(&node, i))
1778 g.write(' = ')
1779 g.gen_array_literal_value(rhs_node, elem_type)
1780 g.writeln(';')
1781 } else {
1782 lhs_type := g.usable_expr_type(lhs_id)
1783 rhs_type := g.usable_expr_type(rhs_id)
1784 if node.op == .assign {
1785 if lhs_fixed := array_fixed_type(lhs_type) {
1786 if _ := array_fixed_type(rhs_type) {
1787 dst := g.expr_to_string(lhs_id)
1788 g.writeln('memmove(${dst}, ${g.expr_to_string(rhs_id)}, sizeof(${dst}));')
1789 i += 2
1790 continue
1791 } else if rhs_node.kind == .array_init || rhs_node.kind == .array_literal
1792 || rhs_node.kind == .postfix {
1793 dst := g.expr_to_string(lhs_id)
1794 g.write('memmove(${dst}, ')
1795 g.gen_fixed_array_data_arg(rhs_id, lhs_fixed)
1796 g.writeln(', sizeof(${dst}));')
1797 i += 2
1798 continue
1799 }
1800 }
1801 }
1802 if node.op == .plus_assign && (lhs_type is types.String || rhs_type is types.String) {
1803 g.gen_expr(g.a.child(&node, i))
1804 g.write(' = string__plus(')
1805 g.gen_expr(g.a.child(&node, i))
1806 g.write(', ')
1807 g.gen_expr(rhs_id)
1808 g.writeln(');')
1809 i += 2
1810 continue
1811 }
1812 if method_name := g.assign_struct_operator_method(lhs_type, node.op) {
1813 g.gen_expr(lhs_id)
1814 g.write(' = ${c_name(method_name)}(')
1815 g.gen_expr(lhs_id)
1816 g.write(', ')
1817 g.gen_expr(rhs_id)
1818 g.writeln(');')
1819 i += 2
1820 continue
1821 }
1822 if lhs_type is types.Enum {
1823 g.expected_enum = lhs_type.name
1824 }
1825 if g.assign_lhs_needs_deref(g.a.child(&node, i), lhs_type, rhs_type, node.op) {
1826 g.write('*')
1827 }
1828 g.gen_expr(g.a.child(&node, i))
1829 g.write(' ${g.op_str(node.op)} ')
1830 if _ := fn_type_from(lhs_type) {
1831 if c_abi_fn := g.assign_lhs_c_abi_fn_ptr_type(lhs_id) {
1832 if g.gen_callback_fn_value_for_field_c_abi(rhs_id, lhs_type, c_abi_fn) {
1833 g.writeln(';')
1834 g.expected_enum = ''
1835 i += 2
1836 continue
1837 }
1838 }
1839 g.gen_expr_with_expected_type(rhs_id, lhs_type)
1840 } else {
1841 g.gen_expr(rhs_id)
1842 }
1843 g.writeln(';')
1844 g.expected_enum = ''
1845 }
1846 }
1847 i += 2
1848 }
1849}
1850
1851fn (g &FlatGen) assign_lhs_c_abi_fn_ptr_type(lhs_id flat.NodeId) ?string {
1852 if int(lhs_id) < 0 || int(lhs_id) >= g.a.nodes.len {
1853 return none
1854 }
1855 lhs := g.a.nodes[int(lhs_id)]
1856 if lhs.kind != .selector || lhs.children_count == 0 || lhs.value.len == 0 {
1857 return none
1858 }
1859 base_id := g.a.child(&lhs, 0)
1860 base_type := types.unwrap_pointer(g.usable_expr_type(base_id))
1861 mut clean := base_type
1862 if base_type is types.Alias {
1863 clean = base_type.base_type
1864 }
1865 if clean is types.Struct {
1866 return g.struct_field_c_abi_fn_ptr_type(clean.name, lhs.value)
1867 }
1868 return none
1869}
1870
1871fn (g &FlatGen) assign_struct_operator_method(lhs_type types.Type, op flat.Op) ?string {
1872 clean := types.unwrap_pointer(lhs_type)
1873 if clean !is types.Struct {
1874 return none
1875 }
1876 op_symbol := assign_struct_operator_symbol(op) or { return none }
1877 method_name := '${clean.name()}.${op_symbol}'
1878 if method_name in g.tc.fn_param_types || method_name in g.tc.fn_ret_types {
1879 return method_name
1880 }
1881 cmethod_name := c_name(method_name)
1882 if cmethod_name in g.tc.fn_param_types || cmethod_name in g.tc.fn_ret_types {
1883 return cmethod_name
1884 }
1885 return none
1886}
1887
1888fn assign_struct_operator_symbol(op flat.Op) ?string {
1889 match op {
1890 .plus_assign { return '+' }
1891 .minus_assign { return '-' }
1892 .mul_assign { return '*' }
1893 .div_assign { return '/' }
1894 .mod_assign { return '%' }
1895 else {}
1896 }
1897
1898 return none
1899}
1900
1901// assign_lhs_needs_deref supports assign lhs needs deref handling for FlatGen.
1902fn (g &FlatGen) assign_lhs_needs_deref(lhs_id flat.NodeId, lhs_type types.Type, rhs_type types.Type, op flat.Op) bool {
1903 if op != .assign {
1904 return false
1905 }
1906 lhs := g.a.nodes[int(lhs_id)]
1907 if lhs.kind != .ident {
1908 return false
1909 }
1910 if lhs_type is types.Pointer {
1911 return lhs_type.base_type.name() == rhs_type.name()
1912 }
1913 return false
1914}
1915
1916// gen_multi_return_assign emits multi return assign output for c.
1917fn (mut g FlatGen) gen_multi_return_assign(node flat.Node) {
1918 rhs_id := g.a.child(&node, 1)
1919 rhs_multi := g.multi_return_expr_type(rhs_id) or { return }
1920 rhs_type := types.Type(rhs_multi)
1921 ct := g.tc.c_type(rhs_type)
1922 tmp := g.tmp_name()
1923 g.write('${ct} ${tmp} = ')
1924 g.gen_expr_with_expected_type(rhs_id, rhs_type)
1925 g.writeln(';')
1926 num_lhs := node.children_count - 1
1927 multi_types := rhs_multi.types.clone()
1928 for j in 0 .. num_lhs {
1929 lhs_idx := if j == 0 { 0 } else { j + 1 }
1930 lhs_id := g.a.child(&node, lhs_idx)
1931 lhs := g.a.nodes[int(lhs_id)]
1932 if lhs.kind == .ident && lhs.value == '_' {
1933 continue
1934 }
1935 if j < multi_types.len {
1936 if _ := array_fixed_type(multi_types[j]) {
1937 dst := g.expr_to_string(lhs_id)
1938 g.writeln('memmove(${dst}, ${tmp}.arg${j}, sizeof(${dst}));')
1939 continue
1940 }
1941 }
1942 gen_expr_lvalue(mut g, lhs_id)
1943 g.writeln(' = ${tmp}.arg${j};')
1944 }
1945}
1946
1947// gen_decl_lhs emits decl lhs output for c.
1948fn (mut g FlatGen) gen_decl_lhs(id flat.NodeId) {
1949 node := g.a.nodes[int(id)]
1950 if node.kind == .ident {
1951 if node.value == '_' {
1952 g.write('__discard_${int(id)}')
1953 return
1954 }
1955 g.write(c_name(node.value))
1956 } else {
1957 g.gen_expr(id)
1958 }
1959}
1960
1961// decl_lhs_str supports decl lhs str handling for FlatGen.
1962fn (mut g FlatGen) decl_lhs_str(id flat.NodeId) string {
1963 node := g.a.nodes[int(id)]
1964 if node.kind == .ident {
1965 if node.value == '_' {
1966 return '__discard_${int(id)}'
1967 }
1968 return c_name(node.value)
1969 }
1970 return g.expr_to_string(id)
1971}
1972
1973// gen_assign_or_expr emits assign or expr output for c.
1974fn (mut g FlatGen) gen_assign_or_expr(node flat.Node, lhs_idx int, or_node flat.Node) {
1975 expr_id := g.a.child(&or_node, 0)
1976 or_body_id := g.a.child(&or_node, 1)
1977 or_body := g.a.nodes[int(or_body_id)]
1978 expr_node := g.a.nodes[int(expr_id)]
1979 tmp := g.tmp_name()
1980 expr_type := g.or_expr_source_type(expr_id, expr_node)
1981 opt_ct := g.optional_type_name(expr_type)
1982 g.write('${opt_ct} ${tmp} = ')
1983 g.gen_expr(expr_id)
1984 g.writeln(';')
1985 g.writeln('if (${tmp}.ok) {')
1986 g.indent++
1987 g.gen_expr(g.a.child(&node, lhs_idx))
1988 g.writeln(' = ${tmp}.value;')
1989 g.indent--
1990 g.writeln('} else {')
1991 g.tc.push_scope()
1992 g.tc.cur_scope.insert('err', types.Type(types.Struct{
1993 name: 'IError'
1994 }))
1995 g.indent++
1996 g.writeln('IError err = ${tmp}.err;')
1997 if or_node.value == '!' || or_node.value == '?' {
1998 if g.cur_fn_ret_is_optional {
1999 fn_opt_ct := g.optional_type_name(g.cur_fn_ret)
2000 g.writeln('return (${fn_opt_ct}){.ok = false, .err = err};')
2001 } else {
2002 g.writeln('panic(IError__str(err));')
2003 }
2004 } else {
2005 for j in 0 .. or_body.children_count {
2006 child_id := g.a.child(&or_body, j)
2007 g.gen_node(child_id)
2008 }
2009 }
2010 g.indent--
2011 g.tc.pop_scope()
2012 g.writeln('}')
2013}
2014
2015// gen_decl_or_expr emits decl or expr output for c.
2016fn (mut g FlatGen) gen_decl_or_expr(lhs flat.Node, or_node flat.Node) {
2017 expr_id := g.a.child(&or_node, 0)
2018 or_body_id := g.a.child(&or_node, 1)
2019 or_body := g.a.nodes[int(or_body_id)]
2020 expr_node := g.a.nodes[int(expr_id)]
2021 if expr_node.kind == .index {
2022 base_type := g.tc.resolve_type(g.a.child(&expr_node, 0))
2023 clean := types.unwrap_pointer(base_type)
2024 if clean is types.Map {
2025 g.gen_decl_or_map_index(lhs, expr_node, clean, or_body)
2026 return
2027 }
2028 }
2029 tmp := g.tmp_name()
2030 expr_type := g.or_expr_source_type(expr_id, expr_node)
2031 opt_ct := g.optional_type_name(expr_type)
2032 val_ct, val_type := g.optional_value_ct(expr_type)
2033 g.tc.cur_scope.insert(lhs.value, val_type)
2034 g.write('${opt_ct} ${tmp} = ')
2035 if g.is_json_decode_call_expr(expr_id) {
2036 g.write('(${opt_ct}){0}')
2037 } else {
2038 g.gen_expr_with_expected_type(expr_id, expr_type)
2039 }
2040 g.writeln(';')
2041 g.writeln('${val_ct} ${c_name(lhs.value)};')
2042 g.writeln('if (${tmp}.ok) {')
2043 g.indent++
2044 g.writeln('${c_name(lhs.value)} = ${tmp}.value;')
2045 g.indent--
2046 g.writeln('} else {')
2047 g.tc.push_scope()
2048 g.tc.cur_scope.insert('err', types.Type(types.Struct{
2049 name: 'IError'
2050 }))
2051 g.indent++
2052 g.writeln('IError err = ${tmp}.err;')
2053 if or_node.value == '!' || or_node.value == '?' {
2054 if g.cur_fn_ret_is_optional {
2055 fn_opt_ct := g.optional_type_name(g.cur_fn_ret)
2056 g.writeln('return (${fn_opt_ct}){.ok = false, .err = err};')
2057 } else {
2058 g.writeln('panic(IError__str(err));')
2059 }
2060 } else if or_body.children_count > 0 {
2061 for i in 0 .. or_body.children_count {
2062 child_id := g.a.child(&or_body, i)
2063 child := g.a.nodes[int(child_id)]
2064 if i == or_body.children_count - 1 && child.kind == .expr_stmt {
2065 inner := g.a.child_node(&child, 0)
2066 if inner.kind == .call && g.is_noreturn_call(inner) {
2067 g.gen_node(child_id)
2068 } else {
2069 g.write('${c_name(lhs.value)} = ')
2070 g.gen_expr(g.a.child(&child, 0))
2071 g.writeln(';')
2072 }
2073 } else {
2074 g.gen_node(child_id)
2075 }
2076 }
2077 }
2078 g.indent--
2079 g.tc.pop_scope()
2080 g.writeln('}')
2081}
2082
2083// gen_decl_or_map_index emits decl or map index output for c.
2084fn (mut g FlatGen) gen_decl_or_map_index(lhs flat.Node, expr_node flat.Node, m types.Map, or_body flat.Node) {
2085 tmp := g.tmp_name()
2086 c_val := g.tc.c_type(m.value_type)
2087 c_key := g.tc.c_type(m.key_type)
2088 g.tc.cur_scope.insert(lhs.value, m.value_type)
2089 g.write('void* ${tmp} = map__get_check(&')
2090 g.gen_expr(g.a.child(&expr_node, 0))
2091 g.write(', &(${c_key}[]){')
2092 g.gen_expr(g.a.child(&expr_node, 1))
2093 g.writeln('});')
2094 g.writeln('${c_val} ${c_name(lhs.value)};')
2095 g.writeln('if (${tmp}) {')
2096 g.indent++
2097 g.writeln('${c_name(lhs.value)} = *(${c_val}*)${tmp};')
2098 g.indent--
2099 g.writeln('} else {')
2100 g.indent++
2101 if or_body.children_count > 0 {
2102 for i in 0 .. or_body.children_count {
2103 child_id := g.a.child(&or_body, i)
2104 child := g.a.nodes[int(child_id)]
2105 if i == or_body.children_count - 1 && child.kind == .expr_stmt {
2106 inner := g.a.child_node(&child, 0)
2107 if inner.kind == .call && g.is_noreturn_call(inner) {
2108 g.gen_node(child_id)
2109 } else {
2110 g.write('${c_name(lhs.value)} = ')
2111 g.gen_expr(g.a.child(&child, 0))
2112 g.writeln(';')
2113 }
2114 } else {
2115 g.gen_node(child_id)
2116 }
2117 }
2118 }
2119 g.indent--
2120 g.writeln('}')
2121}
2122
2123fn (g &FlatGen) is_json_decode_call_expr(id flat.NodeId) bool {
2124 if int(id) < 0 || int(id) >= g.a.nodes.len {
2125 return false
2126 }
2127 node := g.a.nodes[int(id)]
2128 if node.kind == .call && node.children_count > 0 {
2129 target := g.call_target_name(g.a.child(&node, 0))
2130 if target in ['decode', 'json.decode', 'json2.decode'] {
2131 return true
2132 }
2133 if g.call_has_selector_name(g.a.child(&node, 0), 'decode') {
2134 return true
2135 }
2136 }
2137 for i in 0 .. node.children_count {
2138 if g.is_json_decode_call_expr(g.a.child(&node, i)) {
2139 return true
2140 }
2141 }
2142 return false
2143}
2144
2145// is_noreturn_call reports whether is noreturn call applies in c.
2146fn (g &FlatGen) is_noreturn_call(node &flat.Node) bool {
2147 if node.kind != .call || node.children_count == 0 {
2148 return false
2149 }
2150 fn_node := g.a.child_node(node, 0)
2151 return fn_node.value in ['panic', 'exit']
2152}
2153
2154// tmp_name supports tmp name handling for FlatGen.
2155fn (mut g FlatGen) tmp_name() string {
2156 g.tmp_count++
2157 return '_t${g.tmp_count}'
2158}
2159
2160// gen_or_expr emits or expr output for c.
2161fn (mut g FlatGen) gen_or_expr(node flat.Node) {
2162 expr_id := g.a.child(&node, 0)
2163 or_body_id := g.a.child(&node, 1)
2164 or_body := g.a.nodes[int(or_body_id)]
2165 expr_node := g.a.nodes[int(expr_id)]
2166 if expr_node.kind == .index {
2167 base_type := g.tc.resolve_type(g.a.child(&expr_node, 0))
2168 clean := types.unwrap_pointer(base_type)
2169 if clean is types.Map {
2170 g.gen_or_map_index(expr_node, clean, or_body)
2171 return
2172 }
2173 }
2174 tmp := g.tmp_name()
2175 expr_type := g.or_expr_source_type(expr_id, expr_node)
2176 opt_ct := g.optional_type_name(expr_type)
2177 val_ct, val_type := g.optional_value_ct(expr_type)
2178 val := g.tmp_name()
2179 g.write('({${opt_ct} ${tmp} = ')
2180 g.gen_expr_with_expected_type(expr_id, expr_type)
2181 g.write('; ${val_ct} ${val}; if (${tmp}.ok) { ${val} = ${tmp}.value; } else { IError err = ${tmp}.err; (void)err; ')
2182 // Bind `err` (IError) in a *temporary* cgen scope so the or-body's own string
2183 // interpolations and selector accesses resolve `err`'s type correctly (without this
2184 // an `${err}` inside the or-body falls back to `int__str(err)`). The scope is popped
2185 // afterwards so an outer local named `err` keeps its real type — e.g.
2186 // `err := 1; _ := maybe() or { 0 }; println('${err}')` must still see `err` as int.
2187 g.tc.push_scope()
2188 g.tc.cur_scope.insert('err', g.tc.parse_type('IError'))
2189 g.gen_or_body_value(or_body, val, val_type)
2190 g.tc.pop_scope()
2191 g.write(' } ${val};})')
2192}
2193
2194fn (g &FlatGen) or_expr_source_type(expr_id flat.NodeId, expr_node flat.Node) types.Type {
2195 if expr_node.kind == .call {
2196 decl_type := g.declared_call_return_type(expr_id)
2197 if decl_type is types.OptionType || decl_type is types.ResultType {
2198 return decl_type
2199 }
2200 local_type := g.local_fn_call_return_type(expr_id, expr_node)
2201 if local_type is types.OptionType || local_type is types.ResultType {
2202 return local_type
2203 }
2204 }
2205 return g.tc.resolve_type(expr_id)
2206}
2207
2208// gen_or_body emits or body output for c.
2209fn (mut g FlatGen) gen_or_body(or_body flat.Node) {
2210 if or_body.children_count == 1 {
2211 last_id := g.a.child(&or_body, or_body.children_count - 1)
2212 last := g.a.nodes[int(last_id)]
2213 if last.kind == .expr_stmt {
2214 g.gen_expr(g.a.child(&last, 0))
2215 } else {
2216 g.gen_expr(last_id)
2217 }
2218 } else {
2219 g.write('({')
2220 for i in 0 .. or_body.children_count {
2221 child_id := g.a.child(&or_body, i)
2222 child := g.a.nodes[int(child_id)]
2223 if i == or_body.children_count - 1 && child.kind == .expr_stmt {
2224 g.gen_expr(g.a.child(&child, 0))
2225 g.write(';')
2226 } else {
2227 g.gen_node(child_id)
2228 }
2229 }
2230 g.write('})')
2231 }
2232}
2233
2234fn (mut g FlatGen) gen_or_body_value(or_body flat.Node, value_name string, value_type types.Type) {
2235 for i in 0 .. or_body.children_count {
2236 child_id := g.a.child(&or_body, i)
2237 child := g.a.nodes[int(child_id)]
2238 is_last := i == or_body.children_count - 1
2239 if is_last && child.kind == .expr_stmt {
2240 expr_id := g.a.child(&child, 0)
2241 if g.expr_is_error_call(expr_id) && g.cur_fn_ret_is_optional {
2242 fn_opt_ct := g.optional_type_name(g.cur_fn_ret)
2243 g.write('return ')
2244 g.gen_optional_error_from_call(fn_opt_ct, g.a.nodes[int(expr_id)])
2245 g.write(';')
2246 } else if g.tc.resolve_type(expr_id) is types.Void {
2247 // A diverging/void or-body tail (e.g. `panic(..)`/`exit(..)`) yields no
2248 // value; emit it as a bare statement instead of assigning void.
2249 g.gen_expr(expr_id)
2250 g.write(';')
2251 } else {
2252 g.write('${value_name} = ')
2253 g.gen_expr_with_expected_type(expr_id, value_type)
2254 g.write(';')
2255 }
2256 } else {
2257 g.gen_node(child_id)
2258 }
2259 }
2260}
2261
2262fn (g &FlatGen) expr_is_error_call(id flat.NodeId) bool {
2263 if int(id) < 0 || int(id) >= g.a.nodes.len {
2264 return false
2265 }
2266 node := g.a.nodes[int(id)]
2267 if node.kind != .call || node.children_count == 0 {
2268 return false
2269 }
2270 fn_node := g.a.child_node(&node, 0)
2271 return fn_node.value == 'error' || fn_node.value == 'error_with_code'
2272}
2273
2274// gen_or_map_index emits or map index output for c.
2275fn (mut g FlatGen) gen_or_map_index(expr_node flat.Node, m types.Map, or_body flat.Node) {
2276 tmp := g.tmp_name()
2277 c_val := g.tc.c_type(m.value_type)
2278 c_key := g.tc.c_type(m.key_type)
2279 val := g.tmp_name()
2280 g.write('({void* ${tmp} = map__get_check(&')
2281 g.gen_expr(g.a.child(&expr_node, 0))
2282 g.write(', &(${c_key}[]){')
2283 g.gen_expr(g.a.child(&expr_node, 1))
2284 g.write('}); ${c_val} ${val}; if (${tmp}) { ${val} = *(${c_val}*)${tmp}; } else { ')
2285 g.gen_or_body_value(or_body, val, m.value_type)
2286 g.write(' } ${val};})')
2287}
2288
2289// gen_or_expr_stmt emits or expr stmt output for c.
2290fn (mut g FlatGen) gen_or_expr_stmt(node flat.Node) {
2291 expr_id := g.a.child(&node, 0)
2292 or_body_id := g.a.child(&node, 1)
2293 or_body := g.a.nodes[int(or_body_id)]
2294 tmp := g.tmp_name()
2295 expr_type := g.tc.resolve_type(expr_id)
2296 opt_ct := g.optional_type_name(expr_type)
2297 g.writeln('${opt_ct} ${tmp} = ')
2298 g.gen_expr_with_expected_type(expr_id, expr_type)
2299 g.writeln(';')
2300 g.writeln('if (!${tmp}.ok) {')
2301 g.tc.push_scope()
2302 g.tc.cur_scope.insert('err', types.Type(types.Struct{
2303 name: 'IError'
2304 }))
2305 g.indent++
2306 g.writeln('IError err = ${tmp}.err;')
2307 if node.value == '!' || node.value == '?' {
2308 if g.cur_fn_ret_is_optional {
2309 fn_opt_ct := g.optional_type_name(g.cur_fn_ret)
2310 g.writeln('return (${fn_opt_ct}){.ok = false, .err = err};')
2311 } else {
2312 g.writeln('panic(IError__str(err));')
2313 }
2314 } else {
2315 for i in 0 .. or_body.children_count {
2316 g.gen_node(g.a.child(&or_body, i))
2317 }
2318 }
2319 g.indent--
2320 g.tc.pop_scope()
2321 g.writeln('}')
2322}
2323