v4 / vlib / v / gen / c / array.v
2954 lines · 2829 sloc · 96.45 KB · 82e947b1b9e56b6ae3f376c0c2880c4351fff749
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
3module c
4
5import strings
6import v.ast
7
8fn array_init_orig_expr(expr ast.Expr) ast.Expr {
9 return match expr {
10 ast.CTempVar { expr.orig }
11 else { expr }
12 }
13}
14
15fn (g &Gen) can_keep_array_init_expr_inline(expr ast.Expr) bool {
16 return match expr {
17 ast.BoolLiteral, ast.CharLiteral, ast.EnumVal, ast.FloatLiteral, ast.IntegerLiteral,
18 ast.None, ast.OffsetOf, ast.SizeOf, ast.StringLiteral, ast.TypeNode {
19 true
20 }
21 ast.Ident {
22 expr.or_expr.kind == .absent
23 }
24 ast.ParExpr {
25 g.can_keep_array_init_expr_inline(expr.expr)
26 }
27 ast.SelectorExpr {
28 expr.or_block.kind == .absent && g.can_keep_array_init_expr_inline(expr.expr)
29 }
30 else {
31 false
32 }
33 }
34}
35
36fn (mut g Gen) array_init_expr_needs_gc_root(expr ast.Expr, expr_type ast.Type) bool {
37 if g.pref.gc_mode !in [.boehm_full, .boehm_incr, .boehm_full_opt, .boehm_incr_opt] {
38 return false
39 }
40 if g.inside_const || g.inside_global_decl || g.inside_cinit {
41 return false
42 }
43 if expr is ast.CTempVar || g.can_keep_array_init_expr_inline(expr) || expr.is_lvalue() {
44 return false
45 }
46 resolved_expr_type := g.unwrap_generic(g.recheck_concrete_type(expr_type))
47 return resolved_expr_type != 0 && g.contains_ptr(resolved_expr_type)
48}
49
50fn (mut g Gen) prepare_array_init_exprs(exprs []ast.Expr, expr_types []ast.Type, default_type ast.Type) []ast.Expr {
51 mut needs_order_preserved := false
52 for i, expr in exprs {
53 expr_type := if expr_types.len > i && expr_types[i] != 0 {
54 expr_types[i]
55 } else {
56 default_type
57 }
58 if g.need_tmp_var_in_expr(expr) || g.array_init_expr_needs_gc_root(expr, expr_type) {
59 needs_order_preserved = true
60 break
61 }
62 }
63 if !needs_order_preserved {
64 return exprs
65 }
66 stmt_str := if g.inside_ternary > 0 {
67 g.go_before_ternary().trim_space()
68 } else {
69 g.go_before_last_stmt().trim_space()
70 }
71 g.empty_line = true
72 mut prepared := []ast.Expr{cap: exprs.len}
73 for i, expr in exprs {
74 expr_type := if expr_types.len > i && expr_types[i] != 0 {
75 expr_types[i]
76 } else {
77 default_type
78 }
79 if g.can_keep_array_init_expr_inline(expr)
80 && !g.array_init_expr_needs_gc_root(expr, expr_type) {
81 prepared << expr
82 continue
83 }
84 mut tmp := g.new_ctemp_var(expr, expr_type)
85 g.gen_ctemp_var(mut tmp)
86 prepared << ast.Expr(tmp)
87 }
88 if stmt_str.ends_with('return') {
89 g.write(stmt_str)
90 g.write(' ')
91 } else {
92 g.write(stmt_str)
93 if g.pref.is_vlines && stmt_str.contains('#line') {
94 g.writeln('')
95 }
96 }
97 return prepared
98}
99
100fn (mut g Gen) array_init(node ast.ArrayInit, var_name string) {
101 base_array_typ := if node.generic_typ != 0 { node.generic_typ } else { node.typ }
102 base_elem_typ := if node.generic_elem_type != 0 {
103 node.generic_elem_type
104 } else {
105 node.elem_type
106 }
107 mut array_type := g.unwrap(g.recheck_concrete_type(base_array_typ))
108 mut array_styp := ''
109 elem_type := g.unwrap(g.recheck_concrete_type(base_elem_typ))
110 mut expr_types := node.expr_types.clone()
111 mut shared_styp := '' // only needed for shared &[]{...}
112 is_amp := g.is_amp
113 g.is_amp = false
114 if is_amp {
115 g.go_back(1) // delete the `&` already generated in `prefix_expr()
116 }
117 if g.is_shared {
118 shared_styp = g.styp(array_type.typ.set_flag(.shared_f))
119 g.writeln('(${shared_styp}*)__dup_shared_array(&(${shared_styp}){.mtx = {0}, .val =')
120 } else if is_amp {
121 array_styp = g.styp(array_type.typ)
122 if node.is_fixed && !g.inside_global_decl {
123 line := g.go_before_last_stmt()
124 tmp_var := g.new_tmp_var()
125 g.write('${array_styp} ${tmp_var} = ')
126 g.fixed_array_init(node, array_type, var_name, is_amp)
127 g.writeln(';')
128 g.write(line)
129
130 g.write('builtin__memdup((void*)&${tmp_var}, sizeof(${array_styp}))')
131 } else {
132 g.write('HEAP(${array_styp}, ')
133 }
134 }
135 len := node.exprs.len
136 mut resolved_elem_type := elem_type
137 if g.cur_concrete_types.len > 0 && len > 0 && !node.is_fixed {
138 expr_types = []ast.Type{cap: len}
139 mut inferred_elem_type := ast.void_type
140 for expr in node.exprs {
141 default_expr_type := if inferred_elem_type != ast.void_type {
142 inferred_elem_type
143 } else {
144 base_elem_typ
145 }
146 mut resolved_expr_type := ast.void_type
147 if expr is ast.Ident {
148 resolved_expr_type = g.resolved_scope_var_type(expr)
149 }
150 if resolved_expr_type == ast.void_type {
151 resolved_expr_type = g.unwrap_generic(g.recheck_concrete_type(g.resolved_expr_type(expr,
152 default_expr_type)))
153 }
154 expr_types << resolved_expr_type
155 if inferred_elem_type == ast.void_type && resolved_expr_type != 0 {
156 inferred_elem_type = if expr.is_auto_deref_var() && resolved_expr_type.is_ptr() {
157 ast.mktyp(resolved_expr_type.deref())
158 } else {
159 ast.mktyp(resolved_expr_type)
160 }
161 }
162 }
163 if inferred_elem_type != ast.void_type {
164 resolved_elem_type = g.unwrap(inferred_elem_type)
165 }
166 }
167 if g.cur_concrete_types.len > 0 && array_type.unaliased_sym.kind == .array
168 && resolved_elem_type.typ != 0 {
169 current_elem_type :=
170 g.unwrap_generic(g.recheck_concrete_type(g.table.value_type(array_type.typ)))
171 if current_elem_type != resolved_elem_type.typ {
172 resolved_array_type := g.table.find_or_register_array(resolved_elem_type.typ)
173 array_type = g.unwrap(resolved_array_type)
174 if g.is_shared {
175 shared_styp = g.styp(array_type.typ.set_flag(.shared_f))
176 } else if is_amp {
177 array_styp = g.styp(array_type.typ)
178 }
179 }
180 }
181 $if trace_ci_fixes ? {
182 if g.cur_fn != unsafe { nil } && g.cur_fn.name == 'arrays.group_by' && len > 0 {
183 eprintln('cgen array ${g.cur_fn.name} elem=${g.table.type_to_str(resolved_elem_type.typ)} exprs=${expr_types.map(g.table.type_to_str(it))} cur=${g.cur_concrete_types.map(g.table.type_to_str(it))}')
184 }
185 }
186 elem_sym := g.table.sym(g.unwrap_generic(resolved_elem_type.typ))
187 if node.is_fixed || array_type.unaliased_sym.kind == .array_fixed {
188 if !(is_amp && !g.inside_global_decl) {
189 g.fixed_array_init(node, array_type, var_name, is_amp)
190 if is_amp {
191 g.write(')')
192 }
193 }
194 } else if node.has_update_expr {
195 // `[...base, e1, e2]`
196 // Clone `base` with the proper depth so that nested arrays / strings are
197 // deep-copied (matches `a := b` clone semantics). The runtime helper then
198 // just appends the trailing elements onto the already-owned clone.
199 elem_styp := g.styp(resolved_elem_type.typ)
200 array_depth := g.get_array_depth(resolved_elem_type.typ)
201 is_iface_or_sumtype := elem_sym.kind in [.sum_type, .interface]
202 g.write('builtin__new_array_from_array_and_c_array(builtin__array_clone_static_to_depth(')
203 g.expr(node.update_expr)
204 g.write(', ${array_depth}), ${len}, sizeof(${elem_styp}), ')
205 if len == 0 {
206 g.write('((${elem_styp}*)0))')
207 } else {
208 prepared_exprs := g.prepare_array_init_exprs(node.exprs, expr_types,
209 resolved_elem_type.typ)
210 g.write('_MOV((${elem_styp}[${len}]){')
211 for i, expr in prepared_exprs {
212 actual_expr := array_init_orig_expr(expr)
213 expr_type := if expr_types.len > i { expr_types[i] } else { resolved_elem_type.typ }
214 if resolved_elem_type.typ.has_flag(.option) {
215 g.expr_with_opt(expr, expr_type, resolved_elem_type.typ)
216 } else if expr_type == ast.string_type
217 && actual_expr !in [ast.IndexExpr, ast.CallExpr, ast.StringLiteral, ast.StringInterLiteral, ast.InfixExpr] {
218 if is_iface_or_sumtype {
219 g.expr_with_cast(expr, expr_type, resolved_elem_type.typ)
220 } else {
221 g.write('builtin__string_clone(')
222 g.expr(expr)
223 g.write(')')
224 }
225 } else {
226 g.expr_with_cast(expr, expr_type, resolved_elem_type.typ)
227 }
228 if i != len - 1 {
229 g.write(', ')
230 }
231 }
232 g.write('}))')
233 }
234 if g.is_shared {
235 g.write('}, sizeof(${shared_styp}))')
236 } else if is_amp {
237 g.write(')')
238 }
239 } else if len == 0 {
240 // `[]int{len: 6, cap:10, init:22}`
241 g.array_init_with_fields(node, elem_type, is_amp, shared_styp, var_name)
242 } else {
243 // `[1, 2, 3]`
244 elem_styp := g.styp(resolved_elem_type.typ)
245 noscan := g.check_noscan(resolved_elem_type.typ)
246 prepared_exprs := g.prepare_array_init_exprs(node.exprs, expr_types, resolved_elem_type.typ)
247 if resolved_elem_type.unaliased_sym.kind == .function {
248 g.write('builtin__new_array_from_c_array(${len}, ${len}, sizeof(voidptr), _MOV((voidptr[${len}]){')
249 } else {
250 g.write('builtin__new_array_from_c_array${noscan}(${len}, ${len}, sizeof(${elem_styp}), _MOV((${elem_styp}[${len}]){')
251 }
252 if len > 8 {
253 g.writeln('')
254 g.write('\t\t')
255 }
256 is_iface_or_sumtype := elem_sym.kind in [.sum_type, .interface]
257 for i, expr in prepared_exprs {
258 actual_expr := array_init_orig_expr(expr)
259 expr_type := if expr_types.len > i { expr_types[i] } else { resolved_elem_type.typ }
260 if expr_type == ast.string_type
261 && actual_expr !in [ast.IndexExpr, ast.CallExpr, ast.StringLiteral, ast.StringInterLiteral, ast.InfixExpr] {
262 if is_iface_or_sumtype {
263 g.expr_with_cast(expr, expr_type, resolved_elem_type.typ)
264 } else {
265 g.write('builtin__string_clone(')
266 g.expr(expr)
267 g.write(')')
268 }
269 } else {
270 if resolved_elem_type.typ.has_flag(.option) {
271 g.expr_with_opt(expr, expr_type, resolved_elem_type.typ)
272 } else if resolved_elem_type.unaliased_sym.kind == .array_fixed
273 && (expr is ast.CTempVar
274 || actual_expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr]) {
275 info := resolved_elem_type.unaliased_sym.info as ast.ArrayFixed
276 g.fixed_array_var_init(g.expr_string(expr), expr.is_auto_deref_var(),
277 info.elem_type, info.size)
278 } else {
279 g.expr_with_cast(expr, expr_type, resolved_elem_type.typ)
280 }
281 }
282 if i != len - 1 {
283 if i > 0 && i & 7 == 0 { // i > 0 && i % 8 == 0
284 g.writeln(',')
285 g.write('\t\t')
286 } else {
287 g.write(', ')
288 }
289 }
290 }
291 g.write('}))')
292 if g.is_shared {
293 g.write('}, sizeof(${shared_styp}))')
294 } else if is_amp {
295 g.write(')')
296 }
297 }
298}
299
300fn (mut g Gen) normalized_array_interface_cast_type(typ ast.Type) ast.Type {
301 return g.table.unaliased_type(g.unwrap_generic(typ)).clear_flags(.generic, .variadic)
302}
303
304fn (mut g Gen) can_convert_array_to_interface_array(got_type ast.Type, expected_type ast.Type) bool {
305 if got_type.is_ptr() || expected_type.is_ptr() || got_type.has_option_or_result()
306 || expected_type.has_option_or_result() {
307 return false
308 }
309 got := g.normalized_array_interface_cast_type(got_type)
310 expected := g.normalized_array_interface_cast_type(expected_type)
311 if got == expected {
312 return false
313 }
314 if g.table.final_sym(got).kind != .array || g.table.final_sym(expected).kind != .array {
315 return false
316 }
317 return g.can_convert_array_elem_to_interface_array(got, expected)
318}
319
320fn (mut g Gen) can_convert_array_elem_to_interface_array(got ast.Type, expected ast.Type) bool {
321 got_type := g.normalized_array_interface_cast_type(got)
322 expected_type := g.normalized_array_interface_cast_type(expected)
323 got_sym := g.table.final_sym(got_type)
324 expected_sym := g.table.final_sym(expected_type)
325 if got_sym.kind == .array && expected_sym.kind == .array {
326 return g.can_convert_array_elem_to_interface_array(got_sym.array_info().elem_type,
327 expected_sym.array_info().elem_type)
328 }
329 return !expected_type.is_ptr() && expected_sym.kind == .interface
330 && g.table.does_type_implement_interface(got_type, expected_type)
331}
332
333fn (mut g Gen) register_array_interface_cast_fn(got_type ast.Type, expected_type ast.Type) string {
334 got := g.normalized_array_interface_cast_type(got_type)
335 expected := g.normalized_array_interface_cast_type(expected_type)
336 fn_name := '__v_array_to_interface_array__${g.styp(got)}__to__${g.styp(expected)}'
337 mut already_generated := false
338 lock g.generated_array_interface_cast_fns {
339 already_generated = fn_name in g.generated_array_interface_cast_fns
340 if !already_generated {
341 g.generated_array_interface_cast_fns[fn_name] = true
342 }
343 }
344 if already_generated {
345 return fn_name
346 }
347 got_info := g.table.final_sym(got).array_info()
348 expected_info := g.table.final_sym(expected).array_info()
349 expected_styp := g.styp(expected)
350 expected_elem_styp := g.styp(expected_info.elem_type)
351 noscan := g.check_noscan(expected_info.elem_type)
352 g.definitions.writeln('${g.static_non_parallel}${expected_styp} ${fn_name}(${g.styp(got)} a);')
353 mut fn_builder := strings.new_builder(512)
354 fn_builder.writeln('${g.static_non_parallel}inline ${expected_styp} ${fn_name}(${g.styp(got)} a) {')
355 fn_builder.writeln('\t${expected_styp} res = builtin____new_array_with_default${noscan}(a.len, a.cap, sizeof(${expected_elem_styp}), 0);')
356 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < a.len; ++i) {')
357 src_elem_expr := '((${g.styp(got_info.elem_type)}*)a.data)[i]'
358 converted_expr := g.array_interface_cast_expr(src_elem_expr, got_info.elem_type,
359 expected_info.elem_type)
360 fn_builder.writeln('\t\t((${expected_elem_styp}*)res.data)[i] = ${converted_expr};')
361 fn_builder.writeln('\t}')
362 fn_builder.writeln('\treturn res;')
363 fn_builder.writeln('}')
364 g.auto_fn_definitions << fn_builder.str()
365 return fn_name
366}
367
368fn (mut g Gen) array_interface_cast_expr(src_elem_expr string, got_type ast.Type, expected_type ast.Type) string {
369 got := g.normalized_array_interface_cast_type(got_type)
370 expected := g.normalized_array_interface_cast_type(expected_type)
371 if got == expected {
372 return src_elem_expr
373 }
374 got_sym := g.table.final_sym(got)
375 expected_sym := g.table.final_sym(expected)
376 if got_sym.kind == .array && expected_sym.kind == .array {
377 inner_fn := g.register_array_interface_cast_fn(got, expected)
378 return '${inner_fn}(${src_elem_expr})'
379 }
380 if expected_sym.kind == .interface && !expected.is_ptr() {
381 concrete_got := g.concrete_interface_cast_type(got)
382 got_styp := g.cc_type(concrete_got, true)
383 mut cast_fn := 'I_${got_styp}_to_Interface_${expected_sym.cname}'
384 if expected_sym.info is ast.Interface && expected_sym.info.is_generic {
385 cast_fn = g.generic_fn_name(expected_sym.info.concrete_types, cast_fn)
386 }
387 lock g.referenced_fns {
388 g.referenced_fns[cast_fn] = true
389 }
390 if concrete_got.is_ptr() {
391 return '${cast_fn}(${src_elem_expr})'
392 }
393 return '${cast_fn}(HEAP(${got_styp}, ${src_elem_expr}))'
394 }
395 return src_elem_expr
396}
397
398fn (mut g Gen) interface_clone_fn_name(interface_type ast.Type) string {
399 interface_sym := g.table.final_sym(g.table.unaliased_type(g.unwrap_generic(interface_type)))
400 mut fn_name := '__v_interface_clone__${interface_sym.cname}'
401 if interface_sym.info is ast.Interface && interface_sym.info.is_generic {
402 fn_name = g.generic_fn_name(interface_sym.info.concrete_types, fn_name)
403 }
404 return fn_name
405}
406
407fn (mut g Gen) register_array_interface_repeat_fn(array_type ast.Type) string {
408 array_typ := g.table.unaliased_type(g.unwrap_generic(array_type))
409 array_sym := g.table.final_sym(array_typ)
410 if array_sym.kind != .array {
411 return ''
412 }
413 array_info := array_sym.info as ast.Array
414 interface_sym :=
415 g.table.final_sym(g.table.unaliased_type(g.unwrap_generic(array_info.elem_type)))
416 if interface_sym.kind != .interface {
417 return ''
418 }
419 array_styp := g.styp(array_type)
420 elem_styp := g.styp(array_info.elem_type)
421 clone_fn_name := g.interface_clone_fn_name(array_info.elem_type)
422 fn_name := '__v_array_repeat_interface__${array_styp}'
423 mut already_generated := false
424 lock g.generated_array_interface_repeat_fns {
425 already_generated = fn_name in g.generated_array_interface_repeat_fns
426 if !already_generated {
427 g.generated_array_interface_repeat_fns[fn_name] = true
428 }
429 }
430 if already_generated {
431 return fn_name
432 }
433 g.definitions.writeln('${g.static_non_parallel}${array_styp} ${fn_name}(${array_styp} a, ${ast.int_type_name} count);')
434 mut fn_builder := strings.new_builder(512)
435 fn_builder.writeln('${g.static_non_parallel}inline ${array_styp} ${fn_name}(${array_styp} a, ${ast.int_type_name} count) {')
436 fn_builder.writeln('\t${array_styp} res = builtin__array_repeat_to_depth(*(array*)&a, count, 0);')
437 fn_builder.writeln('\tif (a.len > 0) {')
438 fn_builder.writeln('\t\tfor (${ast.int_type_name} i = 0; i < res.len; ++i) {')
439 fn_builder.writeln('\t\t\t((${elem_styp}*)res.data)[i] = ${clone_fn_name}(((${elem_styp}*)a.data)[i % a.len]);')
440 fn_builder.writeln('\t\t}')
441 fn_builder.writeln('\t}')
442 fn_builder.writeln('\treturn res;')
443 fn_builder.writeln('}')
444 g.auto_fn_definitions << fn_builder.str()
445 return fn_name
446}
447
448fn (mut g Gen) fixed_array_init(node ast.ArrayInit, array_type Type, var_name string, is_amp bool) {
449 prev_inside_lambda := g.inside_lambda
450 g.inside_lambda = true
451 defer {
452 g.inside_lambda = prev_inside_lambda
453 }
454 array_info := array_type.unaliased_sym.array_fixed_info()
455 if node.has_index {
456 past := g.past_tmp_var_from_var_name(var_name)
457 defer(fn) {
458 g.past_tmp_var_done(past)
459 }
460
461 ret_typ_str := g.styp(node.typ)
462 elem_typ_str := g.styp(node.elem_type)
463 if var_name == '' {
464 g.write('${ret_typ_str} ${past.tmp_var} =')
465 }
466 g.write('{')
467 if node.has_val {
468 g.write_c99_0_elements_for_array(node.exprs.len)
469 } else if node.has_init {
470 g.write_c99_0_elements_for_array(array_info.size)
471 } else {
472 g.write('0')
473 }
474 g.write('}')
475 g.writeln2(';', '{')
476 g.indent++
477 g.writeln('${elem_typ_str}* pelem = (${elem_typ_str}*)${past.tmp_var};')
478 g.writeln('${ast.int_type_name} _len = (${ast.int_type_name})sizeof(${past.tmp_var}) / sizeof(${elem_typ_str});')
479 g.writeln('for (${ast.int_type_name} index=0; index<_len; index++, pelem++) {')
480 g.set_current_pos_as_last_stmt_pos()
481 g.indent++
482 g.writeln('${ast.int_type_name} it = index;') // FIXME: Remove this line when it is fully forbidden
483 g.set_current_pos_as_last_stmt_pos()
484 g.write('*pelem = ')
485 g.expr_with_init(node)
486 g.writeln(';')
487 g.indent--
488 g.writeln('}')
489 g.indent--
490 g.writeln('}')
491 g.set_current_pos_as_last_stmt_pos()
492 return
493 }
494 is_none := node.is_option && !node.has_init && !node.has_val
495
496 if node.has_val && node.exprs.len == 0 {
497 g.write('NULL')
498 return
499 }
500
501 if (g.inside_struct_init && g.inside_cast && !g.inside_memset && !g.inside_opt_or_res
502 && !g.inside_sumtype_cast) || (node.is_option && !is_none) {
503 ret_typ_str := g.styp(node.typ)
504 g.write('(${ret_typ_str})')
505 }
506 elem_sym := g.table.final_sym(node.elem_type)
507 is_struct := g.inside_array_fixed_struct && elem_sym.kind == .struct
508 if !is_struct && !is_none {
509 g.write('{')
510 }
511 if node.is_option && !is_none {
512 g.write('.state=0, .err=_const_none__, .data={')
513 }
514 if node.has_val {
515 tmp_inside_array := g.inside_array_item
516 g.inside_array_item = true
517 defer(fn) {
518 g.inside_array_item = tmp_inside_array
519 }
520 nelen := node.exprs.len
521 prepared_exprs := g.prepare_array_init_exprs(node.exprs, node.expr_types, node.elem_type)
522 for i, expr in prepared_exprs {
523 actual_expr := array_init_orig_expr(expr)
524 if elem_sym.kind == .array_fixed
525 && (expr is ast.CTempVar || actual_expr in [ast.Ident, ast.SelectorExpr]) {
526 elem_info := elem_sym.array_fixed_info()
527 g.fixed_array_var_init(g.expr_string(expr), expr.is_auto_deref_var(),
528 elem_info.elem_type, elem_info.size)
529 } else if elem_sym.kind == .array_fixed && actual_expr is ast.CallExpr
530 && g.table.final_sym(actual_expr.return_type).kind == .array_fixed {
531 elem_info := elem_sym.array_fixed_info()
532 tmp_var := g.expr_with_var(expr, node.expr_types[i], false)
533 g.fixed_array_var_init(tmp_var, false, elem_info.elem_type, elem_info.size)
534 } else {
535 expr_type := if node.expr_types.len > i && node.expr_types[i] != 0 {
536 node.expr_types[i]
537 } else {
538 node.elem_type
539 }
540 if node.elem_type.has_flag(.option) {
541 g.expr_with_opt(expr, expr_type, node.elem_type)
542 } else {
543 g.expr_with_cast(expr, expr_type, node.elem_type)
544 }
545 }
546 g.add_commas_and_prevent_long_lines(i, nelen)
547 }
548 } else if node.has_init {
549 info := array_type.unaliased_sym.info as ast.ArrayFixed
550 // Always loop and call expr_with_init for each element to avoid copying
551 // temporary variable declarations and initialization code
552 for i in 0 .. info.size {
553 g.expr_with_init(node)
554 g.add_commas_and_prevent_long_lines(i, info.size)
555 }
556 } else if is_amp {
557 g.write('0')
558 } else {
559 if elem_sym.kind == .map {
560 // fixed array for map -- [N]map[key_type]value_type
561 map_info := elem_sym.map_info()
562 before_map_expr_pos := g.out.len
563 {
564 g.expr(ast.MapInit{
565 key_type: map_info.key_type
566 value_type: map_info.value_type
567 })
568 }
569 smap_expr := g.out.cut_to(before_map_expr_pos)
570 g.write_all_n_elements_for_array(array_info.size, smap_expr)
571 } else if elem_sym.kind == .array_fixed {
572 // nested fixed array -- [N][N]type
573 arr_info := elem_sym.array_fixed_info()
574 mut exprs := []ast.Expr{cap: 1}
575 exprs << ast.IntegerLiteral{}
576 {
577 g.expr(ast.ArrayInit{
578 exprs: exprs
579 typ: node.elem_type
580 elem_type: arr_info.elem_type
581 })
582 }
583 sarr_expr := g.cut_and_get_fixed_array_init_elements()
584 g.write_c99_elements_for_array(array_info.size, sarr_expr)
585 } else if elem_sym.kind == .chan {
586 // fixed array for chan -- [N]chan
587 chan_info := elem_sym.chan_info()
588 before_chan_expr_pos := g.out.len
589 g.expr(ast.ChanInit{
590 typ: node.elem_type
591 elem_type: chan_info.elem_type
592 })
593 schan_expr := g.out.cut_to(before_chan_expr_pos)
594 g.write_c99_elements_for_array(array_info.size, schan_expr)
595 } else if is_none {
596 g.gen_option_error(node.typ, ast.None{})
597 } else {
598 std := g.type_default(node.elem_type)
599 if g.can_use_c99_designators() && std == '0' {
600 g.write('0')
601 } else if node.elem_type.has_flag(.option) {
602 for i in 0 .. array_info.size {
603 g.expr_with_opt(ast.None{}, ast.none_type, node.elem_type)
604 g.add_commas_and_prevent_long_lines(i, array_info.size)
605 }
606 } else {
607 g.write_c99_elements_for_array(array_info.size, std)
608 }
609 }
610 }
611 if node.is_option && !is_none {
612 g.write('}')
613 }
614 if !is_struct && !is_none {
615 g.write('}')
616 }
617}
618
619// cut_and_get_fixed_array_init_elements
620// for `Array_fixed_Array_fixed_Array_fixed__option_int_2_2_2 a = {{ _t1, _t2}`
621// will cut to `=` and return `{ _t1, _t2}`
622@[direct_array_access]
623fn (mut g Gen) cut_and_get_fixed_array_init_elements() string {
624 // extract the `{{},{}}` string
625 mut nested_level := 0
626 for i := g.out.len - 1; i >= 0; i-- {
627 if g.out[i] == `}` {
628 nested_level++
629 } else if g.out[i] == `{` {
630 nested_level--
631 } else if g.out[i] == ` ` {
632 continue
633 }
634 if nested_level == 0 {
635 return g.out.cut_to(i)
636 }
637 }
638 return '/*this should not happend*/'
639}
640
641fn (mut g Gen) expr_with_init(node ast.ArrayInit) {
642 if node.elem_type.has_flag(.option) {
643 g.expr_with_opt(node.init_expr, node.init_type, node.elem_type)
644 } else {
645 g.expr_with_cast(node.init_expr, node.init_type, node.elem_type)
646 }
647}
648
649fn (mut g Gen) struct_has_array_or_map_field(elem_typ ast.Type) bool {
650 unaliased_sym := g.table.final_sym(elem_typ)
651 if unaliased_sym.kind == .struct {
652 info := unaliased_sym.info as ast.Struct
653 for field in info.fields {
654 field_sym := g.table.final_sym(field.typ)
655 if field_sym.kind in [.array, .map] {
656 return true
657 }
658 }
659 }
660 return false
661}
662
663// `[]int{len: 6, cap: 10, init: index * index}`
664fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp bool, shared_styp string,
665 var_name string) {
666 prev_inside_lambda := g.inside_lambda
667 g.inside_lambda = true
668 defer {
669 g.inside_lambda = prev_inside_lambda
670 }
671 elem_styp := g.styp(elem_type.typ)
672 noscan := g.check_noscan(elem_type.typ)
673 is_default_array := elem_type.unaliased_sym.kind == .array && node.has_init
674 is_default_map := elem_type.unaliased_sym.kind == .map && node.has_init
675 needs_more_defaults := node.has_len && (g.struct_has_array_or_map_field(elem_type.typ)
676 || elem_type.unaliased_sym.kind in [.array, .map])
677 if node.has_index {
678 // []int{len: 6, init: index * index} when variable it is used in init expression
679 past := g.past_tmp_var_from_var_name(var_name)
680 defer(fn) {
681 g.past_tmp_var_done(past)
682 }
683
684 // Use the resolved elem_type (not stale AST types) for generating correct C types
685 // in generic function instantiations.
686 resolved_array_idx := g.table.find_or_register_array(elem_type.typ)
687 ret_typ := g.styp(ast.new_type(resolved_array_idx))
688 elem_typ := g.styp(elem_type.typ)
689 if var_name == '' {
690 g.write('${ret_typ} ${past.tmp_var} =')
691 }
692 if is_default_array {
693 g.write('builtin____new_array_with_array_default${noscan}(')
694 } else if is_default_map {
695 g.write('builtin____new_array_with_map_default${noscan}(')
696 } else {
697 g.write('builtin____new_array_with_default${noscan}(')
698 }
699 if node.has_len {
700 g.expr(node.len_expr)
701 g.write(', ')
702 } else {
703 g.write('0, ')
704 }
705 if node.has_cap {
706 g.expr(node.cap_expr)
707 g.write(', ')
708 } else {
709 g.write('0, ')
710 }
711 if elem_type.unaliased_sym.kind == .function {
712 g.write('sizeof(voidptr), ')
713 } else {
714 g.write('sizeof(${elem_styp}), ')
715 }
716 if is_default_array {
717 info := elem_type.unaliased_sym.info as ast.Array
718 depth := if g.table.sym(info.elem_type).kind == .array { 1 } else { 0 }
719 g.write2('(${elem_styp}[]){', g.type_default(elem_type.typ))
720 g.write('}[0], ${depth})')
721 } else if node.has_len && elem_type.typ == ast.string_type {
722 g.write2('&(${elem_styp}[]){', '_S("")')
723 g.write('})')
724 } else if node.has_len && elem_type.unaliased_sym.kind in [.array, .map] {
725 g.write2('(voidptr)&(${elem_styp}[]){', g.type_default(elem_type.typ))
726 g.write('}[0])')
727 } else {
728 g.write('0)')
729 }
730 if g.is_shared {
731 g.write('}, sizeof(${shared_styp}))')
732 } else if is_amp {
733 g.write(')')
734 }
735 g.writeln2(';', '{')
736 g.indent++
737 g.writeln('${elem_typ}* pelem = (${elem_typ}*)${past.tmp_var}.data;')
738 g.writeln('for (${ast.int_type_name} index=0; index<${past.tmp_var}.len; index++, pelem++) {')
739 g.set_current_pos_as_last_stmt_pos()
740 g.indent++
741 g.writeln('${ast.int_type_name} it = index;') // FIXME: Remove this line when it is fully forbidden
742 g.set_current_pos_as_last_stmt_pos()
743 if elem_type.unaliased_sym.kind != .array_fixed {
744 g.write('*pelem = ')
745 g.expr_with_init(node)
746 g.writeln(';')
747 } else {
748 g.write('memcpy(pelem, ')
749 g.expr_with_init(node)
750 g.writeln(', sizeof(${elem_styp}));')
751 }
752 g.indent--
753 g.writeln('}')
754 g.indent--
755 g.writeln('}')
756 g.set_current_pos_as_last_stmt_pos()
757 return
758 }
759 if is_default_array {
760 g.write('builtin____new_array_with_array_default${noscan}(')
761 } else if is_default_map {
762 g.write('builtin____new_array_with_map_default${noscan}(')
763 } else if needs_more_defaults {
764 g.write('builtin____new_array_with_multi_default${noscan}(')
765 } else {
766 g.write('builtin____new_array_with_default${noscan}(')
767 }
768 if node.has_len {
769 g.expr(node.len_expr)
770 g.write(', ')
771 } else {
772 g.write('0, ')
773 }
774 if node.has_cap {
775 g.expr(node.cap_expr)
776 g.write(', ')
777 } else {
778 g.write('0, ')
779 }
780 if elem_type.unaliased_sym.kind == .function {
781 g.write('sizeof(voidptr), ')
782 } else {
783 g.write('sizeof(${elem_styp}), ')
784 }
785 if is_default_array {
786 info := elem_type.unaliased_sym.info as ast.Array
787 depth := if g.table.sym(info.elem_type).kind == .array { 1 } else { 0 }
788 g.write('(${elem_styp}[]){')
789 g.expr(node.init_expr)
790 g.write('}[0], ${depth})')
791 } else if is_default_map {
792 g.write('(${elem_styp}[]){')
793 g.expr(node.init_expr)
794 g.write('}[0])')
795 } else if needs_more_defaults {
796 tmp := g.new_tmp_var()
797 line := g.go_before_last_stmt().trim_space()
798 g.empty_line = true
799
800 g.write('${elem_styp}* ${tmp} = (${elem_styp}*) builtin___v_malloc((')
801 g.expr(node.len_expr)
802 g.writeln(') * sizeof(${elem_styp}));')
803 ind := g.new_tmp_var()
804 g.write('for (${ast.int_type_name} ${ind}=0; ${ind}<')
805 g.expr(node.len_expr)
806 g.writeln('; ${ind}++) {')
807 g.write('\t${tmp}[${ind}] = ')
808 if node.has_init {
809 g.expr_with_init(node)
810 } else {
811 if node.elem_type.has_flag(.option) {
812 g.expr_with_opt(ast.None{}, ast.none_type, elem_type.typ)
813 } else if elem_type.unaliased_sym.kind == .struct {
814 // `T{}` stays expression-safe for struct field defaults that expand
815 // to statement-based array/map initialization.
816 g.struct_init(ast.StructInit{
817 typ: elem_type.typ
818 })
819 } else {
820 g.write(g.type_default(elem_type.typ))
821 }
822 }
823 g.writeln2(';', '}')
824 g.write2(line, ' (voidptr)${tmp})')
825 } else if node.has_init {
826 g.write('&(${elem_styp}[]){')
827 g.expr_with_init(node)
828 g.write('})')
829 } else if node.has_len && node.elem_type.has_flag(.option) {
830 g.write('&')
831 g.expr_with_opt(ast.None{}, ast.none_type, elem_type.typ)
832 g.write(')')
833 } else if node.has_len && node.elem_type == ast.string_type {
834 g.write2('&(${elem_styp}[]){', '_S("")')
835 g.write('})')
836 } else if node.has_len && elem_type.unaliased_sym.kind in [.struct, .array, .map] {
837 g.write2('(voidptr)&(${elem_styp}[]){', g.type_default(elem_type.typ))
838 g.write('}[0])')
839 } else {
840 g.write('0)')
841 }
842 if g.is_shared {
843 g.write('}, sizeof(${shared_styp}))')
844 } else if is_amp {
845 g.write(')')
846 }
847}
848
849fn (mut g Gen) declare_closure_fn(mut expr ast.AnonFn, var_name string) {
850 decl_var := g.fn_var_signature(expr.typ, expr.decl.return_type, expr.decl.params.map(it.typ),
851 var_name)
852 g.write('${decl_var} = ')
853 g.gen_anon_fn(mut expr)
854 g.writeln(';')
855}
856
857fn (mut g Gen) write_closure_fn(mut expr ast.AnonFn, var_name string, declared_var string) {
858 if declared_var == '' {
859 past := g.past_tmp_var_new()
860 g.declare_closure_fn(mut expr, past.var_name)
861 g.past_tmp_var_done(past)
862 g.write('(${var_name})') // usually `it`
863 } else {
864 g.write('${declared_var}(${var_name})')
865 }
866}
867
868// `nums.map(it % 2 == 0)`
869fn (mut g Gen) gen_array_map(node ast.CallExpr) {
870 prev_inside_lambda := g.inside_lambda
871 g.inside_lambda = true
872 defer {
873 g.inside_lambda = prev_inside_lambda
874 }
875
876 past := g.past_tmp_var_new()
877 defer {
878 g.past_tmp_var_done(past)
879 }
880
881 left_type := g.resolved_array_receiver_type(node)
882 left_sym := g.table.final_sym(left_type)
883 left_is_array := left_sym.kind == .array
884 inp_sym := left_sym
885 inp_elem_type := if left_is_array {
886 (inp_sym.info as ast.Array).elem_type
887 } else {
888 (inp_sym.info as ast.ArrayFixed).elem_type
889 }
890 inp_elem_styp := g.styp(inp_elem_type)
891 if inp_sym.kind !in [.array, .array_fixed] {
892 verror('map() requires an array or a fixed array')
893 }
894
895 mut expr := node.args[0].expr
896 var_name := g.get_array_expr_param_name(mut expr)
897 g.refresh_array_expr_param_type(expr, var_name, inp_elem_type)
898
899 mut return_type := g.resolve_return_type(node)
900 if g.table.final_sym(g.unwrap_generic(return_type)).kind !in [.array, .array_fixed] {
901 return_type = if g.type_resolver.is_generic_expr(node.args[0].expr) {
902 mut ctyp := ast.void_type
903 if node.args[0].expr is ast.CallExpr && node.args[0].expr.return_type_generic != 0
904 && node.args[0].expr.return_type_generic.has_flag(.generic) {
905 ctyp = g.resolve_return_type(node.args[0].expr)
906 if g.table.type_kind(node.args[0].expr.return_type_generic) in [
907 .array,
908 .array_fixed,
909 ] {
910 ctyp = ast.new_type(g.table.find_or_register_array(ctyp))
911 }
912 }
913 if ctyp == ast.void_type {
914 ctyp = g.type_resolver.unwrap_generic_expr(node.args[0].expr, node.return_type)
915 }
916 if g.table.type_kind(g.unwrap_generic(ctyp)) !in [.array, .array_fixed] {
917 ast.new_type(g.table.find_or_register_array(ctyp))
918 } else {
919 ctyp
920 }
921 } else {
922 node.return_type
923 }
924 }
925 ret_styp := g.styp(return_type)
926 ret_sym := g.table.final_sym(return_type)
927
928 ret_elem_type := if left_is_array {
929 (ret_sym.info as ast.Array).elem_type
930 } else {
931 (ret_sym.info as ast.ArrayFixed).elem_type
932 }
933 ret_elem_sym := g.table.final_sym(ret_elem_type)
934 mut ret_elem_styp := g.styp(ret_elem_type)
935 mut closure_var_decl := ''
936 tmp_map_expr_result_name := g.new_tmp_var()
937 if mut expr is ast.SelectorExpr {
938 if expr.typ != ast.void_type {
939 var_sym := g.table.sym(expr.typ)
940 if var_sym.info is ast.FnType {
941 ret_elem_styp = 'voidptr'
942 closure_var_decl = g.fn_var_signature(expr.typ, var_sym.info.func.return_type,
943 var_sym.info.func.params.map(it.typ), tmp_map_expr_result_name)
944 }
945 }
946 }
947 noscan := g.check_noscan(ret_elem_type)
948 has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, ret_styp, '{0}')
949 if left_is_array {
950 g.writeln('${past.tmp_var} = builtin____new_array${noscan}(0, ${past.tmp_var}_len, sizeof(${ret_elem_styp}));\n')
951 }
952
953 mut closure_var := ''
954 if mut expr is ast.AnonFn {
955 if expr.inherited_vars.len > 0 {
956 closure_var = g.new_tmp_var()
957 prev_track_closure_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
958 g.track_lambda_autofree_tmp_arg_vars = false
959 g.declare_closure_fn(mut expr, closure_var)
960 g.track_lambda_autofree_tmp_arg_vars = prev_track_closure_tmp_arg_vars
961 }
962 }
963
964 i := g.new_tmp_var()
965 g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
966 g.indent++
967 is_auto_heap := g.array_expr_param_needs_indirect_access(expr, var_name)
968 old_param_auto_heap := g.set_array_expr_param_auto_heap(expr, var_name, is_auto_heap)
969 defer {
970 g.set_array_expr_param_auto_heap(expr, var_name, old_param_auto_heap)
971 }
972 g.write_prepared_var(var_name, inp_elem_type, inp_elem_styp, past.tmp_var, i, left_is_array,
973 is_auto_heap)
974 g.set_current_pos_as_last_stmt_pos()
975 mut is_embed_map_filter := false
976 lambda_autofree_tmp_arg_vars_start := g.lambda_autofree_tmp_arg_vars.len
977 prev_inside_lambda_autofree_tmp := g.inside_lambda_autofree_tmp
978 prev_track_lambda_autofree_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
979 g.inside_lambda_autofree_tmp = true
980 g.track_lambda_autofree_tmp_arg_vars = true
981 match mut expr {
982 ast.AnonFn {
983 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
984 if ret_elem_sym.kind == .array_fixed {
985 // unpack fixed array return value
986 g.writeln('{0};')
987 g.write('memcpy(&${tmp_map_expr_result_name}, ')
988 }
989 if expr.inherited_vars.len > 0 {
990 g.write_closure_fn(mut expr, var_name, closure_var)
991 } else {
992 prev_track_anon_fn_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
993 g.track_lambda_autofree_tmp_arg_vars = false
994 g.gen_anon_fn_decl(mut expr)
995 g.track_lambda_autofree_tmp_arg_vars = prev_track_anon_fn_tmp_arg_vars
996 g.write('${expr.decl.name}(${var_name})')
997 }
998 if ret_elem_sym.kind == .array_fixed {
999 g.write('.ret_arr, sizeof(${ret_elem_styp}))')
1000 }
1001 }
1002 ast.Ident {
1003 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1004 if expr.kind == .function {
1005 if expr.obj is ast.Var && expr.obj.is_inherited {
1006 g.write(closure_ctx + '->')
1007 }
1008 g.write('${c_name(expr.name)}(${var_name})')
1009 } else if expr.kind == .variable {
1010 var_info := expr.var_info()
1011 sym := g.table.sym(var_info.typ)
1012 if sym.kind == .function {
1013 if expr.obj is ast.Var && expr.obj.is_inherited {
1014 g.write(closure_ctx + '->')
1015 }
1016 g.write('${c_name(expr.name)}(${var_name})')
1017 } else {
1018 g.expr(expr)
1019 }
1020 } else {
1021 g.expr(expr)
1022 }
1023 }
1024 ast.CallExpr {
1025 if expr.name in ['map', 'filter', 'all', 'any', 'count'] {
1026 is_embed_map_filter = true
1027 g.set_current_pos_as_last_stmt_pos()
1028 }
1029 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1030 g.expr(expr)
1031 }
1032 ast.CastExpr {
1033 // value.map(Type(it)) when `value` is a comptime var
1034 if expr.expr is ast.Ident && node.left is ast.Ident && node.left.ct_expr {
1035 ctyp := g.type_resolver.get_type(ast.Expr(node.left))
1036 if ctyp != ast.void_type {
1037 expr.expr_type = g.table.value_type(ctyp)
1038 }
1039 }
1040 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1041 g.expr(expr)
1042 }
1043 ast.LambdaExpr {
1044 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1045 g.expr(expr.expr)
1046 }
1047 ast.SelectorExpr {
1048 if expr.typ != ast.void_type && g.table.final_sym(expr.typ).kind == .array_fixed {
1049 atype := g.styp(expr.typ)
1050 if closure_var_decl != '' {
1051 g.write('memcpy(&${closure_var_decl}, &')
1052 g.expr(expr)
1053 g.write(', sizeof(${atype}))')
1054 } else {
1055 g.writeln('${ret_elem_styp} ${tmp_map_expr_result_name};')
1056 g.write('memcpy(&${tmp_map_expr_result_name}, &')
1057 g.expr(expr)
1058 g.write(', sizeof(${atype}))')
1059 }
1060 } else {
1061 if closure_var_decl != '' {
1062 g.write('${closure_var_decl} = ')
1063 } else {
1064 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1065 }
1066 g.expr(expr)
1067 }
1068 }
1069 ast.AsCast {
1070 if expr.typ.has_flag(.generic) {
1071 ret_elem_styp = g.styp(g.unwrap_generic(expr.typ))
1072 }
1073 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1074 g.expr(expr)
1075 }
1076 else {
1077 if closure_var_decl != '' {
1078 g.write('${closure_var_decl} = ')
1079 } else {
1080 g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
1081 }
1082 g.expr(expr)
1083 }
1084 }
1085
1086 g.inside_lambda_autofree_tmp = prev_inside_lambda_autofree_tmp
1087 g.track_lambda_autofree_tmp_arg_vars = prev_track_lambda_autofree_tmp_arg_vars
1088
1089 if left_is_array {
1090 g.writeln(';')
1091 g.write_lambda_autofree_tmp_arg_vars(lambda_autofree_tmp_arg_vars_start)
1092 g.writeln('builtin__array_push${noscan}((array*)&${past.tmp_var}, &${tmp_map_expr_result_name});')
1093 } else {
1094 g.writeln(';')
1095 g.write_lambda_autofree_tmp_arg_vars(lambda_autofree_tmp_arg_vars_start)
1096 g.writeln('${past.tmp_var}[${i}] = ${tmp_map_expr_result_name};')
1097 }
1098 g.indent--
1099 g.writeln('}')
1100 if !is_embed_map_filter {
1101 g.set_current_pos_as_last_stmt_pos()
1102 }
1103 if has_infix_left_var_name {
1104 g.indent--
1105 g.writeln('}')
1106 }
1107}
1108
1109fn (mut g Gen) write_lambda_autofree_tmp_arg_vars(start int) {
1110 if g.lambda_autofree_tmp_arg_vars.len <= start {
1111 return
1112 }
1113 for var_name in g.lambda_autofree_tmp_arg_vars[start..] {
1114 g.writeln('builtin__string_free(&${var_name});')
1115 }
1116 g.lambda_autofree_tmp_arg_vars = g.lambda_autofree_tmp_arg_vars[..start].clone()
1117}
1118
1119@[inline]
1120fn (mut g Gen) array_receiver_is_auto_heap(left ast.Expr) bool {
1121 return left is ast.Ident && g.resolved_ident_is_auto_heap(left)
1122}
1123
1124@[inline]
1125fn (mut g Gen) resolved_array_receiver_type(node ast.CallExpr) ast.Type {
1126 resolved_left_type := g.recheck_concrete_type(g.resolved_expr_type(node.left, node.left_type))
1127 default_left_type := g.recheck_concrete_type(node.left_type)
1128 unwrapped_resolved := g.unwrap_generic(resolved_left_type)
1129 unwrapped_default := g.unwrap_generic(default_left_type)
1130 resolved_left_sym := if unwrapped_resolved != 0 {
1131 g.table.final_sym(unwrapped_resolved)
1132 } else {
1133 g.table.final_sym(node.left_type)
1134 }
1135 default_left_sym := if unwrapped_default != 0 {
1136 g.table.final_sym(unwrapped_default)
1137 } else {
1138 g.table.final_sym(node.left_type)
1139 }
1140 if resolved_left_type != 0 && resolved_left_sym.kind in [.array, .array_fixed] {
1141 return resolved_left_type
1142 }
1143 if default_left_type != 0 && default_left_sym.kind in [.array, .array_fixed] {
1144 return default_left_type
1145 }
1146 return if resolved_left_type != 0 {
1147 resolved_left_type
1148 } else {
1149 default_left_type
1150 }
1151}
1152
1153@[inline]
1154fn (mut g Gen) array_receiver_is_indirect(left ast.Expr, left_type ast.Type) bool {
1155 return !left_type.has_flag(.shared_f)
1156 && (left_type.is_ptr() || g.array_receiver_is_auto_heap(left))
1157}
1158
1159@[inline]
1160fn (mut g Gen) array_receiver_field_access(left ast.Expr, left_type ast.Type) string {
1161 return if g.array_receiver_is_auto_heap(left) && !left_type.has_flag(.shared_f) {
1162 '->'
1163 } else {
1164 g.dot_or_ptr(left_type)
1165 }
1166}
1167
1168fn (mut g Gen) write_array_receiver(left ast.Expr) {
1169 old_inside_selector_lhs := g.inside_selector_lhs
1170 g.inside_selector_lhs = true
1171 defer {
1172 g.inside_selector_lhs = old_inside_selector_lhs
1173 }
1174 g.expr(left)
1175}
1176
1177// `susers := users.sorted(a.age < b.age)`
1178fn (mut g Gen) gen_array_sorted(node ast.CallExpr) {
1179 past := g.past_tmp_var_new()
1180 defer {
1181 g.past_tmp_var_done(past)
1182 }
1183 mut resolved_return_type := g.resolve_return_type(node)
1184 mut sym := g.table.final_sym(resolved_return_type)
1185 if sym.kind !in [.array, .array_fixed] {
1186 resolved_return_type = node.return_type
1187 sym = g.table.final_sym(resolved_return_type)
1188 }
1189 atype := g.styp(resolved_return_type)
1190 left_is_array := sym.kind == .array
1191 elem_type := if left_is_array {
1192 (sym.info as ast.Array).elem_type
1193 } else {
1194 (sym.info as ast.ArrayFixed).elem_type
1195 }
1196 if left_is_array {
1197 depth := g.get_array_depth(elem_type)
1198 resolved_left_type := g.resolved_array_receiver_type(node)
1199 left_is_indirect := g.array_receiver_is_indirect(node.left, resolved_left_type)
1200 if !left_is_indirect {
1201 g.write('${atype} ${past.tmp_var} = builtin__array_clone_to_depth(ADDR(${atype},')
1202 g.write_array_receiver(node.left)
1203 g.writeln('), ${depth});')
1204 } else {
1205 g.write('${atype} ${past.tmp_var} = builtin__array_clone_to_depth(')
1206 g.write_array_receiver(node.left)
1207 g.writeln(', ${depth});')
1208 }
1209 } else {
1210 g.writeln('${atype} ${past.tmp_var};')
1211 g.write('memcpy(&${past.tmp_var}, &')
1212 if node.left is ast.ArrayInit {
1213 g.fixed_array_init_with_cast(node.left, node.left_type)
1214 } else {
1215 g.expr(node.left)
1216 }
1217 g.writeln(', sizeof(${atype}));')
1218 }
1219
1220 unsafe {
1221 node.left = ast.Expr(ast.Ident{
1222 name: past.tmp_var
1223 })
1224 // The tmp_var is a cloned array (value, not pointer), so update
1225 // left_type to strip pointer flags from the mut receiver.
1226 node.left_type = resolved_return_type
1227 }
1228 g.gen_array_sort(node)
1229 g.writeln(';')
1230}
1231
1232// array_sort_expr_key returns a C-identifier-safe, lossless key for a sort expression.
1233fn array_sort_expr_key(expr_key string) string {
1234 hex_digits := '0123456789abcdef'
1235 mut b := strings.new_builder(expr_key.len * 2)
1236 for ch in expr_key.bytes() {
1237 b.write_u8(hex_digits[int(ch >> 4)])
1238 b.write_u8(hex_digits[int(ch & 0x0f)])
1239 }
1240 return b.str()
1241}
1242
1243// `users.sort(a.age < b.age)`
1244fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
1245 // println('filter s="${s}"')
1246 resolved_left_type := g.resolved_array_receiver_type(node)
1247 rec_sym := g.table.final_sym(resolved_left_type)
1248 if rec_sym.kind !in [.array, .array_fixed] {
1249 // println(rec_sym.kind)
1250 verror('.sort() is an array method or a fixed array method')
1251 }
1252 if g.pref.is_bare {
1253 g.writeln('bare_panic(_S("sort does not work with -freestanding"))')
1254 return
1255 }
1256 left_is_array := rec_sym.kind == .array
1257 elem_type := if left_is_array {
1258 (rec_sym.info as ast.Array).elem_type
1259 } else {
1260 (rec_sym.info as ast.ArrayFixed).elem_type
1261 }
1262 // `users.sort(a.age > b.age)`
1263 // Generate a comparison function for a custom type
1264 elem_stype := g.styp(elem_type)
1265 mut compare_fn := 'compare_${g.stable_type_symbol_hash(elem_type)}_${elem_stype.replace('*',
1266 '_ptr')}'
1267 mut comparison_type := g.unwrap(ast.void_type)
1268 mut left_expr, mut right_expr := '', ''
1269 mut use_lambda := false
1270 mut lambda_fn_name := ''
1271 // the only argument can only be an infix expression like `a < b` or `b.field > a.field`
1272 if node.args.len == 0 {
1273 comparison_type = g.unwrap(elem_type.set_nr_muls(0))
1274 left_expr = '*a'
1275 right_expr = '*b'
1276 } else if node.args[0].expr is ast.LambdaExpr {
1277 lambda_fn_name = node.args[0].expr.func.decl.name
1278 compare_fn = '${lambda_fn_name}_lambda_wrapper'
1279 use_lambda = true
1280 mut lambda_node := unsafe { node.args[0].expr }
1281 g.gen_anon_fn_decl(mut lambda_node.func)
1282 } else {
1283 infix_expr := node.args[0].expr as ast.InfixExpr
1284 // For plain `a < b` / `b < a`, the comparison_type is the element type.
1285 // Avoid using `infix_expr.left_type` here because the AST node is shared
1286 // across generic instantiations and may have been mutated by a later
1287 // checker pass for a different concrete type. See vlang/v#27121.
1288 comparison_left_type := if infix_expr.left is ast.Ident
1289 && (infix_expr.left.name == 'a' || infix_expr.left.name == 'b') {
1290 elem_type
1291 } else {
1292 infix_expr.left_type
1293 }
1294 comparison_type = g.unwrap(comparison_left_type.set_nr_muls(0))
1295 left_name := infix_expr.left.str()
1296 expr_key := '${left_name}\n${infix_expr.op.str()}\n${infix_expr.right.str()}'
1297 if left_name.len > 1 {
1298 compare_fn += '_by' +
1299 left_name[1..].replace_each(['.', '_', '[', '_', ']', '_', "'", '_', '"', '_', '(', '', ')', '', ',', '', '/', '_'])
1300 }
1301 compare_fn += '_expr_${array_sort_expr_key(expr_key)}'
1302 // is_reverse is `true` for `.sort(a > b)` and `.sort(b < a)`
1303 is_reverse := (left_name.starts_with('a') && infix_expr.op == .gt)
1304 || (left_name.starts_with('b') && infix_expr.op == .lt)
1305 if is_reverse {
1306 compare_fn += '_reverse'
1307 }
1308 if left_name.starts_with('a') != is_reverse {
1309 left_expr = g.expr_string(infix_expr.left)
1310 right_expr = g.expr_string(infix_expr.right)
1311 if infix_expr.left is ast.Ident {
1312 left_expr = '*' + left_expr
1313 }
1314 if infix_expr.right is ast.Ident {
1315 right_expr = '*' + right_expr
1316 }
1317 } else {
1318 left_expr = g.expr_string(infix_expr.right)
1319 right_expr = g.expr_string(infix_expr.left)
1320 if infix_expr.left is ast.Ident {
1321 right_expr = '*' + right_expr
1322 }
1323 if infix_expr.right is ast.Ident {
1324 left_expr = '*' + left_expr
1325 }
1326 }
1327 }
1328
1329 // Register a new custom `compare_xxx` function for qsort()
1330 // TODO: move to checker
1331 mut already_generated := false
1332 lock g.array_sort_fn {
1333 already_generated = compare_fn in g.array_sort_fn
1334 if !already_generated {
1335 g.array_sort_fn << compare_fn
1336 }
1337 }
1338 if already_generated {
1339 g.gen_array_sort_call(node, '${compare_fn}_qsort_adapter', left_is_array)
1340 return
1341 }
1342
1343 stype_arg := g.styp(elem_type)
1344 // In -parallel-cc these bodies are seen by every split C translation unit via `out.h`,
1345 // so they need internal linkage to avoid duplicate symbols at link time.
1346 g.sort_fn_definitions.writeln('${g.array_sort_fn_visibility()}int ${compare_fn}(${stype_arg}* a, ${stype_arg}* b) {')
1347 c_condition := g.array_sort_lt_condition(comparison_type, use_lambda, lambda_fn_name,
1348 left_expr, right_expr, 'a', 'b')
1349 reverse_condition := g.array_sort_lt_condition(comparison_type, use_lambda, lambda_fn_name,
1350 right_expr, left_expr, 'b', 'a')
1351 g.sort_fn_definitions.writeln('\tif (${c_condition}) return -1;')
1352 g.sort_fn_definitions.writeln('\tif (${reverse_condition}) return 1;')
1353 g.sort_fn_definitions.writeln('\treturn 0;')
1354 g.sort_fn_definitions.writeln('}\n')
1355
1356 // write call to the generated function
1357 g.gen_array_sort_call(node, g.ensure_array_sort_qsort_adapter(compare_fn, elem_type),
1358 left_is_array)
1359}
1360
1361fn (mut g Gen) array_sort_lt_condition(comparison_type Type, use_lambda bool, lambda_fn_name string, left_expr string, right_expr string, left_arg string, right_arg string) string {
1362 if use_lambda {
1363 return '${lambda_fn_name}(${left_arg}, ${right_arg})'
1364 }
1365 if comparison_type.sym.has_method('<') {
1366 method_name := if comparison_type.sym.is_builtin() {
1367 'builtin__${g.styp(comparison_type.typ)}__lt'
1368 } else {
1369 '${g.styp(comparison_type.typ)}__lt'
1370 }
1371 return '${method_name}(${left_expr}, ${right_expr})'
1372 }
1373 if comparison_type.unaliased_sym.has_method('<') {
1374 method_name := if comparison_type.unaliased_sym.is_builtin() {
1375 'builtin__${g.styp(comparison_type.unaliased)}__lt'
1376 } else {
1377 '${g.styp(comparison_type.unaliased)}__lt'
1378 }
1379 return '${method_name}(${left_expr}, ${right_expr})'
1380 }
1381 return '${left_expr} < ${right_expr}'
1382}
1383
1384@[inline]
1385fn (g &Gen) array_sort_fn_visibility() string {
1386 return if g.static_modifier != '' { g.static_modifier } else { 'VV_LOC ' }
1387}
1388
1389fn (mut g Gen) ensure_array_sort_qsort_adapter(compare_fn string, elem_type ast.Type) string {
1390 qsort_compare_fn := '${compare_fn}_qsort_adapter'
1391 mut already_generated := false
1392 lock g.array_sort_wrappers {
1393 already_generated = qsort_compare_fn in g.array_sort_wrappers
1394 if !already_generated {
1395 g.array_sort_wrappers << qsort_compare_fn
1396 }
1397 }
1398 if already_generated {
1399 return qsort_compare_fn
1400 }
1401 elem_stype := g.styp(elem_type)
1402 g.sort_fn_definitions.writeln('${g.array_sort_fn_visibility()}int ${qsort_compare_fn}(const void* a, const void* b) {')
1403 g.sort_fn_definitions.writeln('\treturn ${compare_fn}((${elem_stype}*)a, (${elem_stype}*)b);')
1404 g.sort_fn_definitions.writeln('}\n')
1405 return qsort_compare_fn
1406}
1407
1408@[inline]
1409fn (g &Gen) qsort_callback_cast(compare_expr string) string {
1410 return '((int (*)(const void*, const void*))(${compare_expr}))'
1411}
1412
1413@[inline]
1414fn (mut g Gen) plain_array_sort_callback_cname(expr ast.Expr) ?string {
1415 if expr is ast.CastExpr {
1416 return g.plain_array_sort_callback_cname(expr.expr)
1417 }
1418 if expr is ast.ParExpr {
1419 return g.plain_array_sort_callback_cname(expr.expr)
1420 }
1421 if expr is ast.UnsafeExpr {
1422 return g.plain_array_sort_callback_cname(expr.expr)
1423 }
1424 if expr is ast.Ident && expr.kind == .function {
1425 return g.expr_string(expr)
1426 }
1427 return none
1428}
1429
1430@[inline]
1431fn (mut g Gen) can_generate_array_sort_qsort_adapter(expr ast.Expr) bool {
1432 return g.plain_array_sort_callback_cname(expr) != none
1433}
1434
1435fn (mut g Gen) array_sort_qsort_callback_expr(expr ast.Expr, elem_type ast.Type) (string, bool) {
1436 if expr is ast.CastExpr {
1437 return g.array_sort_qsort_callback_expr(expr.expr, elem_type)
1438 }
1439 if expr is ast.ParExpr {
1440 return g.array_sort_qsort_callback_expr(expr.expr, elem_type)
1441 }
1442 if expr is ast.UnsafeExpr {
1443 return g.array_sort_qsort_callback_expr(expr.expr, elem_type)
1444 }
1445 if expr is ast.LambdaExpr {
1446 lambda_fn_name := expr.func.decl.name
1447 mut lambda_node := unsafe { expr }
1448 g.gen_anon_fn_decl(mut lambda_node.func)
1449 return g.ensure_array_sort_qsort_adapter('${lambda_fn_name}_lambda_wrapper', elem_type), true
1450 }
1451 if expr is ast.AnonFn {
1452 mut fn_expr := unsafe { expr }
1453 g.gen_anon_fn_decl(mut fn_expr)
1454 return g.ensure_array_sort_qsort_adapter(expr.decl.name, elem_type), true
1455 }
1456 if expr is ast.Ident && expr.kind == .function {
1457 return g.ensure_array_sort_qsort_adapter(g.expr_string(expr), elem_type), true
1458 }
1459 return g.qsort_callback_cast(g.expr_string(expr)), false
1460}
1461
1462fn (mut g Gen) gen_array_sort_call(node ast.CallExpr, qsort_compare_fn string, is_array bool) {
1463 resolved_left_type := g.resolved_array_receiver_type(node)
1464 deref_field := g.array_receiver_field_access(node.left, resolved_left_type)
1465 // eprintln('> qsort: pointer ${node.left_type} | deref_field: `${deref_field}`')
1466 g.empty_line = true
1467 if is_array {
1468 g.write('if (')
1469 g.write_array_receiver(node.left)
1470 g.write2('${deref_field}len > 0) { ', 'v_stable_sort(')
1471 g.write_array_receiver(node.left)
1472 g.write('${deref_field}data, ')
1473 g.write_array_receiver(node.left)
1474 g.write('${deref_field}len, ')
1475 g.write_array_receiver(node.left)
1476 g.write2('${deref_field}element_size, ${qsort_compare_fn});', ' }')
1477 } else {
1478 info := g.table.final_sym(node.left_type).info as ast.ArrayFixed
1479 elem_styp := g.styp(info.elem_type)
1480 g.write('v_stable_sort(&')
1481 g.write_array_receiver(node.left)
1482 g.write(', ${info.size}, sizeof(${elem_styp}), ${qsort_compare_fn});')
1483 }
1484 g.writeln('')
1485}
1486
1487fn (mut g Gen) gen_array_sorted_with_compare(node ast.CallExpr) bool {
1488 mut resolved_return_type := g.resolve_return_type(node)
1489 mut sym := g.table.final_sym(resolved_return_type)
1490 if sym.kind !in [.array, .array_fixed] {
1491 resolved_return_type = node.return_type
1492 sym = g.table.final_sym(resolved_return_type)
1493 }
1494 left_is_array := sym.kind == .array
1495 elem_type := if left_is_array {
1496 (sym.info as ast.Array).elem_type
1497 } else {
1498 (sym.info as ast.ArrayFixed).elem_type
1499 }
1500 if left_is_array && !g.can_generate_array_sort_qsort_adapter(node.args[0].expr) {
1501 return false
1502 }
1503 past := g.past_tmp_var_new()
1504 defer {
1505 g.past_tmp_var_done(past)
1506 }
1507 atype := g.styp(resolved_return_type)
1508 if left_is_array {
1509 depth := g.get_array_depth(elem_type)
1510 resolved_left_type := g.resolved_array_receiver_type(node)
1511 left_is_indirect := g.array_receiver_is_indirect(node.left, resolved_left_type)
1512 if !left_is_indirect {
1513 g.write('${atype} ${past.tmp_var} = builtin__array_clone_to_depth(ADDR(${atype},')
1514 g.write_array_receiver(node.left)
1515 g.writeln('), ${depth});')
1516 } else {
1517 g.write('${atype} ${past.tmp_var} = builtin__array_clone_to_depth(')
1518 g.write_array_receiver(node.left)
1519 g.writeln(', ${depth});')
1520 }
1521 } else {
1522 g.writeln('${atype} ${past.tmp_var};')
1523 g.write('memcpy(&${past.tmp_var}, &')
1524 if node.left is ast.ArrayInit {
1525 g.fixed_array_init_with_cast(node.left, node.left_type)
1526 } else {
1527 g.expr(node.left)
1528 }
1529 g.writeln(', sizeof(${atype}));')
1530 }
1531
1532 unsafe {
1533 node.left = ast.Expr(ast.Ident{
1534 name: past.tmp_var
1535 })
1536 if left_is_array {
1537 node.left_type = resolved_return_type
1538 }
1539 }
1540 return g.gen_array_sort_with_compare(node)
1541}
1542
1543fn (mut g Gen) gen_array_sort_with_compare(node ast.CallExpr) bool {
1544 resolved_left_type := g.resolved_array_receiver_type(node)
1545 rec_sym := g.table.final_sym(resolved_left_type)
1546 if rec_sym.kind !in [.array, .array_fixed] {
1547 verror('.sort_with_compare() is an array method or a fixed array method')
1548 }
1549 if g.pref.is_bare {
1550 g.writeln('bare_panic(_S("sort_with_compare does not work with -freestanding"))')
1551 return true
1552 }
1553 left_is_array := rec_sym.kind == .array
1554 elem_type := if left_is_array {
1555 (rec_sym.info as ast.Array).elem_type
1556 } else {
1557 (rec_sym.info as ast.ArrayFixed).elem_type
1558 }
1559 if left_is_array {
1560 if compare_fn := g.plain_array_sort_callback_cname(node.args[0].expr) {
1561 g.gen_array_sort_call(node, g.ensure_array_sort_qsort_adapter(compare_fn, elem_type),
1562 true)
1563 return true
1564 }
1565 return false
1566 }
1567 qsort_compare_fn, has_qsort_adapter := g.array_sort_qsort_callback_expr(node.args[0].expr,
1568 elem_type)
1569 _ = has_qsort_adapter
1570 g.gen_array_sort_call(node, qsort_compare_fn, left_is_array)
1571 return true
1572}
1573
1574fn (mut g Gen) gen_fixed_array_sorted_with_compare(node ast.CallExpr) {
1575 _ = g.gen_array_sorted_with_compare(node)
1576}
1577
1578fn (mut g Gen) gen_fixed_array_sort_with_compare(node ast.CallExpr) {
1579 _ = g.gen_array_sort_with_compare(node)
1580}
1581
1582fn (mut g Gen) gen_fixed_array_reverse(node ast.CallExpr) {
1583 past := g.past_tmp_var_new()
1584 defer {
1585 g.past_tmp_var_done(past)
1586 }
1587 atype := g.styp(node.return_type)
1588 g.writeln('${atype} ${past.tmp_var};')
1589 g.write('memcpy(&${past.tmp_var}, &')
1590 if node.left is ast.ArrayInit {
1591 g.fixed_array_init_with_cast(node.left, node.left_type)
1592 } else {
1593 g.expr(node.left)
1594 }
1595 g.writeln(', sizeof(${atype}));')
1596
1597 unsafe {
1598 node.left = ast.Expr(ast.Ident{
1599 name: past.tmp_var
1600 })
1601 }
1602 g.gen_fixed_array_reverse_in_place(node)
1603}
1604
1605fn (mut g Gen) gen_fixed_array_reverse_in_place(node ast.CallExpr) {
1606 left_sym := g.table.final_sym(node.left_type)
1607 info := left_sym.info as ast.ArrayFixed
1608 elem_type := info.elem_type
1609 elem_styp := g.styp(elem_type)
1610 tmp_var := g.new_tmp_var()
1611 g.writeln('${elem_styp} ${tmp_var};')
1612 i := g.new_tmp_var()
1613 left_var := g.expr_string(node.left)
1614 g.empty_line = true
1615 g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${info.size}/2; ++${i}) {')
1616 g.writeln('\tmemcpy(&${tmp_var}, &${left_var}[${i}], sizeof(${elem_styp}));')
1617 g.writeln('\tmemcpy(&${left_var}[${i}], &${left_var}[${info.size}-${i}-1], sizeof(${elem_styp}));')
1618 g.writeln('\tmemcpy(&${left_var}[${info.size}-${i}-1], &${tmp_var}, sizeof(${elem_styp}));')
1619 g.writeln('}')
1620}
1621
1622// `nums.filter(it % 2 == 0)`
1623fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
1624 past := g.past_tmp_var_new()
1625 defer {
1626 g.past_tmp_var_done(past)
1627 }
1628
1629 resolved_left_type := g.resolved_array_receiver_type(node)
1630 left_sym := g.table.final_sym(g.unwrap_generic(resolved_left_type))
1631 if left_sym.kind !in [.array_fixed, .array] {
1632 verror('filter() requires an array')
1633 }
1634 left_is_array := left_sym.kind == .array
1635 left_elem_type := if left_is_array {
1636 (left_sym.info as ast.Array).elem_type
1637 } else {
1638 (left_sym.info as ast.ArrayFixed).elem_type
1639 }
1640 left_elem_type_str := g.styp(left_elem_type)
1641 mut resolved_return_type := g.resolve_return_type(node)
1642 if g.table.final_sym(g.unwrap_generic(resolved_return_type)).kind !in [
1643 .array_fixed,
1644 .array,
1645 ] {
1646 resolved_return_type = resolved_left_type
1647 }
1648 // .filter() returns a new plain array, not shared.
1649 if resolved_return_type.has_flag(.shared_f) {
1650 resolved_return_type = resolved_return_type.clear_flag(.shared_f)
1651 if resolved_return_type.is_ptr() {
1652 resolved_return_type = resolved_return_type.deref()
1653 }
1654 }
1655 return_sym := g.table.final_sym(g.unwrap_generic(resolved_return_type))
1656 return_elem_type := if return_sym.kind == .array {
1657 (return_sym.info as ast.Array).elem_type
1658 } else {
1659 (return_sym.info as ast.ArrayFixed).elem_type
1660 }
1661 styp := g.styp(resolved_return_type)
1662 return_elem_type_str := g.styp(return_elem_type)
1663 noscan := g.check_noscan(return_elem_type)
1664 has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, styp, '{0}')
1665 g.writeln('${past.tmp_var} = builtin____new_array${noscan}(0, ${past.tmp_var}_len, sizeof(${return_elem_type_str}));\n')
1666
1667 mut expr := node.args[0].expr
1668 var_name := g.get_array_expr_param_name(mut expr)
1669 g.refresh_array_expr_param_type(expr, var_name, left_elem_type)
1670
1671 mut closure_var := ''
1672 if mut expr is ast.AnonFn {
1673 if expr.inherited_vars.len > 0 {
1674 closure_var = g.new_tmp_var()
1675 prev_track_closure_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
1676 g.track_lambda_autofree_tmp_arg_vars = false
1677 g.declare_closure_fn(mut expr, closure_var)
1678 g.track_lambda_autofree_tmp_arg_vars = prev_track_closure_tmp_arg_vars
1679 }
1680 }
1681
1682 i := g.new_tmp_var()
1683 g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
1684 g.indent++
1685 g.write_prepared_var(var_name, left_elem_type, left_elem_type_str, past.tmp_var, i,
1686 left_is_array, false)
1687 g.set_current_pos_as_last_stmt_pos()
1688 mut is_embed_map_filter := false
1689 lambda_autofree_tmp_arg_vars_start := g.lambda_autofree_tmp_arg_vars.len
1690 match mut expr {
1691 ast.AnonFn {
1692 g.write('if (')
1693 if expr.inherited_vars.len > 0 {
1694 g.write_closure_fn(mut expr, var_name, closure_var)
1695 } else {
1696 prev_track_anon_fn_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
1697 g.track_lambda_autofree_tmp_arg_vars = false
1698 g.gen_anon_fn_decl(mut expr)
1699 g.track_lambda_autofree_tmp_arg_vars = prev_track_anon_fn_tmp_arg_vars
1700 g.write('${expr.decl.name}(${var_name})')
1701 }
1702 }
1703 ast.Ident {
1704 g.write('if (')
1705 if expr.kind == .function {
1706 g.write('${c_name(expr.name)}(${var_name})')
1707 } else if expr.kind == .variable {
1708 var_info := expr.var_info()
1709 sym_t := g.table.sym(var_info.typ)
1710 if sym_t.kind == .function {
1711 g.write('${c_name(expr.name)}(${var_name})')
1712 } else {
1713 g.expr(expr)
1714 }
1715 } else {
1716 g.expr(expr)
1717 }
1718 }
1719 ast.CallExpr {
1720 if expr.name in ['map', 'filter', 'all', 'any', 'count'] {
1721 is_embed_map_filter = true
1722 g.set_current_pos_as_last_stmt_pos()
1723 }
1724 g.write('if (')
1725 g.expr(expr)
1726 }
1727 ast.LambdaExpr {
1728 g.write('if (')
1729 g.expr(expr.expr)
1730 }
1731 else {
1732 g.write('if (')
1733 g.expr(expr)
1734 }
1735 }
1736
1737 g.writeln2(') {', '\tbuiltin__array_push${noscan}((array*)&${past.tmp_var}, &${var_name});')
1738 g.writeln('}')
1739 g.write_lambda_autofree_tmp_arg_vars(lambda_autofree_tmp_arg_vars_start)
1740 g.indent--
1741 g.writeln('}')
1742 if !is_embed_map_filter {
1743 g.set_current_pos_as_last_stmt_pos()
1744 }
1745 if has_infix_left_var_name {
1746 g.indent--
1747 g.writeln('}')
1748 }
1749}
1750
1751// `nums.insert(0, 2)` `nums.insert(0, [2,3,4])`
1752fn (mut g Gen) gen_array_insert(node ast.CallExpr) {
1753 left_sym := g.table.final_sym(node.left_type)
1754 left_info := left_sym.info as ast.Array
1755 elem_type_str := g.styp(left_info.elem_type)
1756 arg2_sym := g.table.final_sym(node.args[1].typ)
1757 is_arg2_array := arg2_sym.kind == .array
1758 && g.table.unaliased_type(node.args[1].typ.clear_flag(.variadic)) == g.table.unaliased_type(node.left_type)
1759 noscan := g.check_noscan(left_info.elem_type)
1760 resolved_left_type := g.resolved_array_receiver_type(node)
1761 addr := if g.array_receiver_is_indirect(node.left, resolved_left_type) { '' } else { '&' }
1762 if is_arg2_array {
1763 g.write('builtin__array_insert_many${noscan}(${addr}')
1764 } else {
1765 g.write('builtin__array_insert${noscan}(${addr}')
1766 }
1767 g.write_array_receiver(node.left)
1768 g.write(', ')
1769 g.expr(node.args[0].expr)
1770 if is_arg2_array {
1771 g.write(', ')
1772 g.expr(node.args[1].expr)
1773 g.write('.data, ')
1774 g.expr(node.args[1].expr)
1775 g.write('.len)')
1776 } else {
1777 needs_clone := left_info.elem_type == ast.string_type
1778 && node.args[1].expr !in [ast.IndexExpr, ast.CallExpr, ast.StringLiteral, ast.StringInterLiteral, ast.InfixExpr]
1779 g.write(', &(${elem_type_str}[]){')
1780 if needs_clone {
1781 g.write('builtin__string_clone(')
1782 }
1783 g.expr_with_cast(node.args[1].expr, node.args[1].typ, left_info.elem_type)
1784 if needs_clone {
1785 g.write(')')
1786 }
1787 g.write('})')
1788 }
1789}
1790
1791// `nums.prepend(2)` `nums.prepend([2,3,4])`
1792fn (mut g Gen) gen_array_prepend(node ast.CallExpr) {
1793 left_sym := g.table.final_sym(node.left_type)
1794 left_info := left_sym.info as ast.Array
1795 elem_type_str := g.styp(left_info.elem_type)
1796 arg_sym := g.table.final_sym(node.args[0].typ)
1797 is_arg_array := arg_sym.kind == .array
1798 && g.table.unaliased_type(node.args[0].typ) == g.table.unaliased_type(node.left_type)
1799 noscan := g.check_noscan(left_info.elem_type)
1800 resolved_left_type := g.resolved_array_receiver_type(node)
1801 addr := if g.array_receiver_is_indirect(node.left, resolved_left_type) { '' } else { '&' }
1802 if is_arg_array {
1803 g.write('builtin__array_prepend_many${noscan}(${addr}')
1804 } else {
1805 g.write('builtin__array_prepend${noscan}(${addr}')
1806 }
1807 g.write_array_receiver(node.left)
1808 if is_arg_array {
1809 g.write(', ')
1810 g.expr(node.args[0].expr)
1811 g.write('.data, ')
1812 g.expr(node.args[0].expr)
1813 g.write('.len)')
1814 } else {
1815 g.write(', &(${elem_type_str}[]){')
1816 g.expr_with_cast(node.args[0].expr, node.args[0].typ, left_info.elem_type)
1817 g.write('})')
1818 }
1819}
1820
1821fn (mut g Gen) get_array_contains_method(typ ast.Type) string {
1822 t := g.table.final_sym(g.unwrap_generic(typ).set_nr_muls(0)).idx
1823 g.array_contains_types << t
1824 return g.styp(ast.idx_to_type(t)) + '_contains'
1825}
1826
1827fn (mut g Gen) gen_array_contains_methods() {
1828 mut done := []ast.Type{}
1829 for t in g.array_contains_types {
1830 left_final_sym := g.table.final_sym(t)
1831 if left_final_sym.idx in done || g.table.sym(t).has_method('contains') {
1832 continue
1833 }
1834 done << t
1835 mut fn_builder := strings.new_builder(512)
1836 mut left_type_str := g.styp(t)
1837 fn_name := '${left_type_str}_contains'
1838
1839 if left_final_sym.kind == .array {
1840 elem_type := (left_final_sym.info as ast.Array).elem_type
1841 mut elem_type_str := g.styp(elem_type)
1842 elem_kind := g.table.sym(elem_type).kind
1843 elem_is_not_ptr := elem_type.nr_muls() == 0
1844 if elem_kind == .function {
1845 left_type_str = 'Array_voidptr'
1846 elem_type_str = 'voidptr'
1847 }
1848 g.type_definitions.writeln('${g.static_non_parallel}bool ${fn_name}(${left_type_str} a, ${elem_type_str} v);')
1849 fn_builder.writeln('${g.static_non_parallel}bool ${fn_name}(${left_type_str} a, ${elem_type_str} v) {')
1850 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < a.len; ++i) {')
1851 if elem_kind == .string {
1852 fn_builder.writeln('\t\tif (builtin__fast_string_eq(((string*)a.data)[i], v)) {')
1853 } else if elem_kind in [.array, .array_fixed] && elem_is_not_ptr {
1854 ptr_typ := g.equality_fn(elem_type)
1855 fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(((${elem_type_str}*)a.data)[i], v)) {')
1856 } else if elem_kind == .function {
1857 fn_builder.writeln('\t\tif (((voidptr*)a.data)[i] == v) {')
1858 } else if elem_kind == .map && elem_is_not_ptr {
1859 ptr_typ := g.equality_fn(elem_type)
1860 fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(((${elem_type_str}*)a.data)[i], v)) {')
1861 } else if elem_kind == .struct && elem_is_not_ptr {
1862 ptr_typ := g.equality_fn(elem_type)
1863 fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(((${elem_type_str}*)a.data)[i], v)) {')
1864 } else if elem_kind == .interface && elem_is_not_ptr {
1865 ptr_typ := g.equality_fn(elem_type)
1866 fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(((${elem_type_str}*)a.data)[i], v)) {')
1867 } else if elem_kind == .sum_type && elem_is_not_ptr {
1868 ptr_typ := g.equality_fn(elem_type)
1869 fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(((${elem_type_str}*)a.data)[i], v)) {')
1870 } else if elem_kind == .alias && elem_is_not_ptr {
1871 if g.no_eq_method_types[elem_type] {
1872 fn_builder.writeln('\t\tif (((${elem_type_str}*)a.data)[i] == v) {')
1873 } else {
1874 ptr_typ := g.equality_fn(elem_type)
1875 fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(((${elem_type_str}*)a.data)[i], v)) {')
1876 }
1877 } else {
1878 fn_builder.writeln('\t\tif (((${elem_type_str}*)a.data)[i] == v) {')
1879 }
1880 } else if left_final_sym.kind == .array_fixed {
1881 left_info := left_final_sym.info as ast.ArrayFixed
1882 size := left_info.size
1883 elem_type := left_info.elem_type
1884 mut elem_type_str := g.styp(elem_type)
1885 elem_kind := g.table.sym(elem_type).kind
1886 elem_is_not_ptr := elem_type.nr_muls() == 0
1887 if elem_kind == .function {
1888 elem_type_str = 'voidptr'
1889 }
1890 g.type_definitions.writeln('${g.static_non_parallel}bool ${fn_name}(${left_type_str} a, ${elem_type_str} v);')
1891 fn_builder.writeln('${g.static_non_parallel}bool ${fn_name}(${left_type_str} a, ${elem_type_str} v) {')
1892 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < ${size}; ++i) {')
1893 if elem_kind == .string {
1894 fn_builder.writeln('\t\tif (builtin__fast_string_eq(a[i], v)) {')
1895 } else if elem_kind in [.array, .array_fixed] && elem_is_not_ptr {
1896 ptr_typ := g.equality_fn(left_info.elem_type)
1897 fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(a[i], v)) {')
1898 } else if elem_kind == .function {
1899 fn_builder.writeln('\t\tif (a[i] == v) {')
1900 } else if elem_kind == .map && elem_is_not_ptr {
1901 ptr_typ := g.equality_fn(elem_type)
1902 fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(a[i], v)) {')
1903 } else if elem_kind == .struct && elem_is_not_ptr {
1904 ptr_typ := g.equality_fn(elem_type)
1905 fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(a[i], v)) {')
1906 } else if elem_kind == .interface && elem_is_not_ptr {
1907 ptr_typ := g.equality_fn(elem_type)
1908 fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(a[i], v)) {')
1909 } else if elem_kind == .sum_type && elem_is_not_ptr {
1910 ptr_typ := g.equality_fn(elem_type)
1911 fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(a[i], v)) {')
1912 } else if elem_kind == .alias && elem_is_not_ptr {
1913 if g.no_eq_method_types[elem_type] {
1914 fn_builder.writeln('\t\tif (a[i] == v) {')
1915 } else {
1916 ptr_typ := g.equality_fn(elem_type)
1917 fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(a[i], v)) {')
1918 }
1919 } else {
1920 fn_builder.writeln('\t\tif (a[i] == v) {')
1921 }
1922 }
1923 fn_builder.writeln('\t\t\treturn true;')
1924 fn_builder.writeln('\t\t}')
1925 fn_builder.writeln('\t}')
1926 fn_builder.writeln('\treturn false;')
1927 fn_builder.writeln('}')
1928 g.auto_fn_definitions << fn_builder.str()
1929 }
1930}
1931
1932// `nums.contains(2)`
1933fn (mut g Gen) gen_array_contains(left_type ast.Type, left ast.Expr, right_type ast.Type, right ast.Expr) {
1934 fn_name := g.get_array_contains_method(left_type)
1935 left_sym := g.table.final_sym(left_type)
1936 g.write2('${fn_name}(', strings.repeat(`*`, left_type.nr_muls()))
1937 if left_type.share() == .shared_t {
1938 g.go_back(1)
1939 }
1940 if left_sym.kind == .array_fixed && left is ast.ArrayInit {
1941 g.fixed_array_init_with_cast(left, left_type)
1942 } else {
1943 g.expr(left)
1944 }
1945 if left_type.share() == .shared_t {
1946 g.write('->val')
1947 }
1948 g.write(', ')
1949 elem_typ := if left_sym.kind == .array {
1950 left_sym.array_info().elem_type
1951 } else {
1952 left_sym.array_fixed_info().elem_type
1953 }
1954 is_auto_deref_var := right.is_auto_deref_var()
1955 // Check if the right side is an interface/sumtype variable that needs
1956 // dereferencing. Skip this for smartcast variables (match arms) since
1957 // the smartcast codegen already handles the deref.
1958 mut is_interface_needs_deref := false
1959 if right is ast.Ident && right.info is ast.IdentVar && right.obj is ast.Var {
1960 if g.table.sym(elem_typ).kind !in [.interface, .sum_type, .struct]
1961 && g.table.sym(right.obj.typ).kind in [.interface, .sum_type] {
1962 is_interface_needs_deref = right.obj.smartcasts.len == 0
1963 }
1964 }
1965 if (is_auto_deref_var && !elem_typ.is_ptr()) || is_interface_needs_deref
1966 || elem_typ.nr_muls() + 1 == right_type.nr_muls() {
1967 g.write('*')
1968 }
1969 if g.table.sym(elem_typ).kind in [.interface, .sum_type] {
1970 g.expr_with_cast(right, right_type, elem_typ)
1971 } else if right is ast.ArrayInit && g.table.final_sym(right_type).kind == .array_fixed {
1972 g.fixed_array_init_with_cast(right, right_type)
1973 } else {
1974 g.expr(right)
1975 }
1976 g.write(')')
1977}
1978
1979fn (mut g Gen) get_array_index_method(typ ast.Type, is_last_index bool) string {
1980 t := g.unwrap_generic(typ).set_nr_muls(0)
1981 return if is_last_index {
1982 g.array_last_index_types << t
1983 g.styp(t) + '_last_index'
1984 } else {
1985 g.array_index_types << t
1986 g.styp(t) + '_index'
1987 }
1988}
1989
1990fn (mut g Gen) get_array_get_method(typ ast.Type) string {
1991 t := g.unwrap_generic(typ).set_nr_muls(0)
1992 g.array_get_types << t
1993 return g.styp(t) + '__v_get'
1994}
1995
1996fn (mut g Gen) gen_array_index_methods(is_last_index bool) {
1997 mut done := []ast.Type{}
1998 indxe_types := if is_last_index { g.array_last_index_types } else { g.array_index_types }
1999 for t in indxe_types {
2000 if t in done || (is_last_index && g.table.sym(t).has_method('last_index'))
2001 || (!is_last_index && g.table.sym(t).has_method('index')) {
2002 continue
2003 }
2004 done << t
2005 final_left_sym := g.table.final_sym(t)
2006 mut left_type_str := g.styp(t)
2007 fn_name := if is_last_index {
2008 '${left_type_str}_last_index'
2009 } else {
2010 '${left_type_str}_index'
2011 }
2012 mut fn_builder := strings.new_builder(512)
2013
2014 if final_left_sym.kind == .array {
2015 info := final_left_sym.info as ast.Array
2016 mut elem_type_str := g.styp(info.elem_type)
2017 elem_sym := g.table.sym(info.elem_type)
2018 if elem_sym.kind == .function {
2019 left_type_str = 'Array_voidptr'
2020 elem_type_str = 'voidptr'
2021 }
2022 g.type_definitions.writeln('${g.static_non_parallel}${ast.int_type_name} ${fn_name}(${left_type_str} a, ${elem_type_str} v);')
2023 fn_builder.writeln('${g.static_non_parallel}${ast.int_type_name} ${fn_name}(${left_type_str} a, ${elem_type_str} v) {')
2024 if is_last_index {
2025 fn_builder.writeln('\tif (a.len == 0) return -1;')
2026 fn_builder.writeln('\t${elem_type_str}* pelem = (${elem_type_str}*)((byte*)a.data + (a.len-1)*a.element_size);')
2027 fn_builder.writeln('\tfor (${ast.int_type_name} i = a.len-1; i >= 0; --i, --pelem) {')
2028 } else {
2029 fn_builder.writeln('\t${elem_type_str}* pelem = a.data;')
2030 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < a.len; ++i, ++pelem) {')
2031 }
2032 if elem_sym.kind == .string {
2033 fn_builder.writeln('\t\tif (builtin__fast_string_eq(*pelem, v)) {')
2034 } else if elem_sym.kind in [.array, .array_fixed] && !info.elem_type.is_ptr() {
2035 ptr_typ := g.equality_fn(info.elem_type)
2036 fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(*pelem, v)) {')
2037 } else if elem_sym.kind == .function && !info.elem_type.is_ptr() {
2038 fn_builder.writeln('\t\tif ( *pelem == v) {')
2039 } else if elem_sym.kind == .map && !info.elem_type.is_ptr() {
2040 ptr_typ := g.equality_fn(info.elem_type)
2041 fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((*pelem, v))) {')
2042 } else if elem_sym.kind == .struct && !info.elem_type.is_ptr() {
2043 ptr_typ := g.equality_fn(info.elem_type)
2044 fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(*pelem, v)) {')
2045 } else if elem_sym.kind == .interface {
2046 ptr_typ := g.equality_fn(info.elem_type)
2047 if info.elem_type.is_ptr() {
2048 fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(**pelem, *v)) {')
2049 } else {
2050 fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(*pelem, v)) {')
2051 }
2052 } else if elem_sym.kind == .sum_type {
2053 ptr_typ := g.equality_fn(info.elem_type)
2054 if info.elem_type.is_ptr() {
2055 fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(**pelem, *v)) {')
2056 } else {
2057 fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(*pelem, v)) {')
2058 }
2059 } else if elem_sym.kind == .alias {
2060 ptr_typ := g.equality_fn(info.elem_type)
2061 fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(*pelem, v)) {')
2062 } else {
2063 fn_builder.writeln('\t\tif (*pelem == v) {')
2064 }
2065 } else if final_left_sym.kind == .array_fixed {
2066 info := final_left_sym.info as ast.ArrayFixed
2067 mut elem_type_str := g.styp(info.elem_type)
2068 elem_sym := g.table.sym(info.elem_type)
2069 if elem_sym.kind == .function {
2070 elem_type_str = 'voidptr'
2071 }
2072 g.type_definitions.writeln('${g.static_non_parallel}${ast.int_type_name} ${fn_name}(${left_type_str} a, ${elem_type_str} v);')
2073 fn_builder.writeln('${g.static_non_parallel}${ast.int_type_name} ${fn_name}(${left_type_str} a, ${elem_type_str} v) {')
2074 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < ${info.size}; ++i) {')
2075 if elem_sym.kind == .string {
2076 fn_builder.writeln('\t\tif (builtin__fast_string_eq(a[i], v)) {')
2077 } else if elem_sym.kind in [.array, .array_fixed] && !info.elem_type.is_ptr() {
2078 ptr_typ := g.equality_fn(info.elem_type)
2079 fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(a[i], v)) {')
2080 } else if elem_sym.kind == .function && !info.elem_type.is_ptr() {
2081 fn_builder.writeln('\t\tif (a[i] == v) {')
2082 } else if elem_sym.kind == .map && !info.elem_type.is_ptr() {
2083 ptr_typ := g.equality_fn(info.elem_type)
2084 fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((a[i], v))) {')
2085 } else if elem_sym.kind == .struct && !info.elem_type.is_ptr() {
2086 ptr_typ := g.equality_fn(info.elem_type)
2087 fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(a[i], v)) {')
2088 } else if elem_sym.kind == .interface {
2089 ptr_typ := g.equality_fn(info.elem_type)
2090 if info.elem_type.is_ptr() {
2091 fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(*a[i], *v)) {')
2092 } else {
2093 fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(a[i], v)) {')
2094 }
2095 } else if elem_sym.kind == .sum_type {
2096 ptr_typ := g.equality_fn(info.elem_type)
2097 if info.elem_type.is_ptr() {
2098 fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(*a[i], *v)) {')
2099 } else {
2100 fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(a[i], v)) {')
2101 }
2102 } else if elem_sym.kind == .alias {
2103 ptr_typ := g.equality_fn(info.elem_type)
2104 fn_builder.writeln('\t\tif (${ptr_typ}_alias_eq(a[i], v)) {')
2105 } else {
2106 fn_builder.writeln('\t\tif (a[i] == v) {')
2107 }
2108 }
2109 fn_builder.writeln('\t\t\treturn i;')
2110 fn_builder.writeln('\t\t}')
2111 fn_builder.writeln('\t}')
2112 fn_builder.writeln('\treturn -1;')
2113 fn_builder.writeln('}')
2114 g.auto_fn_definitions << fn_builder.str()
2115 }
2116}
2117
2118fn (mut g Gen) gen_array_get_methods() {
2119 mut done := []ast.Type{}
2120 for t in g.array_get_types {
2121 if t in done {
2122 continue
2123 }
2124 done << t
2125 final_left_sym := g.table.final_sym(t)
2126 if final_left_sym.kind != .array {
2127 continue
2128 }
2129 info := final_left_sym.info as ast.Array
2130 left_type_str := g.styp(t)
2131 elem_type_str := g.styp(info.elem_type)
2132 elem_sym := g.table.sym(info.elem_type)
2133 option_type_str := g.styp(info.elem_type.set_flag(.option))
2134 base_elem_type_str := g.base_type(info.elem_type)
2135 default_value := if info.elem_type.has_flag(.option) {
2136 g.type_default(info.elem_type.clear_flag(.option))
2137 } else if elem_sym.kind == .function {
2138 '0'
2139 } else {
2140 g.type_default(info.elem_type)
2141 }
2142 fn_name := '${left_type_str}__v_get'
2143 g.type_definitions.writeln('${g.static_non_parallel}${option_type_str} ${fn_name}(${left_type_str} a, ${ast.int_type_name} i);')
2144 mut fn_builder := strings.new_builder(512)
2145 fn_builder.writeln('${g.static_non_parallel}${option_type_str} ${fn_name}(${left_type_str} a, ${ast.int_type_name} i) {')
2146 fn_builder.writeln('\t${option_type_str} res = {0};')
2147 fn_builder.writeln('\tif (i < 0 || i >= a.len) {')
2148 fn_builder.writeln('\t\tbuiltin___option_none(&(${base_elem_type_str}[]){ ${default_value} }, (_option*)&res, sizeof(${base_elem_type_str}));')
2149 fn_builder.writeln('\t\treturn res;')
2150 fn_builder.writeln('\t}')
2151 if info.elem_type.has_flag(.option) {
2152 fn_builder.writeln('\t${elem_type_str}* opt_elem = (${elem_type_str}*)((byte*)a.data + i * a.element_size);')
2153 fn_builder.writeln('\tif (opt_elem->state == 0) {')
2154 fn_builder.writeln('\t\tbuiltin___option_ok(opt_elem->data, (_option*)&res, sizeof(${base_elem_type_str}));')
2155 fn_builder.writeln('\t} else {')
2156 fn_builder.writeln('\t\tres.state = opt_elem->state;')
2157 fn_builder.writeln('\t\tres.err = opt_elem->err;')
2158 fn_builder.writeln('\t}')
2159 } else {
2160 storage_type_str := if elem_sym.kind == .function { 'voidptr' } else { elem_type_str }
2161 fn_builder.writeln('\tbuiltin___option_ok(((${storage_type_str}*)((byte*)a.data + i * a.element_size)), (_option*)&res, sizeof(${storage_type_str}));')
2162 }
2163 fn_builder.writeln('\treturn res;')
2164 fn_builder.writeln('}')
2165 g.auto_fn_definitions << fn_builder.str()
2166 }
2167}
2168
2169fn (mut g Gen) gen_array_get(node ast.CallExpr) {
2170 resolved_left_type := g.resolved_array_receiver_type(node)
2171 fn_name := g.get_array_get_method(resolved_left_type)
2172 left_is_ptr := g.array_receiver_is_indirect(node.left, resolved_left_type)
2173 left_is_shared := resolved_left_type.has_flag(.shared_f)
2174 g.write('${fn_name}(')
2175 if left_is_ptr && !left_is_shared {
2176 g.write('*')
2177 }
2178 g.write_array_receiver(node.left)
2179 if left_is_shared {
2180 if left_is_ptr {
2181 g.write('->val')
2182 } else {
2183 g.write('.val')
2184 }
2185 }
2186 g.write(', ')
2187 g.expr(node.args[0].expr)
2188 g.write(')')
2189}
2190
2191// `nums.index(2)`
2192// `nums.last_index(2)`
2193fn (mut g Gen) gen_array_index(node ast.CallExpr, is_last_index bool) {
2194 resolved_left_type := g.resolved_array_receiver_type(node)
2195 fn_name := g.get_array_index_method(resolved_left_type, is_last_index)
2196 left_sym := g.table.final_sym(resolved_left_type)
2197 g.write('${fn_name}(')
2198 if g.array_receiver_is_indirect(node.left, resolved_left_type) {
2199 g.write('*')
2200 }
2201 if left_sym.kind == .array_fixed && node.left is ast.ArrayInit {
2202 g.fixed_array_init_with_cast(node.left, node.left_type)
2203 } else {
2204 g.write_array_receiver(node.left)
2205 }
2206 g.write(', ')
2207
2208 elem_typ := if left_sym.kind == .array {
2209 left_sym.array_info().elem_type
2210 } else {
2211 left_sym.array_fixed_info().elem_type
2212 }
2213 // auto deref var is redundant for interfaces and sum types.
2214 if node.args[0].expr.is_auto_deref_var()
2215 && g.table.sym(elem_typ).kind !in [.interface, .sum_type] {
2216 g.write('*')
2217 }
2218 if g.table.sym(elem_typ).kind in [.interface, .sum_type] {
2219 g.expr_with_cast(node.args[0].expr, node.args[0].typ, elem_typ)
2220 } else if node.args[0].expr is ast.ArrayInit
2221 && g.table.final_sym(node.args[0].typ).kind == .array_fixed {
2222 g.fixed_array_init_with_cast(node.args[0].expr, node.args[0].typ)
2223 } else {
2224 g.expr(node.args[0].expr)
2225 }
2226 g.write(')')
2227}
2228
2229fn (mut g Gen) gen_array_wait(node ast.CallExpr) {
2230 resolved_left_type := g.resolved_array_receiver_type(node)
2231 arr := g.table.sym(g.unwrap_generic(resolved_left_type))
2232 thread_type := arr.array_info().elem_type
2233 thread_sym := g.table.sym(thread_type)
2234 thread_ret_type := thread_sym.thread_info().return_type
2235 fn_name := g.register_thread_array_wait_call(g.unwrap_generic(thread_ret_type))
2236 g.write('${fn_name}(')
2237 if g.array_receiver_is_indirect(node.left, resolved_left_type) {
2238 g.write('*')
2239 }
2240 g.write_array_receiver(node.left)
2241 g.write(')')
2242}
2243
2244fn (mut g Gen) gen_fixed_array_wait(node ast.CallExpr) {
2245 arr := g.table.sym(g.unwrap_generic(node.receiver_type))
2246 thread_type := arr.array_fixed_info().elem_type
2247 thread_sym := g.table.sym(thread_type)
2248 thread_ret_type := thread_sym.thread_info().return_type
2249 fn_name := g.register_thread_fixed_array_wait_call(node, g.unwrap_generic(thread_ret_type))
2250 g.write('${fn_name}(')
2251 g.expr(node.left)
2252 g.write(')')
2253}
2254
2255fn (mut g Gen) gen_array_any(node ast.CallExpr) {
2256 past := g.past_tmp_var_new()
2257 defer {
2258 g.past_tmp_var_done(past)
2259 }
2260
2261 resolved_left_type := g.resolved_array_receiver_type(node)
2262 sym := g.table.final_sym(g.unwrap_generic(resolved_left_type))
2263 left_is_array := sym.kind == .array
2264 elem_type := if left_is_array {
2265 (sym.info as ast.Array).elem_type
2266 } else {
2267 (sym.info as ast.ArrayFixed).elem_type
2268 }
2269 elem_type_str := g.styp(elem_type)
2270 has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, 'bool', 'false')
2271
2272 mut expr := node.args[0].expr
2273 var_name := g.get_array_expr_param_name(mut expr)
2274 g.refresh_array_expr_param_type(expr, var_name, elem_type)
2275
2276 mut closure_var := ''
2277 if mut expr is ast.AnonFn {
2278 if expr.inherited_vars.len > 0 {
2279 closure_var = g.new_tmp_var()
2280 prev_track_closure_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
2281 g.track_lambda_autofree_tmp_arg_vars = false
2282 g.declare_closure_fn(mut expr, closure_var)
2283 g.track_lambda_autofree_tmp_arg_vars = prev_track_closure_tmp_arg_vars
2284 }
2285 }
2286 i := g.new_tmp_var()
2287 g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
2288 g.indent++
2289
2290 g.write_prepared_var(var_name, elem_type, elem_type_str, past.tmp_var, i, left_is_array, false)
2291 g.set_current_pos_as_last_stmt_pos()
2292 mut is_embed_map_filter := false
2293 lambda_autofree_tmp_arg_vars_start := g.lambda_autofree_tmp_arg_vars.len
2294 match mut expr {
2295 ast.AnonFn {
2296 g.write('if (')
2297 if expr.inherited_vars.len > 0 {
2298 g.write_closure_fn(mut expr, var_name, closure_var)
2299 } else {
2300 prev_track_anon_fn_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
2301 g.track_lambda_autofree_tmp_arg_vars = false
2302 g.gen_anon_fn_decl(mut expr)
2303 g.track_lambda_autofree_tmp_arg_vars = prev_track_anon_fn_tmp_arg_vars
2304 g.write('${expr.decl.name}(${var_name})')
2305 }
2306 }
2307 ast.Ident {
2308 g.write('if (')
2309 if expr.kind == .function {
2310 g.write('${c_name(expr.name)}(${var_name})')
2311 } else if expr.kind == .variable {
2312 var_info := expr.var_info()
2313 sym_t := g.table.sym(var_info.typ)
2314 if sym_t.kind == .function {
2315 g.write('${c_name(expr.name)}(${var_name})')
2316 } else {
2317 g.expr(expr)
2318 }
2319 } else {
2320 g.expr(expr)
2321 }
2322 }
2323 ast.CallExpr {
2324 if expr.name in ['map', 'filter', 'all', 'any', 'count'] {
2325 is_embed_map_filter = true
2326 g.set_current_pos_as_last_stmt_pos()
2327 }
2328 g.write('if (')
2329 g.expr(expr)
2330 }
2331 ast.LambdaExpr {
2332 g.write('if (')
2333 g.expr(expr.expr)
2334 }
2335 else {
2336 g.write('if (')
2337 g.expr(expr)
2338 }
2339 }
2340
2341 g.writeln2(') {', '\t${past.tmp_var} = true;')
2342 g.writeln('}')
2343 g.write_lambda_autofree_tmp_arg_vars(lambda_autofree_tmp_arg_vars_start)
2344 g.writeln('if (${past.tmp_var}) {')
2345 g.writeln('\tbreak;')
2346 g.writeln('}')
2347 g.indent--
2348 g.writeln('}')
2349 if !is_embed_map_filter {
2350 g.set_current_pos_as_last_stmt_pos()
2351 }
2352 if has_infix_left_var_name {
2353 g.indent--
2354 g.writeln('}')
2355 g.set_current_pos_as_last_stmt_pos()
2356 }
2357}
2358
2359fn (mut g Gen) gen_array_count(node ast.CallExpr) {
2360 past := g.past_tmp_var_new()
2361 defer {
2362 g.past_tmp_var_done(past)
2363 }
2364
2365 resolved_left_type := g.resolved_array_receiver_type(node)
2366 sym := g.table.final_sym(g.unwrap_generic(resolved_left_type))
2367 left_is_array := sym.kind == .array
2368 elem_type := if left_is_array {
2369 (sym.info as ast.Array).elem_type
2370 } else {
2371 (sym.info as ast.ArrayFixed).elem_type
2372 }
2373 elem_type_str := g.styp(elem_type)
2374 has_infix_left_var_name :=
2375 g.write_prepared_tmp_value(past.tmp_var, node, ast.int_type_name, '0')
2376
2377 mut expr := node.args[0].expr
2378 var_name := g.get_array_expr_param_name(mut expr)
2379 g.refresh_array_expr_param_type(expr, var_name, elem_type)
2380
2381 mut closure_var := ''
2382 if mut expr is ast.AnonFn {
2383 if expr.inherited_vars.len > 0 {
2384 closure_var = g.new_tmp_var()
2385 prev_track_closure_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
2386 g.track_lambda_autofree_tmp_arg_vars = false
2387 g.declare_closure_fn(mut expr, closure_var)
2388 g.track_lambda_autofree_tmp_arg_vars = prev_track_closure_tmp_arg_vars
2389 }
2390 }
2391 i := g.new_tmp_var()
2392 g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
2393 g.indent++
2394
2395 g.write_prepared_var(var_name, elem_type, elem_type_str, past.tmp_var, i, left_is_array, false)
2396 g.set_current_pos_as_last_stmt_pos()
2397 mut is_embed_map_filter := false
2398 lambda_autofree_tmp_arg_vars_start := g.lambda_autofree_tmp_arg_vars.len
2399 match mut expr {
2400 ast.AnonFn {
2401 g.write('if (')
2402 if expr.inherited_vars.len > 0 {
2403 g.write_closure_fn(mut expr, var_name, closure_var)
2404 } else {
2405 prev_track_anon_fn_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
2406 g.track_lambda_autofree_tmp_arg_vars = false
2407 g.gen_anon_fn_decl(mut expr)
2408 g.track_lambda_autofree_tmp_arg_vars = prev_track_anon_fn_tmp_arg_vars
2409 g.write('${expr.decl.name}(${var_name})')
2410 }
2411 }
2412 ast.Ident {
2413 g.write('if (')
2414 if expr.kind == .function {
2415 g.write('${c_name(expr.name)}(${var_name})')
2416 } else if expr.kind == .variable {
2417 var_info := expr.var_info()
2418 sym_t := g.table.sym(var_info.typ)
2419 if sym_t.kind == .function {
2420 g.write('${c_name(expr.name)}(${var_name})')
2421 } else {
2422 g.expr(expr)
2423 }
2424 } else {
2425 g.expr(expr)
2426 }
2427 }
2428 ast.CallExpr {
2429 if expr.name in ['map', 'filter', 'all', 'any', 'count'] {
2430 is_embed_map_filter = true
2431 g.set_current_pos_as_last_stmt_pos()
2432 }
2433 g.write('if (')
2434 g.expr(expr)
2435 }
2436 ast.LambdaExpr {
2437 g.write('if (')
2438 g.expr(expr.expr)
2439 }
2440 else {
2441 g.write('if (')
2442 g.expr(expr)
2443 }
2444 }
2445
2446 g.writeln2(') {', '\t++${past.tmp_var};')
2447 g.writeln('}')
2448 g.write_lambda_autofree_tmp_arg_vars(lambda_autofree_tmp_arg_vars_start)
2449 g.indent--
2450 g.writeln('}')
2451 if !is_embed_map_filter {
2452 g.set_current_pos_as_last_stmt_pos()
2453 }
2454 if has_infix_left_var_name {
2455 g.indent--
2456 g.writeln('}')
2457 g.set_current_pos_as_last_stmt_pos()
2458 }
2459}
2460
2461fn (mut g Gen) gen_array_all(node ast.CallExpr) {
2462 past := g.past_tmp_var_new()
2463 defer {
2464 g.past_tmp_var_done(past)
2465 }
2466
2467 resolved_left_type := g.resolved_array_receiver_type(node)
2468 sym := g.table.final_sym(g.unwrap_generic(resolved_left_type))
2469 left_is_array := sym.kind == .array
2470 elem_type := if left_is_array {
2471 (sym.info as ast.Array).elem_type
2472 } else {
2473 (sym.info as ast.ArrayFixed).elem_type
2474 }
2475 elem_type_str := g.styp(elem_type)
2476
2477 has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, 'bool', 'true')
2478 i := g.new_tmp_var()
2479
2480 mut expr := node.args[0].expr
2481 var_name := g.get_array_expr_param_name(mut expr)
2482 g.refresh_array_expr_param_type(expr, var_name, elem_type)
2483
2484 mut closure_var := ''
2485 if mut expr is ast.AnonFn {
2486 if expr.inherited_vars.len > 0 {
2487 closure_var = g.new_tmp_var()
2488 prev_track_closure_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
2489 g.track_lambda_autofree_tmp_arg_vars = false
2490 g.declare_closure_fn(mut expr, closure_var)
2491 g.track_lambda_autofree_tmp_arg_vars = prev_track_closure_tmp_arg_vars
2492 }
2493 }
2494
2495 g.writeln('for (${ast.int_type_name} ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
2496 g.indent++
2497 g.write_prepared_var(var_name, elem_type, elem_type_str, past.tmp_var, i, left_is_array, false)
2498 g.empty_line = true
2499 g.set_current_pos_as_last_stmt_pos()
2500 mut is_embed_map_filter := false
2501 lambda_autofree_tmp_arg_vars_start := g.lambda_autofree_tmp_arg_vars.len
2502 match mut expr {
2503 ast.AnonFn {
2504 g.write('if (!(')
2505 if expr.inherited_vars.len > 0 {
2506 g.write_closure_fn(mut expr, var_name, closure_var)
2507 } else {
2508 prev_track_anon_fn_tmp_arg_vars := g.track_lambda_autofree_tmp_arg_vars
2509 g.track_lambda_autofree_tmp_arg_vars = false
2510 g.gen_anon_fn_decl(mut expr)
2511 g.track_lambda_autofree_tmp_arg_vars = prev_track_anon_fn_tmp_arg_vars
2512 g.write('${expr.decl.name}(${var_name})')
2513 }
2514 }
2515 ast.Ident {
2516 g.write('if (!(')
2517 if expr.kind == .function {
2518 g.write('${c_name(expr.name)}(${var_name})')
2519 } else if expr.kind == .variable {
2520 var_info := expr.var_info()
2521 sym_t := g.table.sym(var_info.typ)
2522 if sym_t.kind == .function {
2523 g.write('${c_name(expr.name)}(${var_name})')
2524 } else {
2525 g.expr(expr)
2526 }
2527 } else {
2528 g.expr(expr)
2529 }
2530 }
2531 ast.CallExpr {
2532 if expr.name in ['map', 'filter', 'all', 'any', 'count'] {
2533 is_embed_map_filter = true
2534 g.set_current_pos_as_last_stmt_pos()
2535 }
2536 g.write('if (!(')
2537 g.expr(expr)
2538 }
2539 ast.LambdaExpr {
2540 g.write('if (!(')
2541 g.expr(expr.expr)
2542 }
2543 else {
2544 g.write('if (!(')
2545 g.expr(expr)
2546 }
2547 }
2548
2549 g.writeln2(')) {', '\t${past.tmp_var} = false;')
2550 g.writeln('}')
2551 g.write_lambda_autofree_tmp_arg_vars(lambda_autofree_tmp_arg_vars_start)
2552 g.writeln('if (!${past.tmp_var}) {')
2553 g.writeln('\tbreak;')
2554 g.writeln('}')
2555 g.indent--
2556 g.writeln('}')
2557 if !is_embed_map_filter {
2558 g.set_current_pos_as_last_stmt_pos()
2559 }
2560 if has_infix_left_var_name {
2561 g.indent--
2562 g.writeln('}')
2563 g.set_current_pos_as_last_stmt_pos()
2564 }
2565}
2566
2567fn (mut g Gen) resolve_array_call_left_type(node &ast.CallExpr) ast.Type {
2568 return g.unwrap_generic(g.type_resolver.get_type_or_default(node.left, node.left_type))
2569}
2570
2571fn (mut g Gen) write_prepared_tmp_value(tmp string, node &ast.CallExpr, tmp_stype string, initial_value string) bool {
2572 g.writeln('${tmp_stype} ${tmp} = ${initial_value};')
2573 has_infix_left_var_name := g.infix_left_var_name.len > 0
2574 if has_infix_left_var_name {
2575 g.writeln('if (${g.infix_left_var_name}) {')
2576 g.infix_left_var_name = ''
2577 g.indent++
2578 }
2579 resolved_left_type := g.resolved_array_receiver_type(*node)
2580 left_type := if resolved_left_type.has_flag(.shared_f) && resolved_left_type.is_ptr() {
2581 resolved_left_type.clear_flag(.shared_f).deref()
2582 } else if resolved_left_type.has_flag(.shared_f) {
2583 resolved_left_type.clear_flag(.shared_f)
2584 } else if resolved_left_type.is_ptr() {
2585 resolved_left_type.deref()
2586 } else {
2587 resolved_left_type
2588 }
2589 left_sym := g.table.final_sym(left_type)
2590 if left_sym.kind == .array {
2591 g.write('${g.styp(left_type)} ${tmp}_orig = ')
2592 if g.array_receiver_is_indirect(node.left, resolved_left_type) {
2593 g.write('*')
2594 }
2595 g.write_array_receiver(node.left)
2596 if resolved_left_type.has_flag(.shared_f) {
2597 g.write('->val')
2598 }
2599 g.writeln(';')
2600 g.writeln('${ast.int_type_name} ${tmp}_len = ${tmp}_orig.len;')
2601 } else if left_sym.kind == .array_fixed {
2602 left_info := left_sym.info as ast.ArrayFixed
2603 left_styp := g.styp(left_type)
2604 g.writeln('${left_styp} ${tmp}_orig;')
2605 g.write('memcpy(&${tmp}_orig, &')
2606 if node.left is ast.ArrayInit {
2607 g.fixed_array_init_with_cast(node.left, node.left_type)
2608 } else {
2609 if !resolved_left_type.has_flag(.shared_f) && resolved_left_type.is_ptr() {
2610 g.write('*')
2611 }
2612 g.write_array_receiver(node.left)
2613 if resolved_left_type.has_flag(.shared_f) {
2614 g.write('->val')
2615 }
2616 }
2617 g.writeln(', sizeof(${left_styp}));')
2618 g.writeln('${ast.int_type_name} ${tmp}_len = ${left_info.size};')
2619 }
2620 return has_infix_left_var_name
2621}
2622
2623fn (mut g Gen) write_prepared_var(var_name string, elem_type ast.Type, inp_elem_type string, tmp string,
2624 i string, is_array bool, auto_heap bool) {
2625 elem_sym := g.table.sym(elem_type)
2626 if is_array {
2627 if elem_sym.kind == .array_fixed {
2628 g.writeln('${inp_elem_type} ${var_name};')
2629 g.writeln('memcpy(&${var_name}, ((${inp_elem_type}*) ${tmp}_orig.data)[${i}], sizeof(${inp_elem_type}));')
2630 } else if elem_sym.kind == .function {
2631 g.writeln('voidptr ${var_name} = ((${inp_elem_type}*) ${tmp}_orig.data)[${i}];')
2632 } else {
2633 g.write('${inp_elem_type} ')
2634 if auto_heap {
2635 g.write('*')
2636 }
2637 g.write('${var_name} = ')
2638 if auto_heap {
2639 g.write('&')
2640 }
2641 g.writeln('((${inp_elem_type}*) ${tmp}_orig.data)[${i}];')
2642 }
2643 } else {
2644 if elem_sym.kind == .array_fixed {
2645 g.writeln('${inp_elem_type} ${var_name};')
2646 g.writeln('memcpy(&${var_name}, &${tmp}_orig[${i}], sizeof(${inp_elem_type}));')
2647 } else if auto_heap {
2648 g.writeln('${inp_elem_type} *${var_name} = &${tmp}_orig[${i}];')
2649 } else if elem_sym.kind == .function {
2650 g.writeln('voidptr ${var_name} = (voidptr)${tmp}_orig[${i}];')
2651 } else {
2652 g.write('${inp_elem_type} ')
2653 if auto_heap {
2654 g.write('*')
2655 }
2656 g.write('${var_name} = ')
2657 if auto_heap {
2658 g.write('&')
2659 }
2660 g.writeln('${tmp}_orig[${i}];')
2661 }
2662 }
2663}
2664
2665fn (mut g Gen) fixed_array_init_with_cast(expr ast.ArrayInit, typ ast.Type) {
2666 if g.is_cc_msvc {
2667 stmts := g.go_before_last_stmt().trim_space()
2668 tmp_var := g.new_tmp_var()
2669 g.write('${g.styp(typ)} ${tmp_var} = ')
2670 g.expr(expr)
2671 g.writeln(';')
2672 g.write2(stmts, tmp_var)
2673 } else {
2674 g.write('(${g.styp(typ)})')
2675 g.expr(expr)
2676 }
2677}
2678
2679fn (mut g Gen) fixed_array_update_expr_field(expr_str string, field_type ast.Type, field_name string, is_auto_deref bool, elem_type ast.Type, size int, is_update_embed bool) {
2680 elem_sym := g.table.sym(elem_type)
2681 if !g.inside_array_fixed_struct {
2682 g.write('{')
2683 defer(fn) {
2684 g.write('}')
2685 }
2686 }
2687 embed_field := if is_update_embed { g.get_embed_field_name(field_type, field_name) } else { '' }
2688 for i in 0 .. size {
2689 if elem_sym.info is ast.ArrayFixed {
2690 init_str := if g.inside_array_fixed_struct {
2691 '${expr_str}'
2692 } else {
2693 '${expr_str}->${embed_field}${c_name(field_name)}[${i}]'
2694 }
2695 g.fixed_array_update_expr_field(init_str, field_type, field_name, is_auto_deref,
2696 elem_sym.info.elem_type, elem_sym.info.size, is_update_embed)
2697 } else {
2698 g.write(expr_str)
2699 if !expr_str.ends_with(']') {
2700 g.write(g.dot_or_ptr(field_type))
2701 if is_update_embed {
2702 g.write(embed_field)
2703 }
2704 g.write(c_name(field_name))
2705 }
2706 g.write('[${i}]')
2707 }
2708 g.add_commas_and_prevent_long_lines(i, size)
2709 }
2710}
2711
2712fn (mut g Gen) fixed_array_var_init(expr_str string, is_auto_deref bool, elem_type ast.Type, size int) {
2713 elem_sym := g.table.final_sym(elem_type)
2714 if !g.inside_array_fixed_struct {
2715 g.write('{')
2716 defer(fn) {
2717 g.write('}')
2718 }
2719 }
2720 for i in 0 .. size {
2721 if elem_sym.info is ast.ArrayFixed {
2722 init_str := if g.inside_array_fixed_struct { '${expr_str}' } else { '${expr_str}[${i}]' }
2723 g.fixed_array_var_init(init_str, is_auto_deref, elem_sym.info.elem_type,
2724 elem_sym.info.size)
2725 } else {
2726 if is_auto_deref {
2727 g.write('(*')
2728 }
2729 g.write(expr_str)
2730 if is_auto_deref {
2731 g.write(')')
2732 }
2733 if !expr_str.starts_with('(') && !expr_str.starts_with('{') {
2734 g.write('[${i}]')
2735 }
2736 }
2737 g.add_commas_and_prevent_long_lines(i, size)
2738 }
2739}
2740
2741fn (mut g Gen) get_array_expr_param_name(mut expr ast.Expr) string {
2742 return if mut expr is ast.LambdaExpr { expr.params[0].name } else { 'it' }
2743}
2744
2745fn (mut g Gen) array_expr_param_needs_indirect_access(expr ast.Expr, var_name string) bool {
2746 return g.array_expr_param_is_auto_heap(expr, var_name)
2747 || g.array_expr_takes_param_address(expr, var_name)
2748}
2749
2750fn (mut g Gen) array_expr_param_is_auto_heap(expr ast.Expr, var_name string) bool {
2751 if var_name == '' || g.file.scope == unsafe { nil } {
2752 return false
2753 }
2754 mut scope := g.file.scope.innermost(expr.pos().pos)
2755 if scope == unsafe { nil } {
2756 scope = g.file.scope
2757 }
2758 if scope == unsafe { nil } {
2759 return false
2760 }
2761 if v := scope.find_var(var_name) {
2762 return v.is_auto_heap
2763 }
2764 return false
2765}
2766
2767fn (mut g Gen) set_array_expr_param_auto_heap(expr ast.Expr, var_name string, is_auto_heap bool) bool {
2768 if var_name == '' || g.file.scope == unsafe { nil } {
2769 return false
2770 }
2771 mut scope := g.file.scope.innermost(expr.pos().pos)
2772 if scope == unsafe { nil } {
2773 scope = g.file.scope
2774 }
2775 if scope == unsafe { nil } {
2776 return false
2777 }
2778 if mut v := scope.find_var(var_name) {
2779 old_is_auto_heap := v.is_auto_heap
2780 v.is_auto_heap = is_auto_heap
2781 return old_is_auto_heap
2782 }
2783 return false
2784}
2785
2786fn (mut g Gen) array_expr_takes_param_address(expr ast.Expr, var_name string) bool {
2787 match expr {
2788 ast.AsCast {
2789 return g.array_expr_takes_param_address(expr.expr, var_name)
2790 }
2791 ast.CallExpr {
2792 if g.array_expr_takes_param_address(expr.left, var_name) {
2793 return true
2794 }
2795 for arg in expr.args {
2796 if g.array_expr_takes_param_address(arg.expr, var_name) {
2797 return true
2798 }
2799 }
2800 return false
2801 }
2802 ast.CastExpr {
2803 return g.array_expr_takes_param_address(expr.expr, var_name)
2804 }
2805 ast.IndexExpr {
2806 return g.array_expr_takes_param_address(expr.left, var_name)
2807 || g.array_expr_takes_param_address(expr.index, var_name)
2808 }
2809 ast.InfixExpr {
2810 return g.array_expr_takes_param_address(expr.left, var_name)
2811 || g.array_expr_takes_param_address(expr.right, var_name)
2812 }
2813 ast.LambdaExpr {
2814 return g.array_expr_takes_param_address(expr.expr, var_name)
2815 }
2816 ast.ParExpr {
2817 return g.array_expr_takes_param_address(expr.expr, var_name)
2818 }
2819 ast.PostfixExpr {
2820 return g.array_expr_takes_param_address(expr.expr, var_name)
2821 }
2822 ast.PrefixExpr {
2823 if expr.op == .amp && g.array_expr_roots_at_param(expr.right, var_name) {
2824 return true
2825 }
2826 return g.array_expr_takes_param_address(expr.right, var_name)
2827 }
2828 ast.SelectorExpr {
2829 return g.array_expr_takes_param_address(expr.expr, var_name)
2830 }
2831 else {
2832 return false
2833 }
2834 }
2835}
2836
2837fn (mut g Gen) array_expr_roots_at_param(expr ast.Expr, var_name string) bool {
2838 mut root := expr
2839 for {
2840 mut next_root := root
2841 if mut root is ast.ParExpr {
2842 next_root = root.expr
2843 } else {
2844 break
2845 }
2846 root = next_root
2847 }
2848 match mut root {
2849 ast.AsCast {
2850 return g.array_expr_roots_at_param(root.expr, var_name)
2851 }
2852 ast.CastExpr {
2853 return g.array_expr_roots_at_param(root.expr, var_name)
2854 }
2855 ast.Ident {
2856 return root.name == var_name
2857 }
2858 ast.IndexExpr {
2859 return g.array_expr_roots_at_param(root.left, var_name)
2860 }
2861 ast.PostfixExpr {
2862 return g.array_expr_roots_at_param(root.expr, var_name)
2863 }
2864 ast.SelectorExpr {
2865 return g.array_expr_roots_at_param(root.expr, var_name)
2866 }
2867 else {
2868 return false
2869 }
2870 }
2871}
2872
2873fn (mut g Gen) refresh_array_expr_param_type(expr ast.Expr, var_name string, elem_type ast.Type) {
2874 if var_name == '' || elem_type == 0 || g.file.scope == unsafe { nil } {
2875 return
2876 }
2877 mut scope := g.file.scope.innermost(expr.pos().pos)
2878 if scope == unsafe { nil } {
2879 scope = g.file.scope
2880 }
2881 if scope == unsafe { nil } {
2882 return
2883 }
2884 if mut v := scope.find_var(var_name) {
2885 v.typ = g.unwrap_generic(g.recheck_concrete_type(elem_type))
2886 v.orig_type = ast.no_type
2887 v.smartcasts = []
2888 v.is_unwrapped = false
2889 g.clear_type_resolution_caches()
2890 }
2891}
2892
2893const wrap_at_array_element = 0x0F
2894
2895fn (mut g Gen) add_commas_and_prevent_long_lines(i int, len int) {
2896 if i != len - 1 {
2897 g.write(', ')
2898 }
2899 // ensure there is a new line at least once per 16 array elements,
2900 // to prevent too long lines to cause problems with gcc < gcc-11
2901 if i & wrap_at_array_element == wrap_at_array_element && len - i > wrap_at_array_element {
2902 g.writeln('')
2903 }
2904}
2905
2906@[inline]
2907fn (mut g Gen) can_use_c99_designators() bool {
2908 // see https://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Designated-Inits.html
2909 // TODO: all compilers should get the same code, when they really support C99..
2910 return !g.is_cc_msvc && !g.pref.output_cross_c
2911}
2912
2913fn (mut g Gen) write_all_n_elements_for_array(len int, value string) {
2914 for i in 0 .. len {
2915 g.write(value)
2916 g.add_commas_and_prevent_long_lines(i, len)
2917 }
2918}
2919
2920fn (mut g Gen) write_c99_elements_for_array(len int, value string) {
2921 if len == 0 {
2922 return
2923 }
2924 if g.can_use_c99_designators() {
2925 if value in ['0', '{0}', '((u8)(0))', '{((u8)(0))}', '((u32)(0))', '{((u32)(0))}'] {
2926 // zeros are fine for all compilers
2927 g.write('0')
2928 return
2929 }
2930 // TODO remove this check for != gcc, when this works:
2931 // `screen_pixels [nb_tiles][nb_tiles]u32 = [nb_tiles][nb_tiles]u32{init: [nb_tiles]u32{init: u32(white)}}`
2932 // i.e. when `white` as a constant can be handled by gcc without this error:
2933 // `array initialized from non-constant array expression` error, or when `white` is substituted here with its number value.
2934 if len > $d('cgen_c99_cutoff_limit', 64) {
2935 if g.pref.ccompiler_type != .gcc {
2936 if !value.contains('){.') {
2937 // Currently, it is generating this, which works with clang and tcc, but not gcc: ` [0 ... 679] = ((u32)(_const_main__white)) `
2938 g.write(' [0 ... ${len - 1}] = ${value} ')
2939 return
2940 }
2941 }
2942 }
2943 }
2944 g.write_all_n_elements_for_array(len, value)
2945}
2946
2947@[inline]
2948fn (mut g Gen) write_c99_0_elements_for_array(len int) {
2949 if g.can_use_c99_designators() {
2950 g.write('0')
2951 return
2952 }
2953 g.write_all_n_elements_for_array(len, '0')
2954}
2955