v4 / vlib / v3 / transform / array.v
1015 lines · 974 sloc · 38.56 KB · 351709f1031b64c6175612e9e459d8216eeca7f5
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) make_array_push_many_call(lhs_addr flat.NodeId, rhs flat.NodeId, rhs_type string) flat.NodeId {
13 rhs_value := t.stable_transformed_expr_for_reuse(rhs, rhs_type, 'push_many')
14 return t.make_call_typed('array__push_many', arr3(lhs_addr, t.make_selector(rhs_value, 'data',
15 'voidptr'), t.make_selector(rhs_value, 'len', 'int')), 'void')
16}
17
18fn (mut t Transformer) make_array_clone_call(base_id flat.NodeId, base_type string) flat.NodeId {
19 receiver := t.transform_expr(base_id)
20 return t.make_call_typed('array__clone', arr1(t.runtime_addr(receiver, base_type)), base_type)
21}
22
23// lower_array_init_to_runtime converts lower array init to runtime data for transform.
24fn (mut t Transformer) lower_array_init_to_runtime(id flat.NodeId, node flat.Node) flat.NodeId {
25 if node.value.len == 0 || t.is_fixed_array_type(node.value) {
26 return id
27 }
28 elem_type := node.value
29 mut len_expr := t.make_int_literal(0)
30 mut cap_expr := t.make_int_literal(0)
31 mut init_expr := flat.empty_node
32 for i in 0 .. node.children_count {
33 child := t.a.child_node(&node, i)
34 if child.kind == .field_init && child.children_count > 0 {
35 val := t.transform_expr(t.a.child(child, 0))
36 if child.value == 'len' {
37 len_expr = val
38 } else if child.value == 'cap' {
39 cap_expr = val
40 } else if child.value == 'init' {
41 init_expr = val
42 }
43 }
44 }
45 new_call := t.make_array_new_call(elem_type, len_expr, cap_expr)
46 if int(init_expr) < 0 {
47 return new_call
48 }
49 tmp_name := t.new_temp('arr_init')
50 idx_name := t.new_temp('arr_idx')
51 t.pending_stmts << t.make_decl_assign_typed(tmp_name, new_call, '[]${elem_type}')
52 init_idx := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
53 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(t.make_ident(tmp_name),
54 'len', 'int'))
55 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
56 elem_lhs := t.make_index(t.make_ident(tmp_name), t.make_ident(idx_name), elem_type)
57 assign := t.make_assign(elem_lhs, init_expr)
58 // `init:` expressions may reference the magic `index` variable, which V binds to
59 // the current element index. Declare it inside the loop body so it resolves to the
60 // generated loop counter instead of leaking to an external symbol (e.g. libc `index`).
61 index_decl := t.make_decl_assign_typed('index', t.make_ident(idx_name), 'int')
62 t.pending_stmts << t.make_for_stmt(init_idx, cond, post, arr2(index_decl, assign), node)
63 return t.make_ident(tmp_name)
64}
65
66// lower_array_literal_to_runtime converts lower array literal to runtime data for transform.
67fn (mut t Transformer) lower_array_literal_to_runtime(id flat.NodeId, node flat.Node) flat.NodeId {
68 array_type := t.node_type(id)
69 if !array_type.starts_with('[]') {
70 return id
71 }
72 elem_type := array_type[2..]
73 tmp_name := t.new_temp('arr_lit')
74 t.pending_stmts << t.make_decl_assign_typed(tmp_name, t.make_array_new_call(elem_type,
75 t.make_int_literal(0), t.make_int_literal(node.children_count)), array_type)
76 for i in 0 .. node.children_count {
77 elem_id := t.a.child(&node, i)
78 elem := t.a.nodes[int(elem_id)]
79 if elem.kind == .prefix && elem.value == '...' && elem.children_count > 0 {
80 spread_id := t.a.child(&elem, 0)
81 spread := t.transform_expr(spread_id)
82 spread_type := if t.node_type(spread_id).len > 0 {
83 t.node_type(spread_id)
84 } else {
85 array_type
86 }
87 call := t.make_array_push_many_call(t.make_prefix(.amp, t.make_ident(tmp_name)),
88 spread, spread_type)
89 t.pending_stmts << t.make_expr_stmt(call)
90 continue
91 }
92 value_name := t.new_temp('arr_val')
93 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
94 t.wrap_sum_value(elem_id, elem_type)
95 } else {
96 t.transform_expr(elem_id)
97 }
98 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
99 call := t.make_call_typed('array_push', arr2(t.make_prefix(.amp, t.make_ident(tmp_name)), t.make_prefix(.amp,
100 t.make_ident(value_name))), 'void')
101 t.pending_stmts << t.make_expr_stmt(call)
102 }
103 return t.make_ident(tmp_name)
104}
105
106// transform_array_literal_for_type transforms transform array literal for type data for transform.
107fn (mut t Transformer) transform_array_literal_for_type(_id flat.NodeId, node flat.Node, target_type string) ?flat.NodeId {
108 array_type := t.normalize_type_alias(target_type)
109 if !array_type.starts_with('[]') {
110 return none
111 }
112 elem_type := array_type[2..]
113 tmp_name := t.new_temp('arr_lit')
114 t.pending_stmts << t.make_decl_assign_typed(tmp_name, t.make_array_new_call(elem_type,
115 t.make_int_literal(0), t.make_int_literal(node.children_count)), array_type)
116 for i in 0 .. node.children_count {
117 elem_id := t.a.child(&node, i)
118 elem := t.a.nodes[int(elem_id)]
119 if elem.kind == .prefix && elem.value == '...' && elem.children_count > 0 {
120 spread := t.transform_expr_for_type(t.a.child(&elem, 0), array_type)
121 call := t.make_array_push_many_call(t.make_prefix(.amp, t.make_ident(tmp_name)),
122 spread, array_type)
123 t.pending_stmts << t.make_expr_stmt(call)
124 continue
125 }
126 value_name := t.new_temp('arr_val')
127 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
128 t.wrap_sum_value(elem_id, elem_type)
129 } else {
130 t.transform_expr_for_type(elem_id, elem_type)
131 }
132 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
133 call := t.make_call_typed('array_push', arr2(t.make_prefix(.amp, t.make_ident(tmp_name)), t.make_prefix(.amp,
134 t.make_ident(value_name))), 'void')
135 t.pending_stmts << t.make_expr_stmt(call)
136 }
137 return t.make_ident(tmp_name)
138}
139
140fn (mut t Transformer) transform_fixed_array_literal_for_type(_id flat.NodeId, node flat.Node, target_type string) ?flat.NodeId {
141 fixed_type := t.normalize_type_alias(target_type)
142 if !t.is_fixed_array_type(fixed_type) {
143 return none
144 }
145 elem_type := fixed_array_elem_type(fixed_type)
146 mut values := []flat.NodeId{cap: int(node.children_count)}
147 for i in 0 .. node.children_count {
148 elem_id := t.a.child(&node, i)
149 values << t.transform_expr_for_type(elem_id, elem_type)
150 }
151 return t.make_array_literal_typed(values, fixed_type)
152}
153
154// transform_empty_array_init_for_type supports transform_empty_array_init_for_type handling.
155fn (mut t Transformer) transform_empty_array_init_for_type(node flat.Node, target_type string) ?flat.NodeId {
156 if node.value.len > 0 || node.children_count > 0 {
157 return none
158 }
159 array_type := t.normalize_type_alias(target_type)
160 if !array_type.starts_with('[]') {
161 return none
162 }
163 elem_type := array_type[2..]
164 return t.make_array_new_call(elem_type, t.make_int_literal(0), t.make_int_literal(0))
165}
166
167// try_lower_array_append_stmt supports try lower array append stmt handling for Transformer.
168fn (mut t Transformer) try_lower_array_append_stmt(id flat.NodeId) ?[]flat.NodeId {
169 if int(id) < 0 {
170 return none
171 }
172 node := t.a.nodes[int(id)]
173 if node.kind != .infix || node.op != .left_shift || node.children_count < 2 {
174 return none
175 }
176 lhs_id := t.a.child(&node, 0)
177 mut lhs_type := t.lvalue_type(lhs_id)
178 if !array_type_has_generic_placeholder(lhs_type) {
179 lhs_type = t.normalize_type_alias(lhs_type)
180 }
181 mut array_type := t.clean_array_append_lhs_type(lhs_type)
182 if !array_type.starts_with('[]') {
183 return none
184 }
185 elem_type := array_type[2..]
186 rhs_id := t.a.child(&node, 1)
187 mut rhs_type := t.normalize_type_alias(t.node_type(rhs_id))
188 rhs_node := t.a.nodes[int(rhs_id)]
189 mut push_many := t.array_append_rhs_is_push_many(lhs_id, rhs_id, rhs_type, elem_type)
190 if rhs_node.kind == .array_literal && !elem_type.starts_with('[]')
191 && !t.is_fixed_array_type(elem_type) {
192 // `[]scalar << [a, b, c]` always appends the literal's elements. Retype the
193 // literal from the destination so a mis-inferred element type (e.g. `[]int`
194 // for `[f32_expr, ..]`) is corrected and the append stays a clean push_many,
195 // instead of degrading to a single push of the whole array. (An array-typed
196 // element is genuinely ambiguous, so leave that to the inferred decision.)
197 push_many = true
198 t.a.nodes[int(rhs_id)].typ = array_type
199 rhs_type = array_type
200 } else if push_many && rhs_node.kind == .array_literal && !rhs_type.starts_with('[]') {
201 t.a.nodes[int(rhs_id)].typ = array_type
202 rhs_type = array_type
203 }
204
205 mut result := []flat.NodeId{}
206 lhs := t.transform_lvalue(lhs_id)
207 t.drain_pending(mut result)
208 mut rhs := if !push_many
209 && (elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types) {
210 t.wrap_sum_value(rhs_id, elem_type)
211 } else {
212 t.transform_expr(rhs_id)
213 }
214 if !push_many {
215 rhs = t.coerce_transformed_expr_to_type(rhs, rhs_id, elem_type)
216 }
217 t.drain_pending(mut result)
218 if rhs_type.len == 0 {
219 rhs_type = t.node_type(rhs)
220 push_many = t.array_append_rhs_is_push_many(lhs_id, rhs_id, rhs_type, elem_type)
221 }
222
223 lhs_addr := t.runtime_addr(lhs, lhs_type)
224 if push_many {
225 call := if t.is_fixed_array_type(rhs_type) {
226 t.make_call_typed('array_push_many_ptr', arr3(lhs_addr, rhs,
227 t.make_fixed_array_len_expr(rhs_type)), 'void')
228 } else {
229 t.make_array_push_many_call(lhs_addr, rhs, rhs_type)
230 }
231 result << t.make_expr_stmt(call)
232 return result
233 }
234 value_name := t.new_temp('arr_val')
235 result << t.make_decl_assign_typed(value_name, rhs, elem_type)
236 result << t.make_expr_stmt(t.make_call_typed('array_push', arr2(lhs_addr, t.make_prefix(.amp,
237 t.make_ident(value_name))), 'void'))
238 return result
239}
240
241// clean_array_append_lhs_type transforms clean array append lhs type data for transform.
242fn (t &Transformer) clean_array_append_lhs_type(typ string) string {
243 mut clean := if array_type_has_generic_placeholder(typ) {
244 typ.trim_space()
245 } else {
246 t.normalize_type_alias(typ).trim_space()
247 }
248 for {
249 if clean.starts_with('&') {
250 clean = clean[1..].trim_space()
251 continue
252 }
253 if clean.starts_with('shared ') {
254 clean = clean[7..].trim_space()
255 continue
256 }
257 if clean.starts_with('atomic ') {
258 clean = clean[7..].trim_space()
259 continue
260 }
261 break
262 }
263 return clean
264}
265
266fn array_type_has_generic_placeholder(typ string) bool {
267 clean := typ.trim_space()
268 if clean.len == 0 {
269 return false
270 }
271 if is_generic_placeholder_type_name(clean) {
272 return true
273 }
274 if clean.starts_with('&') {
275 return array_type_has_generic_placeholder(clean[1..])
276 }
277 if clean.starts_with('[]') {
278 return array_type_has_generic_placeholder(clean[2..])
279 }
280 if clean.starts_with('map[') {
281 bracket_end := clean.index(']') or { return false }
282 return array_type_has_generic_placeholder(clean[4..bracket_end])
283 || array_type_has_generic_placeholder(clean[bracket_end + 1..])
284 }
285 if clean.starts_with('[') {
286 bracket_end := clean.index(']') or { return false }
287 return array_type_has_generic_placeholder(clean[bracket_end + 1..])
288 }
289 return false
290}
291
292// lower_array_prepend_call builds lower array prepend call data for transform.
293fn (mut t Transformer) lower_array_prepend_call(node flat.Node, fn_node flat.Node, base_type string, elem_type string) ?flat.NodeId {
294 if node.children_count < 2 || fn_node.children_count == 0 {
295 return none
296 }
297 base_id := t.a.child(&fn_node, 0)
298 value_id := t.a.child(&node, 1)
299 base := t.transform_lvalue(base_id)
300 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
301 t.wrap_sum_value(value_id, elem_type)
302 } else {
303 t.transform_expr_for_type(value_id, elem_type)
304 }
305 value_name := t.new_temp('arr_val')
306 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
307 return t.make_call_typed('array__prepend', arr2(t.runtime_addr(base, base_type), t.make_prefix(.amp,
308 t.make_ident(value_name))), 'void')
309}
310
311// lower_array_insert_call builds lower array insert call data for transform.
312fn (mut t Transformer) lower_array_insert_call(node flat.Node, fn_node flat.Node, base_type string, elem_type string) ?flat.NodeId {
313 if node.children_count < 3 || fn_node.children_count == 0 {
314 return none
315 }
316 base_id := t.a.child(&fn_node, 0)
317 index_id := t.a.child(&node, 1)
318 value_id := t.a.child(&node, 2)
319 base := t.transform_lvalue(base_id)
320 index := t.transform_expr_for_type(index_id, 'int')
321 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
322 t.wrap_sum_value(value_id, elem_type)
323 } else {
324 t.transform_expr_for_type(value_id, elem_type)
325 }
326 value_name := t.new_temp('arr_val')
327 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
328 return t.make_call_typed('array__insert', arr3(t.runtime_addr(base, base_type), index, t.make_prefix(.amp,
329 t.make_ident(value_name))), 'void')
330}
331
332fn (mut t Transformer) lower_array_push_many_call(node flat.Node, fn_node flat.Node, base_type string, elem_type string) ?flat.NodeId {
333 if node.children_count < 3 || fn_node.children_count == 0 {
334 return none
335 }
336 base_id := t.a.child(&fn_node, 0)
337 value_id := t.a.child(&node, 1)
338 count_id := t.a.child(&node, 2)
339 base := t.transform_lvalue(base_id)
340 base_addr := t.runtime_addr(base, base_type)
341 if t.push_many_count_is_type_name(count_id) {
342 value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
343 t.wrap_sum_value(value_id, elem_type)
344 } else {
345 t.transform_expr_for_type(value_id, elem_type)
346 }
347 value_name := t.new_temp('arr_val')
348 t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
349 return t.make_call_typed('array_push_many_ptr', arr3(base_addr, t.make_prefix(.amp,
350 t.make_ident(value_name)), t.make_int_literal(1)), 'void')
351 }
352 value := t.transform_expr(value_id)
353 count := t.transform_expr_for_type(count_id, 'int')
354 return t.make_call_typed('array_push_many_ptr', arr3(base_addr, value, count), 'void')
355}
356
357fn (t &Transformer) push_many_count_is_type_name(id flat.NodeId) bool {
358 if int(id) < 0 {
359 return false
360 }
361 node := t.a.nodes[int(id)]
362 return node.kind == .ident && node.value.len > 0 && node.value[0] >= `A` && node.value[0] <= `Z`
363}
364
365// array_append_rhs_is_push_many supports array append rhs is push many handling for Transformer.
366fn (t &Transformer) array_append_rhs_is_push_many(lhs_id flat.NodeId, rhs_id flat.NodeId, rhs_type string, elem_type string) bool {
367 clean_rhs_type := rhs_type.trim_space()
368 if clean_rhs_type.starts_with('[]') {
369 if t.array_append_elem_types_match(clean_rhs_type[2..], elem_type) {
370 return true
371 }
372 if declared_rhs_type := t.array_append_ident_type(rhs_id) {
373 if declared_rhs_type.starts_with('[]') {
374 return t.array_append_elem_types_match(declared_rhs_type[2..], elem_type)
375 }
376 }
377 return false
378 }
379 if t.is_fixed_array_type(clean_rhs_type) {
380 return t.array_append_elem_types_match(fixed_array_elem_type(clean_rhs_type), elem_type)
381 }
382 if !isnil(t.tc) {
383 if rhs_resolved := t.tc.expr_type(rhs_id) {
384 rhs_clean := types.unwrap_pointer(rhs_resolved)
385 if rhs_clean is types.Array {
386 return t.array_append_elem_types_match(rhs_clean.elem_type.name(), elem_type)
387 }
388 if rhs_clean is types.ArrayFixed {
389 return t.array_append_elem_types_match(rhs_clean.elem_type.name(), elem_type)
390 }
391 }
392 if lhs_resolved := t.tc.expr_type(lhs_id) {
393 lhs_clean := types.unwrap_pointer(lhs_resolved)
394 if lhs_clean is types.Array && clean_rhs_type in ['array', 'Array'] {
395 return t.tc.c_type(lhs_clean.elem_type) == 'void*'
396 }
397 }
398 }
399 if clean_rhs_type in ['array', 'Array'] {
400 return t.array_append_elem_c_type(elem_type) !in ['array', 'Array']
401 }
402 return false
403}
404
405// array_append_elem_types_match supports array append elem types match handling for Transformer.
406fn (t &Transformer) array_append_elem_types_match(rhs_elem_type string, lhs_elem_type string) bool {
407 rhs_raw := rhs_elem_type.trim_space()
408 lhs_raw := lhs_elem_type.trim_space()
409 if rhs_raw == lhs_raw {
410 return true
411 }
412 rhs_clean := t.normalize_type_alias(rhs_elem_type)
413 lhs_clean := t.normalize_type_alias(lhs_elem_type)
414 if rhs_clean == lhs_clean {
415 return true
416 }
417 if isnil(t.tc) {
418 return false
419 }
420 return t.array_append_elem_c_type(rhs_clean) == t.array_append_elem_c_type(lhs_clean)
421}
422
423// array_append_ident_type supports array append ident type handling for Transformer.
424fn (t &Transformer) array_append_ident_type(id flat.NodeId) ?string {
425 if int(id) < 0 {
426 return none
427 }
428 node := t.a.nodes[int(id)]
429 if node.kind != .ident || node.value.len == 0 {
430 return none
431 }
432 typ := t.var_type(node.value)
433 if typ.len == 0 {
434 return none
435 }
436 return typ
437}
438
439// array_append_elem_c_type supports array append elem c type handling for Transformer.
440fn (t &Transformer) array_append_elem_c_type(typ string) string {
441 if isnil(t.tc) {
442 return typ
443 }
444 clean := typ.trim_space()
445 if clean.len == 0 {
446 return clean
447 }
448 if !clean.contains('.') {
449 for alias, target in t.tc.type_aliases {
450 if alias.all_after_last('.') == clean {
451 return t.tc.c_type(t.tc.parse_type(target))
452 }
453 }
454 }
455 return t.tc.c_type(t.tc.parse_type(clean))
456}
457
458// array_get_value supports array get value handling for Transformer.
459fn (mut t Transformer) array_get_value(base flat.NodeId, index flat.NodeId, elem_type string) flat.NodeId {
460 get_call := t.make_call_typed('array_get', arr2(base, index), 'voidptr')
461 ptr := t.make_cast('&${elem_type}', get_call, '&${elem_type}')
462 value := t.make_prefix(.mul, ptr)
463 t.a.nodes[int(value)].typ = elem_type
464 return value
465}
466
467// array_get_ptr supports array get ptr handling for Transformer.
468fn (mut t Transformer) array_get_ptr(base flat.NodeId, index flat.NodeId, elem_type string) flat.NodeId {
469 get_call := t.make_call_typed('array_get', arr2(base, index), 'voidptr')
470 return t.make_cast('&${elem_type}', get_call, '&${elem_type}')
471}
472
473// lower_array_filter_call builds lower array filter call data for transform.
474fn (mut t Transformer) lower_array_filter_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
475 if node.children_count < 2 || !base_type.starts_with('[]') {
476 return none
477 }
478 elem_type := base_type[2..]
479 base_id := t.a.child(&fn_node, 0)
480 base := t.stable_expr_for_reuse(base_id)
481 mut prefix := []flat.NodeId{}
482 t.drain_pending(mut prefix)
483 out_name := t.new_temp('filter')
484 idx_name := t.new_temp('filter_idx')
485 prefix << t.make_decl_assign_typed(out_name, t.make_array_new_call(elem_type,
486 t.make_int_literal(0), t.make_selector(base, 'len', 'int')), base_type)
487 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
488 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
489 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
490 elem_name_default := t.new_temp('filter_it')
491 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
492 predicate_id := t.a.child(&node, 1)
493 predicate_node := t.a.nodes[int(predicate_id)]
494 mut predicate_expr_id := predicate_id
495 mut lambda_param := ''
496 if predicate_node.kind == .lambda_expr && predicate_node.children_count > 0 {
497 predicate_expr_id = t.a.child(&predicate_node, predicate_node.children_count - 1)
498 if predicate_node.children_count > 1 {
499 param := t.a.child_node(&predicate_node, 0)
500 if param.kind == .ident && param.value.len > 0 {
501 lambda_param = param.value
502 }
503 }
504 }
505 elem_name := if lambda_param.len > 0 { lambda_param } else { elem_name_default }
506 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
507 old_elem := t.var_type(elem_name)
508 t.set_var_type(elem_name, elem_type)
509 predicate_source := if lambda_param.len > 0 {
510 predicate_expr_id
511 } else {
512 t.substitute_ident(predicate_expr_id, 'it', elem_name)
513 }
514 predicate := t.transform_expr(predicate_source)
515 if old_elem.len > 0 {
516 t.set_var_type(elem_name, old_elem)
517 } else {
518 t.unset_var_type(elem_name)
519 }
520 mut loop_body := []flat.NodeId{}
521 loop_body << elem_decl
522 t.drain_pending(mut loop_body)
523 push_call := t.make_call_typed('array_push', arr2(t.make_prefix(.amp, t.make_ident(out_name)), t.make_prefix(.amp,
524 t.make_ident(elem_name))), 'void')
525 then_block := t.make_block(arr1(t.make_expr_stmt(push_call)))
526 loop_body << t.make_if(predicate, then_block, t.make_empty())
527 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
528 for stmt in prefix {
529 t.pending_stmts << stmt
530 }
531 return t.make_ident(out_name)
532}
533
534// lower_array_map_call builds lower array map call data for transform.
535fn (mut t Transformer) lower_array_map_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
536 if node.children_count < 2 || !base_type.starts_with('[]') {
537 return none
538 }
539 elem_type := base_type[2..]
540 map_expr_id := t.a.child(&node, 1)
541 map_expr := t.a.nodes[int(map_expr_id)]
542 mut map_fn_name := ''
543 elem_name := t.new_temp('map_it')
544 old_elem := t.var_type(elem_name)
545 t.set_var_type(elem_name, elem_type)
546 mapped_source := t.substitute_ident(map_expr_id, 'it', elem_name)
547 mut result_elem_type := t.node_type(map_expr_id)
548 mut direct_selector_type := ''
549 mapped_source_node := t.a.nodes[int(mapped_source)]
550 if mapped_source_node.kind == .selector {
551 selector_type := t.resolve_selector_type(mapped_source_node)
552 if selector_type.len > 0 {
553 direct_selector_type = selector_type
554 result_elem_type = selector_type
555 }
556 }
557 if map_expr.kind == .ident {
558 if fn_name := t.resolve_fn_value_ident(map_expr.value) {
559 map_fn_name = fn_name
560 if ret := t.fn_ret_types[fn_name] {
561 result_elem_type = ret
562 } else if !isnil(t.tc) {
563 if ret_type := t.tc.fn_ret_types[fn_name] {
564 result_elem_type = t.normalize_type_alias(ret_type.name())
565 }
566 }
567 }
568 }
569 if result_elem_type.len == 0 {
570 result_elem_type = t.reliable_stringify_type(map_expr_id)
571 }
572 saved_pending := t.pending_stmts.clone()
573 t.pending_stmts.clear()
574 mapped_expr := if map_fn_name.len > 0 {
575 t.make_call_typed(map_fn_name, arr1(t.make_ident(elem_name)), result_elem_type)
576 } else {
577 t.transform_expr(mapped_source)
578 }
579 mapped_pending := t.pending_stmts.clone()
580 t.pending_stmts = saved_pending
581 if old_elem.len > 0 {
582 t.set_var_type(elem_name, old_elem)
583 } else {
584 t.unset_var_type(elem_name)
585 }
586 mapped_type := t.node_type(mapped_expr)
587 if mapped_type.len > 0 && mapped_type != 'unknown' {
588 result_elem_type = mapped_type
589 }
590 if direct_selector_type.len > 0 {
591 result_elem_type = direct_selector_type
592 }
593 if mapped_expr_node := t.selector_expr_node(mapped_expr) {
594 selector_type := t.resolve_selector_type(mapped_expr_node)
595 if selector_type.len > 0 {
596 result_elem_type = selector_type
597 }
598 }
599 if result_elem_type.len == 0 {
600 result_elem_type = elem_type
601 }
602 out_type := '[]${result_elem_type}'
603 base_id := t.a.child(&fn_node, 0)
604 base := t.stable_expr_for_reuse(base_id)
605 mut prefix := []flat.NodeId{}
606 t.drain_pending(mut prefix)
607 out_name := t.new_temp('map')
608 idx_name := t.new_temp('map_idx')
609 prefix << t.make_decl_assign_typed(out_name, t.make_array_new_call(result_elem_type,
610 t.make_int_literal(0), t.make_selector(base, 'len', 'int')), out_type)
611 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
612 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
613 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
614 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
615 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
616 mut loop_body := []flat.NodeId{}
617 loop_body << elem_decl
618 for stmt in mapped_pending {
619 loop_body << stmt
620 }
621 value_name := t.new_temp('map_val')
622 loop_body << t.make_decl_assign_typed(value_name, mapped_expr, result_elem_type)
623 loop_body << t.make_expr_stmt(t.make_call_typed('array_push', arr2(t.make_prefix(.amp,
624 t.make_ident(out_name)), t.make_prefix(.amp, t.make_ident(value_name))), 'void'))
625 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
626 for stmt in prefix {
627 t.pending_stmts << stmt
628 }
629 result := t.make_ident(out_name)
630 t.a.nodes[int(result)].typ = out_type
631 return result
632}
633
634// selector_expr_node supports selector expr node handling for Transformer.
635fn (t &Transformer) selector_expr_node(id flat.NodeId) ?flat.Node {
636 if int(id) < 0 {
637 return none
638 }
639 node := t.a.nodes[int(id)]
640 if node.kind == .selector {
641 return node
642 }
643 return none
644}
645
646// substitute_ident supports substitute ident handling for Transformer.
647fn (mut t Transformer) substitute_ident(id flat.NodeId, name string, replacement string) flat.NodeId {
648 if int(id) < 0 || name.len == 0 || replacement.len == 0 || name == replacement {
649 return id
650 }
651 node := t.a.nodes[int(id)]
652 if node.kind == .ident && node.value == name {
653 new_id := t.make_ident(replacement)
654 t.a.nodes[int(new_id)].typ = node.typ
655 return new_id
656 }
657 if node.kind == .lambda_expr && node.children_count > 1 {
658 first := t.a.child_node(&node, 0)
659 if first.kind == .ident && first.value == name {
660 return id
661 }
662 }
663 if node.kind == .call && node.children_count > 1 {
664 fn_id := t.a.child(&node, 0)
665 fn_node := t.a.nodes[int(fn_id)]
666 if fn_node.kind == .selector && fn_node.value in ['any', 'all', 'count', 'filter', 'map'] {
667 mut new_children := []flat.NodeId{cap: int(node.children_count)}
668 new_children << t.substitute_ident(fn_id, name, replacement)
669 for i in 1 .. node.children_count {
670 new_children << t.a.child(&node, i)
671 }
672 start := t.a.children.len
673 for child in new_children {
674 t.a.children << child
675 }
676 return t.a.add_node(flat.Node{
677 kind: node.kind
678 op: node.op
679 children_start: start
680 children_count: flat.child_count(new_children.len)
681 pos: node.pos
682 value: node.value
683 typ: node.typ
684 })
685 }
686 }
687 if node.children_count == 0 {
688 return id
689 }
690 mut new_children := []flat.NodeId{cap: int(node.children_count)}
691 for i in 0 .. node.children_count {
692 new_children << t.substitute_ident(t.a.child(&node, i), name, replacement)
693 }
694 start := t.a.children.len
695 for child in new_children {
696 t.a.children << child
697 }
698 return t.a.add_node(flat.Node{
699 kind: node.kind
700 op: node.op
701 children_start: start
702 children_count: flat.child_count(new_children.len)
703 pos: node.pos
704 value: node.value
705 typ: node.typ
706 })
707}
708
709// lower_array_count_call builds lower array count call data for transform.
710fn (mut t Transformer) lower_array_count_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
711 if node.children_count < 2 || !base_type.starts_with('[]') {
712 return none
713 }
714 elem_type := base_type[2..]
715 base_id := t.a.child(&fn_node, 0)
716 base := t.stable_expr_for_reuse(base_id)
717 mut prefix := []flat.NodeId{}
718 t.drain_pending(mut prefix)
719 result_name := t.new_temp('count')
720 idx_name := t.new_temp('count_idx')
721 prefix << t.make_decl_assign_typed(result_name, t.make_int_literal(0), 'int')
722 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
723 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
724 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
725 elem_name := t.new_temp('count_it')
726 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
727 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
728 predicate_id := t.a.child(&node, 1)
729 old_elem := t.var_type(elem_name)
730 t.set_var_type(elem_name, elem_type)
731 predicate := t.transform_expr(t.substitute_ident(predicate_id, 'it', elem_name))
732 if old_elem.len > 0 {
733 t.set_var_type(elem_name, old_elem)
734 } else {
735 t.unset_var_type(elem_name)
736 }
737 mut loop_body := []flat.NodeId{}
738 loop_body << elem_decl
739 t.drain_pending(mut loop_body)
740 inc := t.make_assign_op(t.make_ident(result_name), t.make_int_literal(1), .plus_assign)
741 loop_body << t.make_if(predicate, t.make_block(arr1(inc)), t.make_empty())
742 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
743 for stmt in prefix {
744 t.pending_stmts << stmt
745 }
746 return t.make_ident(result_name)
747}
748
749// lower_array_any_all_call builds lower array any all call data for transform.
750fn (mut t Transformer) lower_array_any_all_call(node flat.Node, fn_node flat.Node, base_type string, method string) ?flat.NodeId {
751 if node.children_count < 2 || !base_type.starts_with('[]') {
752 return none
753 }
754 elem_type := base_type[2..]
755 base_id := t.a.child(&fn_node, 0)
756 base := t.stable_expr_for_reuse(base_id)
757 mut prefix := []flat.NodeId{}
758 t.drain_pending(mut prefix)
759 result_name := t.new_temp(method)
760 idx_name := t.new_temp('${method}_idx')
761 default_value := if method == 'all' {
762 t.make_bool_literal(true)
763 } else {
764 t.make_bool_literal(false)
765 }
766 prefix << t.make_decl_assign_typed(result_name, default_value, 'bool')
767 init := t.make_decl_assign_typed(idx_name, t.make_int_literal(0), 'int')
768 cond := t.make_infix(.lt, t.make_ident(idx_name), t.make_selector(base, 'len', 'int'))
769 post := t.make_expr_stmt(t.make_postfix(t.make_ident(idx_name), .inc))
770 elem_name := t.new_temp('${method}_it')
771 elem_expr := t.array_get_value(base, t.make_ident(idx_name), elem_type)
772 elem_decl := t.make_decl_assign_typed(elem_name, elem_expr, elem_type)
773 predicate_id := t.a.child(&node, 1)
774 old_elem := t.var_type(elem_name)
775 t.set_var_type(elem_name, elem_type)
776 predicate := t.transform_expr(t.substitute_ident(predicate_id, 'it', elem_name))
777 if old_elem.len > 0 {
778 t.set_var_type(elem_name, old_elem)
779 } else {
780 t.unset_var_type(elem_name)
781 }
782 mut loop_body := []flat.NodeId{}
783 loop_body << elem_decl
784 t.drain_pending(mut loop_body)
785 if method == 'all' {
786 not_predicate := t.make_prefix(.not, predicate)
787 assign_false := t.make_assign(t.make_ident(result_name), t.make_bool_literal(false))
788 loop_body << t.make_if(not_predicate, t.make_block(arr1(assign_false)), t.make_empty())
789 } else {
790 assign_true := t.make_assign(t.make_ident(result_name), t.make_bool_literal(true))
791 loop_body << t.make_if(predicate, t.make_block(arr1(assign_true)), t.make_empty())
792 }
793 prefix << t.make_for_stmt(init, cond, post, loop_body, node)
794 for stmt in prefix {
795 t.pending_stmts << stmt
796 }
797 return t.make_ident(result_name)
798}
799
800// lower_array_sort_call builds lower array sort call data for transform.
801fn (mut t Transformer) lower_array_sort_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
802 if !base_type.starts_with('[]') && !(base_type.starts_with('&')
803 && base_type[1..].starts_with('[]')) {
804 return none
805 }
806 if node.children_count > 2 {
807 return none
808 }
809 base_id := t.a.child(&fn_node, 0)
810 base := t.transform_lvalue(base_id)
811 clean_type := if base_type.starts_with('&') { base_type[1..] } else { base_type }
812 elem_type := clean_type[2..]
813 cmp_id := if node.children_count > 1 { t.a.child(&node, 1) } else { flat.empty_node }
814 t.pending_stmts << t.make_array_default_sort_stmt(base, elem_type, node, cmp_id)
815 return t.make_empty()
816}
817
818// lower_array_sorted_call builds lower array sorted call data for transform.
819fn (mut t Transformer) lower_array_sorted_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
820 if node.children_count > 2 || !base_type.starts_with('[]') {
821 return none
822 }
823 base_id := t.a.child(&fn_node, 0)
824 clone_name := t.new_temp('sorted')
825 clone_call := t.make_array_clone_call(base_id, base_type)
826 t.pending_stmts << t.make_decl_assign_typed(clone_name, clone_call, base_type)
827 cmp_id := if node.children_count > 1 { t.a.child(&node, 1) } else { flat.empty_node }
828 t.pending_stmts << t.make_array_default_sort_stmt(t.make_ident(clone_name), base_type[2..],
829 node, cmp_id)
830 return t.make_ident(clone_name)
831}
832
833// lower_array_sort_with_compare_call builds lower array sort with compare call data for transform.
834fn (mut t Transformer) lower_array_sort_with_compare_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
835 if node.children_count != 2
836 || (!base_type.starts_with('[]') && !(base_type.starts_with('&')
837 && base_type[1..].starts_with('[]'))) {
838 return none
839 }
840 base_id := t.a.child(&fn_node, 0)
841 base := t.transform_lvalue(base_id)
842 clean_type := if base_type.starts_with('&') { base_type[1..] } else { base_type }
843 elem_type := clean_type[2..]
844 cmp := t.stable_array_compare_fn(t.a.child(&node, 1), elem_type)
845 t.pending_stmts << t.make_array_compare_sort_stmt(base, elem_type, node, cmp)
846 return t.make_empty()
847}
848
849// lower_array_sorted_with_compare_call supports lower_array_sorted_with_compare_call handling.
850fn (mut t Transformer) lower_array_sorted_with_compare_call(node flat.Node, fn_node flat.Node, base_type string) ?flat.NodeId {
851 if node.children_count != 2 || !base_type.starts_with('[]') {
852 return none
853 }
854 base_id := t.a.child(&fn_node, 0)
855 clone_name := t.new_temp('sorted')
856 clone_call := t.make_array_clone_call(base_id, base_type)
857 t.pending_stmts << t.make_decl_assign_typed(clone_name, clone_call, base_type)
858 elem_type := base_type[2..]
859 cmp := t.stable_array_compare_fn(t.a.child(&node, 1), elem_type)
860 t.pending_stmts << t.make_array_compare_sort_stmt(t.make_ident(clone_name), elem_type, node, cmp)
861 return t.make_ident(clone_name)
862}
863
864// stable_array_compare_fn supports stable array compare fn handling for Transformer.
865fn (mut t Transformer) stable_array_compare_fn(cmp_id flat.NodeId, elem_type string) flat.NodeId {
866 cmp := t.transform_expr(cmp_id)
867 cmp_type := 'fn (&${elem_type}, &${elem_type}) int'
868 return t.stable_transformed_expr_for_reuse(cmp, cmp_type, 'sort_cmp')
869}
870
871// make_array_default_sort_stmt builds make array default sort stmt data for transform.
872fn (mut t Transformer) make_array_default_sort_stmt(base flat.NodeId, elem_type string, src flat.Node, cmp_id flat.NodeId) flat.NodeId {
873 i_name := t.new_temp('sort_i')
874 j_name := t.new_temp('sort_j')
875 tmp_name := t.new_temp('sort_tmp')
876 t.set_var_type(i_name, 'int')
877 t.set_var_type(j_name, 'int')
878 t.set_var_type(tmp_name, elem_type)
879 init := t.make_decl_assign_typed(i_name, t.make_int_literal(1), 'int')
880 cond := t.make_infix(.lt, t.make_ident(i_name), t.make_selector(base, 'len', 'int'))
881 post := t.make_expr_stmt(t.make_postfix(t.make_ident(i_name), .inc))
882 j_decl := t.make_decl_assign_typed(j_name, t.make_ident(i_name), 'int')
883 inner_cond := t.make_infix(.logical_and, t.make_infix(.gt, t.make_ident(j_name),
884 t.make_int_literal(0)), t.array_sort_less_expr(base, elem_type, j_name, cmp_id))
885 tmp_decl := t.make_decl_assign_typed(tmp_name, t.make_index(base, t.make_ident(j_name),
886 elem_type), elem_type)
887 prev_idx := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
888 assign_cur := t.make_index_assign(t.make_index(base, t.make_ident(j_name), elem_type), t.make_index(base,
889 prev_idx, elem_type))
890 prev_idx2 := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
891 assign_prev := t.make_index_assign(t.make_index(base, prev_idx2, elem_type),
892 t.make_ident(tmp_name))
893 dec_j := t.make_expr_stmt(t.make_postfix(t.make_ident(j_name), .dec))
894 inner_body := [tmp_decl, assign_cur, assign_prev, dec_j]
895 inner_for := t.make_for_stmt(t.make_empty(), inner_cond, t.make_empty(), inner_body, src)
896 return t.make_for_stmt(init, cond, post, [j_decl, inner_for], src)
897}
898
899// make_array_compare_sort_stmt builds make array compare sort stmt data for transform.
900fn (mut t Transformer) make_array_compare_sort_stmt(base flat.NodeId, elem_type string, src flat.Node, cmp flat.NodeId) flat.NodeId {
901 i_name := t.new_temp('sort_i')
902 j_name := t.new_temp('sort_j')
903 tmp_name := t.new_temp('sort_tmp')
904 t.set_var_type(i_name, 'int')
905 t.set_var_type(j_name, 'int')
906 t.set_var_type(tmp_name, elem_type)
907 init := t.make_decl_assign_typed(i_name, t.make_int_literal(1), 'int')
908 cond := t.make_infix(.lt, t.make_ident(i_name), t.make_selector(base, 'len', 'int'))
909 post := t.make_expr_stmt(t.make_postfix(t.make_ident(i_name), .inc))
910 j_decl := t.make_decl_assign_typed(j_name, t.make_ident(i_name), 'int')
911 inner_cond := t.make_infix(.logical_and, t.make_infix(.gt, t.make_ident(j_name),
912 t.make_int_literal(0)), t.array_sort_compare_less_expr(base, elem_type, j_name, cmp))
913 tmp_decl := t.make_decl_assign_typed(tmp_name, t.make_index(base, t.make_ident(j_name),
914 elem_type), elem_type)
915 prev_idx := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
916 assign_cur := t.make_index_assign(t.make_index(base, t.make_ident(j_name), elem_type), t.make_index(base,
917 prev_idx, elem_type))
918 prev_idx2 := t.make_infix(.minus, t.make_ident(j_name), t.make_int_literal(1))
919 assign_prev := t.make_index_assign(t.make_index(base, prev_idx2, elem_type),
920 t.make_ident(tmp_name))
921 dec_j := t.make_expr_stmt(t.make_postfix(t.make_ident(j_name), .dec))
922 inner_body := [tmp_decl, assign_cur, assign_prev, dec_j]
923 inner_for := t.make_for_stmt(t.make_empty(), inner_cond, t.make_empty(), inner_body, src)
924 return t.make_for_stmt(init, cond, post, [j_decl, inner_for], src)
925}
926
927// array_sort_less_expr supports array sort less expr handling for Transformer.
928fn (mut t Transformer) array_sort_less_expr(base flat.NodeId, elem_type string, idx_name string, cmp_id flat.NodeId) flat.NodeId {
929 cur := t.make_index(base, t.make_ident(idx_name), elem_type)
930 prev := t.make_index(base, t.make_infix(.minus, t.make_ident(idx_name), t.make_int_literal(1)),
931 elem_type)
932 if int(cmp_id) >= 0 {
933 old_a := t.var_type('a')
934 old_b := t.var_type('b')
935 t.set_var_type('a', elem_type)
936 t.set_var_type('b', elem_type)
937 raw_cmp := t.substitute_array_sort_vars(cmp_id, cur, prev)
938 cmp := t.transform_expr(raw_cmp)
939 if old_a.len > 0 {
940 t.set_var_type('a', old_a)
941 } else {
942 t.unset_var_type('a')
943 }
944 if old_b.len > 0 {
945 t.set_var_type('b', old_b)
946 } else {
947 t.unset_var_type('b')
948 }
949 return cmp
950 }
951 if elem_type == 'string' {
952 return t.make_call_typed('string__lt', arr2(cur, prev), 'bool')
953 }
954 return t.make_infix(.lt, cur, prev)
955}
956
957// array_sort_compare_less_expr supports array sort compare less expr handling for Transformer.
958fn (mut t Transformer) array_sort_compare_less_expr(base flat.NodeId, elem_type string, idx_name string, cmp flat.NodeId) flat.NodeId {
959 cur := t.make_index(base, t.make_ident(idx_name), elem_type)
960 prev := t.make_index(base, t.make_infix(.minus, t.make_ident(idx_name), t.make_int_literal(1)),
961 elem_type)
962 call := t.make_call_expr_typed(cmp, arr2(t.make_prefix(.amp, cur), t.make_prefix(.amp, prev)),
963 'int')
964 return t.make_infix(.lt, call, t.make_int_literal(0))
965}
966
967// substitute_array_sort_vars supports substitute array sort vars handling for Transformer.
968fn (mut t Transformer) substitute_array_sort_vars(id flat.NodeId, a_expr flat.NodeId, b_expr flat.NodeId) flat.NodeId {
969 if int(id) < 0 {
970 return id
971 }
972 node := t.a.nodes[int(id)]
973 if node.kind == .ident {
974 if node.value == 'a' {
975 return a_expr
976 }
977 if node.value == 'b' {
978 return b_expr
979 }
980 return id
981 }
982 if node.children_count == 0 {
983 return id
984 }
985 mut children := []flat.NodeId{cap: int(node.children_count)}
986 for i in 0 .. node.children_count {
987 children << t.substitute_array_sort_vars(t.a.child(&node, i), a_expr, b_expr)
988 }
989 start := t.a.children.len
990 for child in children {
991 t.a.children << child
992 }
993 return t.a.add_node(flat.Node{
994 kind: node.kind
995 op: node.op
996 children_start: start
997 children_count: node.children_count
998 pos: node.pos
999 value: node.value
1000 typ: node.typ
1001 })
1002}
1003
1004// make_index_assign builds make index assign data for transform.
1005fn (mut t Transformer) make_index_assign(lhs flat.NodeId, rhs flat.NodeId) flat.NodeId {
1006 start := t.a.children.len
1007 t.a.children << lhs
1008 t.a.children << rhs
1009 return t.a.add_node(flat.Node{
1010 kind: .index_assign
1011 op: .assign
1012 children_start: start
1013 children_count: 2
1014 })
1015}
1016