vxx2 / vlib / v3 / transform / array.v
1505 lines · 1448 sloc · 53.61 KB · 2b81918e62db9ab38787518603a7f93bee80868c
Raw
1module transform
2
3import v3.flat
4import v3.types
5
6// make_array_new_call builds make array new call data for transform.
7fn (mut t Transformer) make_array_new_call(elem_type string, len_expr flat.NodeId, cap_expr flat.NodeId) flat.NodeId {
8 return t.make_call_typed('array_new', arr3(t.make_sizeof_type(elem_type), len_expr, cap_expr),
9 '[]${elem_type}')
10}
11
12fn (mut t Transformer) try_lower_array_repeat_call(_id flat.NodeId, node flat.Node) ?flat.NodeId {
13 if node.children_count != 2 {
14 return none
15 }
16 fn_id := t.a.child(&node, 0)
17 fn_node := t.a.nodes[int(fn_id)]
18 if fn_node.kind != .selector || fn_node.value != 'repeat' || fn_node.children_count == 0 {
19 return none
20 }
21 base_id := t.a.child(&fn_node, 0)
22 base_type := t.node_type(base_id)
23 count_id := t.a.child(&node, 1)
24 if expanded := t.try_expand_interface_array_literal_repeat(base_id, count_id, base_type) {
25 return expanded
26 }
27 depth := array_repeat_clone_depth(base_type)
28 if depth == 0 {
29 return none
30 }
31 base := t.transform_expr(base_id)
32 count := t.transform_expr(count_id)
33 selector := t.make_selector(base, 'repeat_to_depth', '')
34 return t.make_call_expr_typed(selector, arr2(count, t.make_int_literal(depth)), node.typ)
35}
36
37fn (mut t Transformer) try_expand_interface_array_literal_repeat(base_id flat.NodeId, count_id flat.NodeId, base_type string) ?flat.NodeId {
38 if !base_type.starts_with('[]') {
39 return none
40 }
41 elem_type := base_type[2..]
42 if elem_type !in t.tc.interface_names && t.tc.qualify_name(elem_type) !in t.tc.interface_names {
43 return none
44 }
45 base := t.a.nodes[int(base_id)]
46 count_node := t.a.nodes[int(count_id)]
47 if base.kind != .array_literal || count_node.kind != .int_literal {
48 return none
49 }
50 count := count_node.value.int()
51 if count < 0 || count > 32 {
52 return none
53 }
54 if !t.array_repeat_literal_can_duplicate(base) {
55 return none
56 }
57 mut values := []flat.NodeId{cap: int(base.children_count) * count}
58 for _ in 0 .. count {
59 for i in 0 .. base.children_count {
60 values << t.a.child(&base, i)
61 }
62 }
63 lit := t.make_array_literal_typed(values, base_type)
64 return t.transform_array_literal(lit, t.a.nodes[int(lit)])
65}
66
67fn (t &Transformer) array_repeat_literal_can_duplicate(node flat.Node) bool {
68 for i in 0 .. node.children_count {
69 if !t.array_repeat_expr_can_duplicate(t.a.child(&node, i)) {
70 return false
71 }
72 }
73 return true
74}
75
76fn (t &Transformer) array_repeat_expr_can_duplicate(id flat.NodeId) bool {
77 node := t.a.nodes[int(id)]
78 match node.kind {
79 .int_literal, .float_literal, .bool_literal, .char_literal, .string_literal, .ident,
80 .enum_val, .nil_literal, .none_expr {
81 return true
82 }
83 .paren, .prefix, .postfix, .cast_expr, .as_expr, .field_init, .array_literal, .struct_init {
84 for i in 0 .. node.children_count {
85 if !t.array_repeat_expr_can_duplicate(t.a.child(&node, i)) {
86 return false
87 }
88 }
89 return true
90 }
91 else {
92 return false
93 }
94 }
95}
96
97fn array_repeat_clone_depth(typ string) int {
98 mut clean := typ
99 if clean.starts_with('&') {
100 clean = clean[1..]
101 }
102 mut depth := 0
103 for clean.starts_with('[]') {
104 depth++
105 clean = clean[2..]
106 }
107 if depth <= 1 {
108 return 0
109 }
110 return depth - 1
111}
112
113fn array_nested_eq_depth(typ string) int {
114 mut clean := typ
115 if clean.starts_with('&') {
116 clean = clean[1..]
117 }
118 mut depth := 0
119 for clean.starts_with('[]') {
120 depth++
121 clean = clean[2..]
122 }
123 if depth <= 1 {
124 return 1
125 }
126 return depth
127}
128
129fn (mut t Transformer) make_array_push_many_call(lhs_addr flat.NodeId, rhs flat.NodeId, rhs_type string) flat.NodeId {
130 t.mark_fn_used('array__push_many')
131 rhs_value := t.stable_transformed_expr_for_reuse(rhs, rhs_type, 'push_many')
132 return t.make_call_typed('array__push_many', arr3(lhs_addr, t.make_selector(rhs_value, 'data',
133 'voidptr'), t.make_selector(rhs_value, 'len', 'int')), 'void')
134}
135
136fn (mut t Transformer) make_array_insert_many_call(lhs_addr flat.NodeId, index flat.NodeId, rhs flat.NodeId, rhs_type string) flat.NodeId {
137 if t.is_fixed_array_type(rhs_type) {
138 return t.make_call_typed('array__insert_many', arr4(lhs_addr, index, rhs,
139 t.make_fixed_array_len_expr(rhs_type)), 'void')
140 }
141 rhs_value := t.stable_transformed_expr_for_reuse(rhs, rhs_type, 'insert_many')
142 return t.make_call_typed('array__insert_many', arr4(lhs_addr, index, t.make_selector(rhs_value,
143 'data', 'voidptr'), t.make_selector(rhs_value, 'len', 'int')), 'void')
144}
145
146fn (mut t Transformer) make_array_clone_call(base_id flat.NodeId, base_type string) flat.NodeId {
147 t.mark_fn_used('array__clone')
148 receiver := t.transform_expr(base_id)
149 return t.make_array_clone_value(receiver, base_type)
150}
151
152fn (mut t Transformer) make_array_clone_value(receiver flat.NodeId, base_type string) flat.NodeId {
153 clean_type := if base_type.starts_with('&') { base_type[1..] } else { base_type }
154 depth := array_repeat_clone_depth(clean_type)
155 if depth > 0 {
156 return t.make_call_typed('array__clone_to_depth', arr2(t.runtime_addr(receiver, base_type),
157 t.make_int_literal(depth)), clean_type)
158 }
159 return t.make_call_typed('array__clone', arr1(t.runtime_addr(receiver, base_type)), clean_type)
160}
161
162// lower_array_init_to_runtime converts lower array init to runtime data for transform.
163fn (mut t Transformer) lower_array_init_to_runtime(id flat.NodeId, node flat.Node) flat.NodeId {
164 if node.value.len == 0 || t.is_fixed_array_type(node.value) {
165 return id
166 }
167 elem_type := node.value
168 mut len_expr := t.make_int_literal(0)
169 mut cap_expr := t.make_int_literal(0)
170 mut init_expr := flat.empty_node
171 for i in 0 .. node.children_count {
172 child := t.a.child_node(&node, i)
173 if child.kind == .field_init && child.children_count > 0 {
174 val := t.transform_expr(t.a.child(child, 0))
175 if child.value == 'len' {
176 len_expr = val
177 } else if child.value == 'cap' {
178 cap_expr = val
179 } else if child.value == 'init' {
180 init_expr = val
181 }
182 }
183 }
184 new_call := t.make_array_new_call(elem_type, len_expr, cap_expr)
185 if int(init_expr) < 0 {
186 clean_elem_type := t.normalize_type_alias(elem_type)
187 if clean_elem_type.starts_with('[]') {
188 init_expr = t.make_array_new_call(clean_elem_type[2..], t.make_int_literal(0),
189 t.make_int_literal(0))
190 } else if default_value := t.make_struct_runtime_default_value(clean_elem_type) {
191 init_expr = default_value
192 } else {
193 return new_call
194 }
195 }
196 tmp_name := t.new_temp('arr_init')
197 idx_name := t.new_temp('arr_idx')
198 t.pending_stmts << t.make_decl_assign_typed(tmp_name, new_call, '[]${elem_type}')
199 init_idx := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
200 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(t.make_ident(tmp_name),
201 'len', 'int'))
202 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
203 elem_lhs := t.make_index(t.make_ident(tmp_name), t.make_ident(idx_name), elem_type)
204 // `init:` expressions may reference the magic `index` variable, which V binds to
205 // the current element index. Declare it inside the loop body so it resolves to the
206 // generated loop counter instead of leaking to an external symbol (e.g. libc `index`).
207 index_decl := t.make_decl_assign_typed('index', t.make_ident(idx_name), 'int')
208 mut loop_body := []flat.NodeId{}
209 loop_body << index_decl
210 mut assign_value := init_expr
211 clean_elem_type := t.normalize_type_alias(elem_type)
212 if clean_elem_type.starts_with('[]') {
213 if !t.expr_can_take_address(assign_value) {
214 value_name := t.new_temp('arr_init_val')
215 loop_body << t.make_decl_assign_typed(value_name, assign_value, clean_elem_type)
216 assign_value = t.make_ident(value_name)
217 }
218 assign_value = t.make_array_clone_value(assign_value, clean_elem_type)
219 }
220 assign := t.make_assign(elem_lhs, assign_value)
221 loop_body << assign
222 t.pending_stmts << t.make_for_stmt(init_idx, cond, post, loop_body, node)
223 result := t.make_ident(tmp_name)
224 t.a.nodes[int(result)].typ = '[]${elem_type}'
225 return result
226}
227
228fn (mut t Transformer) make_struct_runtime_default_value(struct_type string) ?flat.NodeId {
229 info := t.lookup_struct_info(struct_type) or { return none }
230 mut field_ids := []flat.NodeId{}
231 for field in info.fields {
232 field_type := if field.typ.len > 0 { field.typ } else { field.raw_typ }
233 clean_type := t.normalize_type_alias(field_type)
234 mut value := flat.empty_node
235 if clean_type.starts_with('map[') || clean_type.starts_with('[]') {
236 value = t.zero_value_for_type(clean_type)
237 } else if nested := t.make_struct_runtime_default_value(clean_type) {
238 value = nested
239 }
240 if int(value) < 0 {
241 continue
242 }
243 start := t.a.children.len
244 t.a.children << value
245 field_ids << t.a.add_node(flat.Node{
246 kind: .field_init
247 children_start: start
248 children_count: 1
249 value: field.name
250 typ: field_type
251 })
252 }
253 if field_ids.len == 0 {
254 return none
255 }
256 start := t.a.children.len
257 for field_id in field_ids {
258 t.a.children << field_id
259 }
260 return t.a.add_node(flat.Node{
261 kind: .struct_init
262 children_start: start
263 children_count: flat.child_count(field_ids.len)
264 value: struct_type
265 typ: struct_type
266 })
267}
268
269// lower_array_literal_to_runtime converts lower array literal to runtime data for transform.
270fn (mut t Transformer) lower_array_literal_to_runtime(id flat.NodeId, node flat.Node) flat.NodeId {
271 array_type := if checker_alias_type := t.array_literal_checker_alias_type(id) {
272 checker_alias_type
273 } else if alias_type := t.array_literal_alias_type(node) {
274 alias_type
275 } else {
276 t.node_type(id)
277 }
278 if !array_type.starts_with('[]') {
279 return id
280 }
281 elem_type := array_type[2..]
282 tmp_name := t.new_temp('arr_lit')
283 t.pending_stmts << t.make_decl_assign_typed(tmp_name, t.make_array_new_call(elem_type,
284 t.make_int_literal(0), t.make_int_literal(node.children_count)), array_type)
285 for i in 0 .. node.children_count {
286 elem_id := t.a.child(&node, i)
287 elem := t.a.nodes[int(elem_id)]
288 if elem.kind == .prefix && elem.value == '...' && elem.children_count > 0 {
289 spread_id := t.a.child(&elem, 0)
290 spread := t.transform_expr(spread_id)
291 spread_type := if t.node_type(spread_id).len > 0 {
292 t.node_type(spread_id)
293 } else {
294 array_type
295 }
296 call := t.make_array_push_many_call(t.make_prefix(.amp, t.make_ident(tmp_name)),
297 spread, spread_type)
298 t.pending_stmts << t.make_expr_stmt(call)
299 continue
300 }
301 value_name := t.new_temp('arr_val')
302 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
303 t.wrap_sum_value(elem_id, elem_type)
304 } else {
305 t.transform_expr_for_type(elem_id, elem_type)
306 }
307 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
308 call := t.make_call_typed('array_push', arr2(t.make_prefix(.amp, t.make_ident(tmp_name)), t.make_prefix(.amp,
309 t.make_ident(value_name))), 'void')
310 t.pending_stmts << t.make_expr_stmt(call)
311 }
312 result := t.make_ident(tmp_name)
313 t.a.nodes[int(result)].typ = array_type
314 return result
315}
316
317fn (t &Transformer) array_literal_checker_alias_type(id flat.NodeId) ?string {
318 if isnil(t.tc) || int(id) < 0 {
319 return none
320 }
321 typ := t.tc.expr_type(id) or { t.tc.resolve_type(id) }
322 name := typ.name()
323 if !name.starts_with('[]') {
324 return none
325 }
326 elem := name[2..]
327 if !t.generic_arg_is_alias_name(elem, t.cur_module) {
328 return none
329 }
330 return '[]${elem.all_after_last('.')}'
331}
332
333fn (t &Transformer) array_literal_alias_type(node flat.Node) ?string {
334 if node.kind != .array_literal || node.children_count == 0 {
335 return none
336 }
337 first_id := t.a.child(&node, 0)
338 first := t.a.nodes[int(first_id)]
339 mut alias_name := ''
340 if first.kind in [.cast_expr, .as_expr] && first.value.len > 0 {
341 alias_name = first.value
342 } else if first.kind == .call && first.children_count > 0 {
343 callee := t.a.child_node(&first, 0)
344 if callee.kind == .ident {
345 alias_name = callee.value
346 }
347 }
348 if alias_name.len == 0 {
349 return none
350 }
351 if !t.generic_arg_is_alias_name(alias_name, t.cur_module) {
352 return none
353 }
354 return '[]${alias_name}'
355}
356
357// transform_array_literal_for_type transforms transform array literal for type data for transform.
358fn (mut t Transformer) transform_array_literal_for_type(id flat.NodeId, node flat.Node, target_type string) ?flat.NodeId {
359 array_type := if checker_alias_type := t.array_literal_checker_alias_type(id) {
360 checker_alias_type
361 } else if alias_type := t.array_literal_alias_type(node) {
362 alias_type
363 } else {
364 t.normalize_type_alias(target_type)
365 }
366 if !array_type.starts_with('[]') {
367 return none
368 }
369 elem_type := array_type[2..]
370 tmp_name := t.new_temp('arr_lit')
371 t.pending_stmts << t.make_decl_assign_typed(tmp_name, t.make_array_new_call(elem_type,
372 t.make_int_literal(0), t.make_int_literal(node.children_count)), array_type)
373 for i in 0 .. node.children_count {
374 elem_id := t.a.child(&node, i)
375 elem := t.a.nodes[int(elem_id)]
376 if elem.kind == .prefix && elem.value == '...' && elem.children_count > 0 {
377 spread := t.transform_expr_for_type(t.a.child(&elem, 0), array_type)
378 call := t.make_array_push_many_call(t.make_prefix(.amp, t.make_ident(tmp_name)),
379 spread, array_type)
380 t.pending_stmts << t.make_expr_stmt(call)
381 continue
382 }
383 value_name := t.new_temp('arr_val')
384 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
385 t.wrap_sum_value(elem_id, elem_type)
386 } else {
387 t.transform_expr_for_type(elem_id, elem_type)
388 }
389 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
390 call := t.make_call_typed('array_push', arr2(t.make_prefix(.amp, t.make_ident(tmp_name)), t.make_prefix(.amp,
391 t.make_ident(value_name))), 'void')
392 t.pending_stmts << t.make_expr_stmt(call)
393 }
394 result := t.make_ident(tmp_name)
395 t.a.nodes[int(result)].typ = array_type
396 return result
397}
398
399fn (mut t Transformer) transform_fixed_array_literal_for_type(_id flat.NodeId, node flat.Node, target_type string) ?flat.NodeId {
400 fixed_type := t.normalize_type_alias(target_type)
401 if !t.is_fixed_array_type(fixed_type) {
402 return none
403 }
404 elem_type := fixed_array_elem_type(fixed_type)
405 mut values := []flat.NodeId{cap: int(node.children_count)}
406 for i in 0 .. node.children_count {
407 elem_id := t.a.child(&node, i)
408 values << t.transform_expr_for_type(elem_id, elem_type)
409 }
410 return t.make_array_literal_typed(values, fixed_type)
411}
412
413fn (mut t Transformer) transform_fixed_array_init_expr(node flat.Node) ?flat.NodeId {
414 fixed_type := t.normalize_type_alias(if node.value.len > 0 { node.value } else { node.typ })
415 if !t.is_fixed_array_type(fixed_type) || node.children_count == 0 {
416 return none
417 }
418 len_text := fixed_array_len_text(fixed_type)
419 len := if is_decimal_text(len_text) {
420 len_text.int()
421 } else if !isnil(t.tc) {
422 t.tc.const_int_value_in_module(len_text, t.cur_module, []string{}) or { return none }
423 } else {
424 return none
425 }
426 mut init_id := flat.empty_node
427 for i in 0 .. node.children_count {
428 child_id := t.a.child(&node, i)
429 child := t.a.nodes[int(child_id)]
430 if child.kind == .field_init && child.value == 'init' && child.children_count > 0 {
431 init_id = t.a.child(&child, 0)
432 break
433 }
434 }
435 if int(init_id) < 0 {
436 return none
437 }
438 elem_type := fixed_array_elem_type(fixed_type)
439 mut values := []flat.NodeId{cap: len}
440 for i in 0 .. len {
441 indexed_init := t.substitute_ident_expr(init_id, 'index', t.make_int_literal(i))
442 values << t.transform_expr_for_type(indexed_init, elem_type)
443 }
444 return t.make_array_literal_typed(values, fixed_type)
445}
446
447// transform_empty_array_init_for_type supports transform_empty_array_init_for_type handling.
448fn (mut t Transformer) transform_empty_array_init_for_type(node flat.Node, target_type string) ?flat.NodeId {
449 if node.value.len > 0 || node.children_count > 0 {
450 return none
451 }
452 array_type := t.normalize_type_alias(target_type)
453 if !array_type.starts_with('[]') {
454 return none
455 }
456 elem_type := array_type[2..]
457 return t.make_array_new_call(elem_type, t.make_int_literal(0), t.make_int_literal(0))
458}
459
460// try_lower_array_append_stmt supports try lower array append stmt handling for Transformer.
461fn (mut t Transformer) try_lower_array_append_stmt(id flat.NodeId) ?[]flat.NodeId {
462 if int(id) < 0 {
463 return none
464 }
465 node := t.a.nodes[int(id)]
466 if node.kind != .infix || node.op != .left_shift || node.children_count < 2 {
467 return none
468 }
469 lhs_id := t.a.child(&node, 0)
470 mut lhs_type := t.lvalue_type(lhs_id)
471 if !array_type_has_generic_placeholder(lhs_type) {
472 lhs_type = t.normalize_type_alias(lhs_type)
473 }
474 mut array_type := t.clean_array_append_lhs_type(lhs_type)
475 if !array_type.starts_with('[]') {
476 return none
477 }
478 elem_type := array_type[2..]
479 rhs_id := t.a.child(&node, 1)
480 mut rhs_type := t.normalize_type_alias(t.node_type(rhs_id))
481 rhs_node := t.a.nodes[int(rhs_id)]
482 mut push_many := t.array_append_rhs_is_push_many(lhs_id, rhs_id, rhs_type, elem_type)
483 if rhs_node.kind == .array_literal && !elem_type.starts_with('[]')
484 && !t.is_fixed_array_type(elem_type) {
485 // `[]scalar << [a, b, c]` always appends the literal's elements. Retype the
486 // literal from the destination so a mis-inferred element type (e.g. `[]int`
487 // for `[f32_expr, ..]`) is corrected and the append stays a clean push_many,
488 // instead of degrading to a single push of the whole array. (An array-typed
489 // element is genuinely ambiguous, so leave that to the inferred decision.)
490 push_many = true
491 t.a.nodes[int(rhs_id)].typ = array_type
492 rhs_type = array_type
493 } else if push_many && rhs_node.kind == .array_literal && !rhs_type.starts_with('[]') {
494 t.a.nodes[int(rhs_id)].typ = array_type
495 rhs_type = array_type
496 }
497
498 mut result := []flat.NodeId{}
499 lhs := t.transform_lvalue(lhs_id)
500 t.drain_pending(mut result)
501 mut rhs := if !push_many
502 && (elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types) {
503 t.wrap_sum_value(rhs_id, elem_type)
504 } else {
505 t.transform_expr(rhs_id)
506 }
507 if !push_many {
508 rhs = t.coerce_transformed_expr_to_type(rhs, rhs_id, elem_type)
509 }
510 t.drain_pending(mut result)
511 if rhs_type.len == 0 {
512 rhs_type = t.node_type(rhs)
513 push_many = t.array_append_rhs_is_push_many(lhs_id, rhs_id, rhs_type, elem_type)
514 }
515
516 lhs_addr := t.runtime_addr(lhs, lhs_type)
517 if push_many {
518 call := if t.is_fixed_array_type(rhs_type) {
519 t.make_call_typed('array_push_many_ptr', arr3(lhs_addr, rhs,
520 t.make_fixed_array_len_expr(rhs_type)), 'void')
521 } else {
522 t.make_array_push_many_call(lhs_addr, rhs, rhs_type)
523 }
524 result << t.make_expr_stmt(call)
525 return result
526 }
527 value_name := t.new_temp('arr_val')
528 result << t.make_decl_assign_typed(value_name, rhs, elem_type)
529 result << t.make_expr_stmt(t.make_call_typed('array_push', arr2(lhs_addr, t.make_prefix(.amp,
530 t.make_ident(value_name))), 'void'))
531 return result
532}
533
534// clean_array_append_lhs_type transforms clean array append lhs type data for transform.
535fn (t &Transformer) clean_array_append_lhs_type(typ string) string {
536 mut clean := if array_type_has_generic_placeholder(typ) {
537 typ.trim_space()
538 } else {
539 t.normalize_type_alias(typ).trim_space()
540 }
541 for {
542 if clean.starts_with('&') {
543 clean = clean[1..].trim_space()
544 continue
545 }
546 if clean.starts_with('shared ') {
547 clean = clean[7..].trim_space()
548 continue
549 }
550 if clean.starts_with('atomic ') {
551 clean = clean[7..].trim_space()
552 continue
553 }
554 break
555 }
556 return clean
557}
558
559fn array_type_has_generic_placeholder(typ string) bool {
560 clean := typ.trim_space()
561 if clean.len == 0 {
562 return false
563 }
564 if is_generic_placeholder_type_name(clean) {
565 return true
566 }
567 if clean.starts_with('&') {
568 return array_type_has_generic_placeholder(clean[1..])
569 }
570 if clean.starts_with('[]') {
571 return array_type_has_generic_placeholder(clean[2..])
572 }
573 if clean.starts_with('map[') {
574 bracket_end := clean.index(']') or { return false }
575 return array_type_has_generic_placeholder(clean[4..bracket_end])
576 || array_type_has_generic_placeholder(clean[bracket_end + 1..])
577 }
578 if clean.starts_with('[') {
579 bracket_end := clean.index(']') or { return false }
580 return array_type_has_generic_placeholder(clean[bracket_end + 1..])
581 }
582 return false
583}
584
585// lower_array_prepend_call builds lower array prepend call data for transform.
586fn (mut t Transformer) lower_array_prepend_call(node flat.Node, fn_node flat.Node, base_type string, elem_type string) ?flat.NodeId {
587 if node.children_count < 2 || fn_node.children_count == 0 {
588 return none
589 }
590 base_id := t.a.child(&fn_node, 0)
591 value_id := t.a.child(&node, 1)
592 mut rhs_type := t.normalize_type_alias(t.node_type(value_id))
593 value_node := t.a.nodes[int(value_id)]
594 mut prepend_many := t.array_append_rhs_is_push_many(base_id, value_id, rhs_type, elem_type)
595 if value_node.kind == .array_literal && !elem_type.starts_with('[]')
596 && !t.is_fixed_array_type(elem_type) {
597 prepend_many = true
598 t.a.nodes[int(value_id)].typ = base_type
599 rhs_type = base_type
600 } else if prepend_many && value_node.kind == .array_literal && !rhs_type.starts_with('[]') {
601 t.a.nodes[int(value_id)].typ = base_type
602 rhs_type = base_type
603 }
604 base := t.transform_lvalue(base_id)
605 if prepend_many {
606 value := t.transform_expr(value_id)
607 return t.make_array_insert_many_call(t.runtime_addr(base, base_type),
608 t.make_int_literal(0), value, rhs_type)
609 }
610 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
611 t.wrap_sum_value(value_id, elem_type)
612 } else {
613 t.transform_expr_for_type(value_id, elem_type)
614 }
615 value_name := t.new_temp('arr_val')
616 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
617 t.mark_fn_used('array__prepend')
618 t.mark_fn_used('array__insert')
619 t.mark_fn_used('array__needs_unique_shift')
620 return t.make_call_typed('array__prepend', arr2(t.runtime_addr(base, base_type), t.make_prefix(.amp,
621 t.make_ident(value_name))), 'void')
622}
623
624// lower_array_insert_call builds lower array insert call data for transform.
625fn (mut t Transformer) lower_array_insert_call(node flat.Node, fn_node flat.Node, base_type string, elem_type string) ?flat.NodeId {
626 if node.children_count < 3 || fn_node.children_count == 0 {
627 return none
628 }
629 base_id := t.a.child(&fn_node, 0)
630 index_id := t.a.child(&node, 1)
631 value_id := t.a.child(&node, 2)
632 mut rhs_type := t.normalize_type_alias(t.node_type(value_id))
633 value_node := t.a.nodes[int(value_id)]
634 mut insert_many := t.array_append_rhs_is_push_many(base_id, value_id, rhs_type, elem_type)
635 if value_node.kind == .array_literal && !elem_type.starts_with('[]')
636 && !t.is_fixed_array_type(elem_type) {
637 insert_many = true
638 t.a.nodes[int(value_id)].typ = base_type
639 rhs_type = base_type
640 } else if insert_many && value_node.kind == .array_literal && !rhs_type.starts_with('[]') {
641 t.a.nodes[int(value_id)].typ = base_type
642 rhs_type = base_type
643 }
644 base := t.transform_lvalue(base_id)
645 index := t.transform_expr_for_type(index_id, 'int')
646 if insert_many {
647 value := t.transform_expr(value_id)
648 return t.make_array_insert_many_call(t.runtime_addr(base, base_type), index, value,
649 rhs_type)
650 }
651 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
652 t.wrap_sum_value(value_id, elem_type)
653 } else {
654 t.transform_expr_for_type(value_id, elem_type)
655 }
656 value_name := t.new_temp('arr_val')
657 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
658 t.mark_fn_used('array__insert')
659 t.mark_fn_used('array__needs_unique_shift')
660 return t.make_call_typed('array__insert', arr3(t.runtime_addr(base, base_type), index, t.make_prefix(.amp,
661 t.make_ident(value_name))), 'void')
662}
663
664fn (mut t Transformer) lower_array_push_many_call(node flat.Node, fn_node flat.Node, base_type string, elem_type string) ?flat.NodeId {
665 if node.children_count < 3 || fn_node.children_count == 0 {
666 return none
667 }
668 base_id := t.a.child(&fn_node, 0)
669 value_id := t.a.child(&node, 1)
670 count_id := t.a.child(&node, 2)
671 base := t.transform_lvalue(base_id)
672 base_addr := t.runtime_addr(base, base_type)
673 t.mark_fn_used('array__push_many')
674 if t.push_many_count_is_type_name(count_id) {
675 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
676 t.wrap_sum_value(value_id, elem_type)
677 } else {
678 t.transform_expr_for_type(value_id, elem_type)
679 }
680 value_name := t.new_temp('arr_val')
681 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
682 return t.make_call_typed('array_push_many_ptr', arr3(base_addr, t.make_prefix(.amp,
683 t.make_ident(value_name)), t.make_int_literal(1)), 'void')
684 }
685 value := t.transform_expr(value_id)
686 count := t.transform_expr_for_type(count_id, 'int')
687 return t.make_call_typed('array_push_many_ptr', arr3(base_addr, value, count), 'void')
688}
689
690fn (t &Transformer) push_many_count_is_type_name(id flat.NodeId) bool {
691 if int(id) < 0 {
692 return false
693 }
694 node := t.a.nodes[int(id)]
695 return node.kind == .ident && node.value.len > 0 && node.value[0] >= `A` && node.value[0] <= `Z`
696}
697
698// array_append_rhs_is_push_many supports array append rhs is push many handling for Transformer.
699fn (t &Transformer) array_append_rhs_is_push_many(lhs_id flat.NodeId, rhs_id flat.NodeId, rhs_type string, elem_type string) bool {
700 clean_rhs_type := rhs_type.trim_space()
701 if clean_rhs_type.starts_with('...') {
702 return t.array_append_elem_types_match(clean_rhs_type[3..], elem_type)
703 }
704 if clean_rhs_type.starts_with('[]') {
705 if t.array_append_elem_types_match(clean_rhs_type[2..], elem_type) {
706 return true
707 }
708 if declared_rhs_type := t.array_append_ident_type(rhs_id) {
709 if declared_rhs_type.starts_with('...') {
710 return t.array_append_elem_types_match(declared_rhs_type[3..], elem_type)
711 }
712 if declared_rhs_type.starts_with('[]') {
713 return t.array_append_elem_types_match(declared_rhs_type[2..], elem_type)
714 }
715 }
716 return false
717 }
718 if t.is_fixed_array_type(clean_rhs_type) {
719 return t.array_append_elem_types_match(fixed_array_elem_type(clean_rhs_type), elem_type)
720 }
721 if !isnil(t.tc) {
722 if rhs_resolved := t.tc.expr_type(rhs_id) {
723 rhs_clean := types.unwrap_pointer(rhs_resolved)
724 if rhs_clean is types.Array {
725 return t.array_append_elem_types_match(rhs_clean.elem_type.name(), elem_type)
726 }
727 if rhs_clean is types.ArrayFixed {
728 return t.array_append_elem_types_match(rhs_clean.elem_type.name(), elem_type)
729 }
730 }
731 if lhs_resolved := t.tc.expr_type(lhs_id) {
732 lhs_clean := types.unwrap_pointer(lhs_resolved)
733 if lhs_clean is types.Array && clean_rhs_type in ['array', 'Array'] {
734 return t.tc.c_type(lhs_clean.elem_type) == 'void*'
735 }
736 }
737 }
738 if clean_rhs_type in ['array', 'Array'] {
739 return t.array_append_elem_c_type(elem_type) !in ['array', 'Array']
740 }
741 return false
742}
743
744// array_append_elem_types_match supports array append elem types match handling for Transformer.
745fn (t &Transformer) array_append_elem_types_match(rhs_elem_type string, lhs_elem_type string) bool {
746 rhs_raw := rhs_elem_type.trim_space()
747 lhs_raw := lhs_elem_type.trim_space()
748 if rhs_raw == lhs_raw {
749 return true
750 }
751 rhs_clean := t.normalize_type_alias(rhs_elem_type)
752 lhs_clean := t.normalize_type_alias(lhs_elem_type)
753 if rhs_clean == lhs_clean {
754 return true
755 }
756 if isnil(t.tc) {
757 return false
758 }
759 return t.array_append_elem_c_type(rhs_clean) == t.array_append_elem_c_type(lhs_clean)
760}
761
762// array_append_ident_type supports array append ident type handling for Transformer.
763fn (t &Transformer) array_append_ident_type(id flat.NodeId) ?string {
764 if int(id) < 0 {
765 return none
766 }
767 node := t.a.nodes[int(id)]
768 if node.kind != .ident || node.value.len == 0 {
769 return none
770 }
771 typ := t.var_type(node.value)
772 if typ.len == 0 {
773 return none
774 }
775 return typ
776}
777
778// array_append_elem_c_type supports array append elem c type handling for Transformer.
779fn (t &Transformer) array_append_elem_c_type(typ string) string {
780 if isnil(t.tc) {
781 return typ
782 }
783 clean := typ.trim_space()
784 if clean.len == 0 {
785 return clean
786 }
787 if !clean.contains('.') {
788 for alias, target in t.tc.type_aliases {
789 if alias.all_after_last('.') == clean {
790 return t.tc.c_type(t.tc.parse_type(target))
791 }
792 }
793 }
794 return t.tc.c_type(t.tc.parse_type(clean))
795}
796
797// array_get_value supports array get value handling for Transformer.
798fn (mut t Transformer) array_get_value(base flat.NodeId, index flat.NodeId, elem_type string) flat.NodeId {
799 get_call := t.make_call_typed('array_get', arr2(base, index), 'voidptr')
800 ptr := t.make_cast('&${elem_type}', get_call, '&${elem_type}')
801 value := t.make_prefix(.mul, ptr)
802 t.a.nodes[int(value)].typ = elem_type
803 return value
804}
805
806// array_get_ptr supports array get ptr handling for Transformer.
807fn (mut t Transformer) array_get_ptr(base flat.NodeId, index flat.NodeId, elem_type string) flat.NodeId {
808 get_call := t.make_call_typed('array_get', arr2(base, index), 'voidptr')
809 return t.make_cast('&${elem_type}', get_call, '&${elem_type}')
810}
811
812// lower_array_filter_call builds lower array filter call data for transform.
813fn (mut t Transformer) lower_array_filter_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
814 if node.children_count < 2 || !base_type.starts_with('[]') {
815 return none
816 }
817 elem_type := base_type[2..]
818 base_id := t.a.child(&fn_node, 0)
819 base := t.stable_expr_for_reuse(base_id)
820 mut prefix := []flat.NodeId{}
821 t.drain_pending(mut prefix)
822 out_name := t.new_temp('filter')
823 idx_name := t.new_temp('filter_idx')
824 prefix << t.make_decl_assign_typed(out_name, t.make_array_new_call(elem_type,
825 t.make_int_literal(0), t.make_selector(base, 'len', 'int')), base_type)
826 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
827 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
828 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
829 elem_name_default := t.new_temp('filter_it')
830 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
831 predicate_id := t.a.child(&node, 1)
832 predicate_node := t.a.nodes[int(predicate_id)]
833 mut predicate_expr_id := predicate_id
834 mut lambda_param := ''
835 mut predicate_fn_name := ''
836 if predicate_node.kind == .lambda_expr && predicate_node.children_count > 0 {
837 predicate_expr_id = t.a.child(&predicate_node, predicate_node.children_count - 1)
838 if predicate_node.children_count > 1 {
839 param := t.a.child_node(&predicate_node, 0)
840 if param.kind == .ident && param.value.len > 0 {
841 lambda_param = param.value
842 }
843 }
844 } else if predicate_node.kind == .ident {
845 if fn_name := t.resolve_fn_value_ident(predicate_node.value) {
846 predicate_fn_name = fn_name
847 } else if ret_type := t.fn_value_return_type_name(predicate_id) {
848 if ret_type == 'bool' {
849 predicate_fn_name = predicate_node.value
850 }
851 }
852 }
853 elem_name := if lambda_param.len > 0 { lambda_param } else { elem_name_default }
854 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
855 old_elem := t.var_type(elem_name)
856 t.set_var_type(elem_name, elem_type)
857 predicate_source := if lambda_param.len > 0 {
858 predicate_expr_id
859 } else {
860 t.substitute_ident(predicate_expr_id, 'it', elem_name)
861 }
862 saved_pending := t.pending_stmts.clone()
863 t.pending_stmts.clear()
864 predicate := if predicate_fn_name.len > 0 {
865 t.make_call_typed(predicate_fn_name, arr1(t.make_ident(elem_name)), 'bool')
866 } else if predicate_node.kind == .fn_literal {
867 fn_value := t.transform_expr(predicate_id)
868 fn_value_node := t.a.nodes[int(fn_value)]
869 if fn_value_node.kind == .ident {
870 t.make_call_typed(fn_value_node.value, arr1(t.make_ident(elem_name)), 'bool')
871 } else {
872 fn_value
873 }
874 } else {
875 t.transform_expr(predicate_source)
876 }
877 predicate_pending := t.pending_stmts.clone()
878 t.pending_stmts = saved_pending
879 if old_elem.len > 0 {
880 t.set_var_type(elem_name, old_elem)
881 } else {
882 t.unset_var_type(elem_name)
883 }
884 mut loop_body := []flat.NodeId{}
885 loop_body << elem_decl
886 for stmt in predicate_pending {
887 loop_body << stmt
888 }
889 push_call := t.make_call_typed('array_push', arr2(t.make_prefix(.amp, t.make_ident(out_name)), t.make_prefix(.amp,
890 t.make_ident(elem_name))), 'void')
891 then_block := t.make_block(arr1(t.make_expr_stmt(push_call)))
892 loop_body << t.make_if(predicate, then_block, t.make_empty())
893 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
894 for stmt in prefix {
895 t.pending_stmts << stmt
896 }
897 return t.make_ident(out_name)
898}
899
900// lower_array_map_call builds lower array map call data for transform.
901fn (mut t Transformer) lower_array_map_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
902 if node.children_count < 2 || !base_type.starts_with('[]') {
903 return none
904 }
905 elem_type := base_type[2..]
906 map_expr_id := t.a.child(&node, 1)
907 map_expr := t.a.nodes[int(map_expr_id)]
908 mut map_fn_name := ''
909 elem_name := t.new_temp('map_it')
910 old_elem := t.var_type(elem_name)
911 t.set_var_type(elem_name, elem_type)
912 mapped_source := t.substitute_ident(map_expr_id, 'it', elem_name)
913 mut result_elem_type := t.node_type(map_expr_id)
914 mut direct_selector_type := ''
915 mut mapped_source_node := t.a.nodes[int(mapped_source)]
916 if mapped_source_node.kind == .map_init {
917 inferred_map_type := t.infer_map_init_entry_type(mapped_source_node)
918 if inferred_map_type.len > 0 {
919 result_elem_type = inferred_map_type
920 t.a.nodes[int(mapped_source)].value = inferred_map_type
921 t.a.nodes[int(mapped_source)].typ = inferred_map_type
922 mapped_source_node = t.a.nodes[int(mapped_source)]
923 }
924 }
925 if mapped_source_node.kind == .selector {
926 selector_type := t.resolve_selector_type(mapped_source_node)
927 if selector_type.len > 0 {
928 direct_selector_type = selector_type
929 result_elem_type = selector_type
930 }
931 }
932 if map_expr.kind == .ident {
933 if fn_name := t.resolve_fn_value_ident(map_expr.value) {
934 map_fn_name = fn_name
935 if ret := t.fn_ret_types[fn_name] {
936 result_elem_type = ret
937 } else if !isnil(t.tc) {
938 if ret_type := t.tc.fn_ret_types[fn_name] {
939 result_elem_type = t.normalize_type_alias(ret_type.name())
940 }
941 }
942 } else if ret_type := t.fn_value_return_type_name(map_expr_id) {
943 map_fn_name = map_expr.value
944 result_elem_type = ret_type
945 }
946 } else if map_expr.kind == .fn_literal || map_expr.kind == .lambda_expr {
947 if ret_type := t.fn_value_return_type_name(map_expr_id) {
948 result_elem_type = ret_type
949 }
950 }
951 if result_elem_type.len == 0 {
952 result_elem_type = t.reliable_stringify_type(map_expr_id)
953 }
954 saved_pending := t.pending_stmts.clone()
955 t.pending_stmts.clear()
956 mapped_expr := if map_fn_name.len > 0 {
957 t.make_call_typed(map_fn_name, arr1(t.make_ident(elem_name)), result_elem_type)
958 } else if map_expr.kind == .fn_literal || map_expr.kind == .lambda_expr {
959 fn_value := t.transform_expr(map_expr_id)
960 fn_value_node := t.a.nodes[int(fn_value)]
961 if fn_value_node.kind == .ident && result_elem_type.len > 0 {
962 t.make_call_typed(fn_value_node.value, arr1(t.make_ident(elem_name)), result_elem_type)
963 } else {
964 fn_value
965 }
966 } else if mapped_source_node.kind == .map_init && result_elem_type.starts_with('map[') {
967 t.transform_expr_for_type(mapped_source, result_elem_type)
968 } else {
969 t.transform_expr(mapped_source)
970 }
971 mapped_pending := t.pending_stmts.clone()
972 t.pending_stmts = saved_pending
973 if old_elem.len > 0 {
974 t.set_var_type(elem_name, old_elem)
975 } else {
976 t.unset_var_type(elem_name)
977 }
978 mapped_type := t.node_type(mapped_expr)
979 if mapped_type.len > 0 && mapped_type != 'unknown' {
980 result_elem_type = mapped_type
981 }
982 if direct_selector_type.len > 0 {
983 result_elem_type = direct_selector_type
984 }
985 if mapped_expr_node := t.selector_expr_node(mapped_expr) {
986 selector_type := t.resolve_selector_type(mapped_expr_node)
987 if selector_type.len > 0 {
988 result_elem_type = selector_type
989 }
990 }
991 if result_elem_type.len == 0 {
992 result_elem_type = elem_type
993 }
994 out_type := '[]${result_elem_type}'
995 base_id := t.a.child(&fn_node, 0)
996 base := t.stable_expr_for_reuse(base_id)
997 mut prefix := []flat.NodeId{}
998 t.drain_pending(mut prefix)
999 out_name := t.new_temp('map')
1000 idx_name := t.new_temp('map_idx')
1001 prefix << t.make_decl_assign_typed(out_name, t.make_array_new_call(result_elem_type,
1002 t.make_int_literal(0), t.make_selector(base, 'len', 'int')), out_type)
1003 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
1004 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
1005 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
1006 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
1007 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
1008 mut loop_body := []flat.NodeId{}
1009 loop_body << elem_decl
1010 for stmt in mapped_pending {
1011 loop_body << stmt
1012 }
1013 value_name := t.new_temp('map_val')
1014 loop_body << t.make_decl_assign_typed(value_name, mapped_expr, result_elem_type)
1015 loop_body << t.make_expr_stmt(t.make_call_typed('array_push', arr2(t.make_prefix(.amp,
1016 t.make_ident(out_name)), t.make_prefix(.amp, t.make_ident(value_name))), 'void'))
1017 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
1018 for stmt in prefix {
1019 t.pending_stmts << stmt
1020 }
1021 result := t.make_ident(out_name)
1022 t.a.nodes[int(result)].typ = out_type
1023 return result
1024}
1025
1026fn (t &Transformer) fn_value_return_type_name(id flat.NodeId) ?string {
1027 if int(id) < 0 {
1028 return none
1029 }
1030 node := t.a.nodes[int(id)]
1031 mut typ := node.typ
1032 if node.kind == .ident {
1033 typ = t.var_type(node.value)
1034 }
1035 if typ.len == 0 || isnil(t.tc) {
1036 return none
1037 }
1038 parsed := t.tc.parse_type(typ)
1039 if parsed is types.FnType {
1040 name := parsed.return_type.name()
1041 if name.len > 0 {
1042 return t.normalize_type_alias(name)
1043 }
1044 }
1045 return none
1046}
1047
1048// selector_expr_node supports selector expr node handling for Transformer.
1049fn (t &Transformer) selector_expr_node(id flat.NodeId) ?flat.Node {
1050 if int(id) < 0 {
1051 return none
1052 }
1053 node := t.a.nodes[int(id)]
1054 if node.kind == .selector {
1055 return node
1056 }
1057 return none
1058}
1059
1060// substitute_ident supports substitute ident handling for Transformer.
1061fn (mut t Transformer) substitute_ident(id flat.NodeId, name string, replacement string) flat.NodeId {
1062 if int(id) < 0 || name.len == 0 || replacement.len == 0 || name == replacement {
1063 return id
1064 }
1065 node := t.a.nodes[int(id)]
1066 if node.kind == .ident && node.value == name {
1067 new_id := t.make_ident(replacement)
1068 if t.a.nodes[int(new_id)].typ.len == 0 {
1069 t.a.nodes[int(new_id)].typ = node.typ
1070 }
1071 return new_id
1072 }
1073 if node.kind == .lambda_expr && node.children_count > 1 {
1074 first := t.a.child_node(&node, 0)
1075 if first.kind == .ident && first.value == name {
1076 return id
1077 }
1078 }
1079 if node.kind == .call && node.children_count > 1 {
1080 fn_id := t.a.child(&node, 0)
1081 fn_node := t.a.nodes[int(fn_id)]
1082 if fn_node.kind == .selector && fn_node.value in ['any', 'all', 'count', 'filter', 'map'] {
1083 mut new_children := []flat.NodeId{cap: int(node.children_count)}
1084 new_children << t.substitute_ident(fn_id, name, replacement)
1085 for i in 1 .. node.children_count {
1086 new_children << t.a.child(&node, i)
1087 }
1088 start := t.a.children.len
1089 for child in new_children {
1090 t.a.children << child
1091 }
1092 return t.a.add_node(flat.Node{
1093 kind: node.kind
1094 op: node.op
1095 children_start: start
1096 children_count: flat.child_count(new_children.len)
1097 pos: node.pos
1098 value: node.value
1099 typ: node.typ
1100 })
1101 }
1102 }
1103 if node.children_count == 0 {
1104 return id
1105 }
1106 mut new_children := []flat.NodeId{cap: int(node.children_count)}
1107 for i in 0 .. node.children_count {
1108 new_children << t.substitute_ident(t.a.child(&node, i), name, replacement)
1109 }
1110 start := t.a.children.len
1111 for child in new_children {
1112 t.a.children << child
1113 }
1114 return t.a.add_node(flat.Node{
1115 kind: node.kind
1116 op: node.op
1117 kind_id: node.kind_id
1118 children_start: start
1119 children_count: flat.child_count(new_children.len)
1120 pos: node.pos
1121 value: node.value
1122 typ: node.typ
1123 generic_params: node.generic_params.clone()
1124 })
1125}
1126
1127fn (mut t Transformer) substitute_ident_expr(id flat.NodeId, name string, replacement flat.NodeId) flat.NodeId {
1128 if int(id) < 0 || name.len == 0 || int(replacement) < 0 {
1129 return id
1130 }
1131 node := t.a.nodes[int(id)]
1132 if node.kind == .ident && node.value == name {
1133 return replacement
1134 }
1135 if node.kind == .lambda_expr && node.children_count > 1 {
1136 first := t.a.child_node(&node, 0)
1137 if first.kind == .ident && first.value == name {
1138 return id
1139 }
1140 }
1141 if node.children_count == 0 {
1142 return id
1143 }
1144 mut new_children := []flat.NodeId{cap: int(node.children_count)}
1145 for i in 0 .. node.children_count {
1146 new_children << t.substitute_ident_expr(t.a.child(&node, i), name, replacement)
1147 }
1148 start := t.a.children.len
1149 for child in new_children {
1150 t.a.children << child
1151 }
1152 return t.a.add_node(flat.Node{
1153 kind: node.kind
1154 op: node.op
1155 kind_id: node.kind_id
1156 children_start: start
1157 children_count: flat.child_count(new_children.len)
1158 pos: node.pos
1159 value: node.value
1160 typ: node.typ
1161 generic_params: node.generic_params.clone()
1162 })
1163}
1164
1165fn (mut t Transformer) infer_map_init_entry_type(node flat.Node) string {
1166 if node.kind != .map_init || node.children_count < 2 {
1167 return ''
1168 }
1169 key_type := t.node_type(t.a.child(&node, 0))
1170 value_type := t.node_type(t.a.child(&node, 1))
1171 if key_type.len == 0 || value_type.len == 0 {
1172 return ''
1173 }
1174 return 'map[${key_type}]${value_type}'
1175}
1176
1177fn (t &Transformer) is_array_transform_call(id flat.NodeId) bool {
1178 if int(id) < 0 {
1179 return false
1180 }
1181 node := t.a.nodes[int(id)]
1182 if node.kind != .call || node.children_count == 0 {
1183 return false
1184 }
1185 fn_id := t.a.child(&node, 0)
1186 fn_node := t.a.nodes[int(fn_id)]
1187 if fn_node.kind != .selector || fn_node.children_count == 0 {
1188 return false
1189 }
1190 if fn_node.value !in ['filter', 'map', 'sorted'] {
1191 return false
1192 }
1193 base_type := t.node_type(t.a.child(&fn_node, 0))
1194 return base_type.starts_with('[]')
1195}
1196
1197// lower_array_count_call builds lower array count call data for transform.
1198fn (mut t Transformer) lower_array_count_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
1199 if node.children_count < 2 || !base_type.starts_with('[]') {
1200 return none
1201 }
1202 elem_type := base_type[2..]
1203 base_id := t.a.child(&fn_node, 0)
1204 base := t.stable_expr_for_reuse(base_id)
1205 mut prefix := []flat.NodeId{}
1206 t.drain_pending(mut prefix)
1207 result_name := t.new_temp('count')
1208 idx_name := t.new_temp('count_idx')
1209 prefix << t.make_decl_assign_typed(result_name, t.make_int_literal(0), 'int')
1210 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
1211 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
1212 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
1213 elem_name := t.new_temp('count_it')
1214 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
1215 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
1216 predicate_id := t.a.child(&node, 1)
1217 old_elem := t.var_type(elem_name)
1218 t.set_var_type(elem_name, elem_type)
1219 predicate := t.transform_expr(t.substitute_ident(predicate_id, 'it', elem_name))
1220 if old_elem.len > 0 {
1221 t.set_var_type(elem_name, old_elem)
1222 } else {
1223 t.unset_var_type(elem_name)
1224 }
1225 mut loop_body := []flat.NodeId{}
1226 loop_body << elem_decl
1227 t.drain_pending(mut loop_body)
1228 inc := t.make_assign_op(t.make_ident(result_name), t.make_int_literal(1), .plus_assign)
1229 loop_body << t.make_if(predicate, t.make_block(arr1(inc)), t.make_empty())
1230 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
1231 for stmt in prefix {
1232 t.pending_stmts << stmt
1233 }
1234 return t.make_ident(result_name)
1235}
1236
1237// lower_array_any_all_call builds lower array any all call data for transform.
1238fn (mut t Transformer) lower_array_any_all_call(node flat.Node, fn_node flat.Node, base_type string, method string) ?flat.NodeId {
1239 if node.children_count < 2 || !base_type.starts_with('[]') {
1240 return none
1241 }
1242 elem_type := base_type[2..]
1243 base_id := t.a.child(&fn_node, 0)
1244 base := t.stable_expr_for_reuse(base_id)
1245 mut prefix := []flat.NodeId{}
1246 t.drain_pending(mut prefix)
1247 result_name := t.new_temp(method)
1248 idx_name := t.new_temp('${method}_idx')
1249 default_value := if method == 'all' {
1250 t.make_bool_literal(true)
1251 } else {
1252 t.make_bool_literal(false)
1253 }
1254 prefix << t.make_decl_assign_typed(result_name, default_value, 'bool')
1255 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
1256 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
1257 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
1258 elem_name := t.new_temp('${method}_it')
1259 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
1260 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
1261 predicate_id := t.a.child(&node, 1)
1262 old_elem := t.var_type(elem_name)
1263 t.set_var_type(elem_name, elem_type)
1264 predicate := t.transform_expr(t.substitute_ident(predicate_id, 'it', elem_name))
1265 if old_elem.len > 0 {
1266 t.set_var_type(elem_name, old_elem)
1267 } else {
1268 t.unset_var_type(elem_name)
1269 }
1270 mut loop_body := []flat.NodeId{}
1271 loop_body << elem_decl
1272 t.drain_pending(mut loop_body)
1273 if method == 'all' {
1274 not_predicate := t.make_prefix(.not, predicate)
1275 assign_false := t.make_assign(t.make_ident(result_name), t.make_bool_literal(false))
1276 loop_body << t.make_if(not_predicate, t.make_block(arr1(assign_false)), t.make_empty())
1277 } else {
1278 assign_true := t.make_assign(t.make_ident(result_name), t.make_bool_literal(true))
1279 loop_body << t.make_if(predicate, t.make_block(arr1(assign_true)), t.make_empty())
1280 }
1281 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
1282 for stmt in prefix {
1283 t.pending_stmts << stmt
1284 }
1285 return t.make_ident(result_name)
1286}
1287
1288// lower_array_sort_call builds lower array sort call data for transform.
1289fn (mut t Transformer) lower_array_sort_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
1290 if !base_type.starts_with('[]') && !(base_type.starts_with('&')
1291 && base_type[1..].starts_with('[]')) {
1292 return none
1293 }
1294 if node.children_count > 2 {
1295 return none
1296 }
1297 base_id := t.a.child(&fn_node, 0)
1298 base := t.transform_lvalue(base_id)
1299 clean_type := if base_type.starts_with('&') { base_type[1..] } else { base_type }
1300 elem_type := clean_type[2..]
1301 cmp_id := if node.children_count > 1 { t.a.child(&node, 1) } else { flat.empty_node }
1302 t.pending_stmts << t.make_array_default_sort_stmt(base, elem_type, node, cmp_id)
1303 return t.make_empty()
1304}
1305
1306// lower_array_sorted_call builds lower array sorted call data for transform.
1307fn (mut t Transformer) lower_array_sorted_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
1308 if node.children_count > 2 || !base_type.starts_with('[]') {
1309 return none
1310 }
1311 base_id := t.a.child(&fn_node, 0)
1312 clone_name := t.new_temp('sorted')
1313 clone_call := t.make_array_clone_call(base_id, base_type)
1314 t.set_var_type(clone_name, base_type)
1315 t.pending_stmts << t.make_decl_assign_typed(clone_name, clone_call, base_type)
1316 cmp_id := if node.children_count > 1 { t.a.child(&node, 1) } else { flat.empty_node }
1317 t.pending_stmts << t.make_array_default_sort_stmt(t.make_ident(clone_name), base_type[2..],
1318 node, cmp_id)
1319 return t.make_ident(clone_name)
1320}
1321
1322// lower_array_sort_with_compare_call builds lower array sort with compare call data for transform.
1323fn (mut t Transformer) lower_array_sort_with_compare_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
1324 if node.children_count != 2
1325 || (!base_type.starts_with('[]') && !(base_type.starts_with('&')
1326 && base_type[1..].starts_with('[]'))) {
1327 return none
1328 }
1329 base_id := t.a.child(&fn_node, 0)
1330 base := t.transform_lvalue(base_id)
1331 clean_type := if base_type.starts_with('&') { base_type[1..] } else { base_type }
1332 elem_type := clean_type[2..]
1333 cmp := t.stable_array_compare_fn(t.a.child(&node, 1), elem_type)
1334 t.pending_stmts << t.make_array_compare_sort_stmt(base, elem_type, node, cmp)
1335 return t.make_empty()
1336}
1337
1338// lower_array_sorted_with_compare_call supports lower_array_sorted_with_compare_call handling.
1339fn (mut t Transformer) lower_array_sorted_with_compare_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
1340 if node.children_count != 2 || !base_type.starts_with('[]') {
1341 return none
1342 }
1343 base_id := t.a.child(&fn_node, 0)
1344 clone_name := t.new_temp('sorted')
1345 clone_call := t.make_array_clone_call(base_id, base_type)
1346 elem_type := base_type[2..]
1347 cmp := t.stable_array_compare_fn(t.a.child(&node, 1), elem_type)
1348 t.set_var_type(clone_name, base_type)
1349 t.pending_stmts << t.make_decl_assign_typed(clone_name, clone_call, base_type)
1350 t.pending_stmts << t.make_array_compare_sort_stmt(t.make_ident(clone_name), elem_type, node, cmp)
1351 return t.make_ident(clone_name)
1352}
1353
1354// stable_array_compare_fn supports stable array compare fn handling for Transformer.
1355fn (mut t Transformer) stable_array_compare_fn(cmp_id flat.NodeId, elem_type string) flat.NodeId {
1356 cmp := t.transform_expr(cmp_id)
1357 cmp_type := 'fn (&${elem_type}, &${elem_type}) int'
1358 return t.stable_transformed_expr_for_reuse(cmp, cmp_type, 'sort_cmp')
1359}
1360
1361// make_array_default_sort_stmt builds make array default sort stmt data for transform.
1362fn (mut t Transformer) make_array_default_sort_stmt(base flat.NodeId, elem_type string, src flat.Node, cmp_id flat.NodeId) flat.NodeId {
1363 i_name := t.new_temp('sort_i')
1364 j_name := t.new_temp('sort_j')
1365 tmp_name := t.new_temp('sort_tmp')
1366 t.set_var_type(i_name, 'int')
1367 t.set_var_type(j_name, 'int')
1368 t.set_var_type(tmp_name, elem_type)
1369 init := t.make_decl_assign_typed(i_name, t.make_int_literal(1), 'int')
1370 cond := t.make_infix(.lt, t.make_ident(i_name), t.make_selector(base, 'len', 'int'))
1371 post := t.make_expr_stmt(t.make_postfix(t.make_ident(i_name), .inc))
1372 j_decl := t.make_decl_assign_typed(j_name, t.make_ident(i_name), 'int')
1373 inner_cond := t.make_infix(.logical_and, t.make_infix(.gt, t.make_ident(j_name),
1374 t.make_int_literal(0)), t.array_sort_less_expr(base, elem_type, j_name, cmp_id))
1375 tmp_decl := t.make_decl_assign_typed(tmp_name, t.make_index(base, t.make_ident(j_name),
1376 elem_type), elem_type)
1377 prev_idx := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
1378 assign_cur := t.make_index_assign(t.make_index(base, t.make_ident(j_name), elem_type), t.make_index(base,
1379 prev_idx, elem_type))
1380 prev_idx2 := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
1381 assign_prev := t.make_index_assign(t.make_index(base, prev_idx2, elem_type),
1382 t.make_ident(tmp_name))
1383 dec_j := t.make_expr_stmt(t.make_postfix(t.make_ident(j_name), .dec))
1384 inner_body := [tmp_decl, assign_cur, assign_prev, dec_j]
1385 inner_for := t.make_for_stmt(t.make_empty(), inner_cond, t.make_empty(), inner_body, src)
1386 return t.make_for_stmt(init, cond, post, [j_decl, inner_for], src)
1387}
1388
1389// make_array_compare_sort_stmt builds make array compare sort stmt data for transform.
1390fn (mut t Transformer) make_array_compare_sort_stmt(base flat.NodeId, elem_type string, src flat.Node, cmp flat.NodeId) flat.NodeId {
1391 i_name := t.new_temp('sort_i')
1392 j_name := t.new_temp('sort_j')
1393 tmp_name := t.new_temp('sort_tmp')
1394 t.set_var_type(i_name, 'int')
1395 t.set_var_type(j_name, 'int')
1396 t.set_var_type(tmp_name, elem_type)
1397 init := t.make_decl_assign_typed(i_name, t.make_int_literal(1), 'int')
1398 cond := t.make_infix(.lt, t.make_ident(i_name), t.make_selector(base, 'len', 'int'))
1399 post := t.make_expr_stmt(t.make_postfix(t.make_ident(i_name), .inc))
1400 j_decl := t.make_decl_assign_typed(j_name, t.make_ident(i_name), 'int')
1401 inner_cond := t.make_infix(.logical_and, t.make_infix(.gt, t.make_ident(j_name),
1402 t.make_int_literal(0)), t.array_sort_compare_less_expr(base, elem_type, j_name, cmp))
1403 tmp_decl := t.make_decl_assign_typed(tmp_name, t.make_index(base, t.make_ident(j_name),
1404 elem_type), elem_type)
1405 prev_idx := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
1406 assign_cur := t.make_index_assign(t.make_index(base, t.make_ident(j_name), elem_type), t.make_index(base,
1407 prev_idx, elem_type))
1408 prev_idx2 := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
1409 assign_prev := t.make_index_assign(t.make_index(base, prev_idx2, elem_type),
1410 t.make_ident(tmp_name))
1411 dec_j := t.make_expr_stmt(t.make_postfix(t.make_ident(j_name), .dec))
1412 inner_body := [tmp_decl, assign_cur, assign_prev, dec_j]
1413 inner_for := t.make_for_stmt(t.make_empty(), inner_cond, t.make_empty(), inner_body, src)
1414 return t.make_for_stmt(init, cond, post, [j_decl, inner_for], src)
1415}
1416
1417// array_sort_less_expr supports array sort less expr handling for Transformer.
1418fn (mut t Transformer) array_sort_less_expr(base flat.NodeId, elem_type string, idx_name string, cmp_id flat.NodeId) flat.NodeId {
1419 cur := t.make_index(base, t.make_ident(idx_name), elem_type)
1420 prev := t.make_index(base, t.make_infix(.minus, t.make_ident(idx_name), t.make_int_literal(1)),
1421 elem_type)
1422 if int(cmp_id) >= 0 {
1423 old_a := t.var_type('a')
1424 old_b := t.var_type('b')
1425 t.set_var_type('a', elem_type)
1426 t.set_var_type('b', elem_type)
1427 raw_cmp := t.substitute_array_sort_vars(cmp_id, cur, prev)
1428 cmp := t.transform_expr(raw_cmp)
1429 if old_a.len > 0 {
1430 t.set_var_type('a', old_a)
1431 } else {
1432 t.unset_var_type('a')
1433 }
1434 if old_b.len > 0 {
1435 t.set_var_type('b', old_b)
1436 } else {
1437 t.unset_var_type('b')
1438 }
1439 return cmp
1440 }
1441 if elem_type == 'string' {
1442 return t.make_call_typed('string__lt', arr2(cur, prev), 'bool')
1443 }
1444 return t.make_infix(.lt, cur, prev)
1445}
1446
1447// array_sort_compare_less_expr supports array sort compare less expr handling for Transformer.
1448fn (mut t Transformer) array_sort_compare_less_expr(base flat.NodeId, elem_type string, idx_name string, cmp flat.NodeId) flat.NodeId {
1449 cur := t.make_index(base, t.make_ident(idx_name), elem_type)
1450 prev := t.make_index(base, t.make_infix(.minus, t.make_ident(idx_name), t.make_int_literal(1)),
1451 elem_type)
1452 call := t.make_call_expr_typed(cmp, arr2(t.make_prefix(.amp, cur), t.make_prefix(.amp, prev)),
1453 'int')
1454 return t.make_infix(.lt, call, t.make_int_literal(0))
1455}
1456
1457// substitute_array_sort_vars supports substitute array sort vars handling for Transformer.
1458fn (mut t Transformer) substitute_array_sort_vars(id flat.NodeId, a_expr flat.NodeId, b_expr flat.NodeId) flat.NodeId {
1459 if int(id) < 0 {
1460 return id
1461 }
1462 node := t.a.nodes[int(id)]
1463 if node.kind == .ident {
1464 if node.value == 'a' {
1465 return a_expr
1466 }
1467 if node.value == 'b' {
1468 return b_expr
1469 }
1470 return id
1471 }
1472 if node.children_count == 0 {
1473 return id
1474 }
1475 mut children := []flat.NodeId{cap: int(node.children_count)}
1476 for i in 0 .. node.children_count {
1477 children << t.substitute_array_sort_vars(t.a.child(&node, i), a_expr, b_expr)
1478 }
1479 start := t.a.children.len
1480 for child in children {
1481 t.a.children << child
1482 }
1483 return t.a.add_node(flat.Node{
1484 kind: node.kind
1485 op: node.op
1486 children_start: start
1487 children_count: node.children_count
1488 pos: node.pos
1489 value: node.value
1490 typ: node.typ
1491 })
1492}
1493
1494// make_index_assign builds make index assign data for transform.
1495fn (mut t Transformer) make_index_assign(lhs flat.NodeId, rhs flat.NodeId) flat.NodeId {
1496 start := t.a.children.len
1497 t.a.children << lhs
1498 t.a.children << rhs
1499 return t.a.add_node(flat.Node{
1500 kind: .index_assign
1501 op: .assign
1502 children_start: start
1503 children_count: 2
1504 })
1505}
1506