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