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