v4 / vlib / v3 / tests / transformer_parity_test.v
603 lines · 564 sloc · 15.03 KB · 288feee4702b35beadb4037d02b96b5c8674156b
Raw
1import os
2import v3.flat
3import v3.parser
4import v3.pref
5import v3.transform
6import v3.types
7
8// parse_transform_source reads parse transform source input for v3 tests.
9fn parse_transform_source(source string) &flat.FlatAst {
10 src := os.join_path(os.temp_dir(), 'v3_transformer_parity_test.v')
11 return parse_transform_file(src, source)
12}
13
14// parse_transform_file reads parse transform file input for v3 tests.
15fn parse_transform_file(src string, source string) &flat.FlatAst {
16 os.write_file(src, source) or { panic(err) }
17 prefs := pref.new_preferences()
18 mut p := parser.Parser.new(prefs)
19 mut a := p.parse_file(src)
20 mut tc := types.TypeChecker.new(a)
21 tc.collect(a)
22 tc.annotate_types()
23 transform.transform(mut a, &tc)
24 return a
25}
26
27// find_fn resolves find fn information for v3 tests.
28fn find_fn(a &flat.FlatAst, name string) flat.Node {
29 for node in a.nodes {
30 if node.kind == .fn_decl && node.value == name {
31 return node
32 }
33 }
34 assert false
35 return flat.Node{}
36}
37
38// first_decl_rhs returns first decl rhs data for v3 tests.
39fn first_decl_rhs(a &flat.FlatAst, fn_name string) flat.Node {
40 f := find_fn(a, fn_name)
41 for i in 0 .. f.children_count {
42 stmt := a.child_node(&f, i)
43 if stmt.kind == .decl_assign && stmt.children_count == 2 {
44 return *a.child_node(stmt, 1)
45 }
46 }
47 assert false
48 return flat.Node{}
49}
50
51// decl_rhs supports decl rhs handling for v3 tests.
52fn decl_rhs(a &flat.FlatAst, fn_name string, name string) flat.Node {
53 f := find_fn(a, fn_name)
54 for i in 0 .. f.children_count {
55 stmt := a.child_node(&f, i)
56 if stmt.kind == .decl_assign && stmt.children_count == 2 {
57 lhs := a.child_node(stmt, 0)
58 if lhs.kind == .ident && lhs.value == name {
59 return *a.child_node(stmt, 1)
60 }
61 }
62 }
63 assert false
64 return flat.Node{}
65}
66
67// first_return_expr returns first return expr data for v3 tests.
68fn first_return_expr(a &flat.FlatAst, fn_name string) flat.Node {
69 f := find_fn(a, fn_name)
70 for i in 0 .. f.children_count {
71 stmt := a.child_node(&f, i)
72 if stmt.kind == .return_stmt && stmt.children_count > 0 {
73 return *a.child_node(stmt, 0)
74 }
75 }
76 assert false
77 return flat.Node{}
78}
79
80// count_kind supports count kind handling for v3 tests.
81fn count_kind(a &flat.FlatAst, id flat.NodeId, kind flat.NodeKind) int {
82 if int(id) < 0 {
83 return 0
84 }
85 node := a.nodes[int(id)]
86 mut total := if node.kind == kind { 1 } else { 0 }
87 for i in 0 .. node.children_count {
88 total += count_kind(a, a.child(&node, i), kind)
89 }
90 return total
91}
92
93// count_call_name supports count call name handling for v3 tests.
94fn count_call_name(a &flat.FlatAst, id flat.NodeId, name string) int {
95 if int(id) < 0 {
96 return 0
97 }
98 node := a.nodes[int(id)]
99 mut total := 0
100 if node.kind == .call && node.children_count > 0 {
101 fn_node := a.child_node(&node, 0)
102 if fn_node.kind == .ident && fn_node.value == name {
103 total++
104 }
105 }
106 for i in 0 .. node.children_count {
107 total += count_call_name(a, a.child(&node, i), name)
108 }
109 return total
110}
111
112// count_infix_op supports count infix op handling for v3 tests.
113fn count_infix_op(a &flat.FlatAst, id flat.NodeId, op flat.Op) int {
114 if int(id) < 0 {
115 return 0
116 }
117 node := a.nodes[int(id)]
118 mut total := if node.kind == .infix && node.op == op { 1 } else { 0 }
119 for i in 0 .. node.children_count {
120 total += count_infix_op(a, a.child(&node, i), op)
121 }
122 return total
123}
124
125// count_wide_decl_assigns supports count wide decl assigns handling for v3 tests.
126fn count_wide_decl_assigns(a &flat.FlatAst, id flat.NodeId) int {
127 if int(id) < 0 {
128 return 0
129 }
130 node := a.nodes[int(id)]
131 mut total := if node.kind == .decl_assign && node.children_count > 2 { 1 } else { 0 }
132 for i in 0 .. node.children_count {
133 total += count_wide_decl_assigns(a, a.child(&node, i))
134 }
135 return total
136}
137
138// count_wide_assigns supports count wide assigns handling for v3 tests.
139fn count_wide_assigns(a &flat.FlatAst, id flat.NodeId) int {
140 if int(id) < 0 {
141 return 0
142 }
143 node := a.nodes[int(id)]
144 mut total := if node.kind == .assign && node.children_count > 2 { 1 } else { 0 }
145 for i in 0 .. node.children_count {
146 total += count_wide_assigns(a, a.child(&node, i))
147 }
148 return total
149}
150
151// count_selector_value supports count selector value handling for v3 tests.
152fn count_selector_value(a &flat.FlatAst, id flat.NodeId, value string) int {
153 if int(id) < 0 {
154 return 0
155 }
156 node := a.nodes[int(id)]
157 mut total := if node.kind == .selector && node.value == value { 1 } else { 0 }
158 for i in 0 .. node.children_count {
159 total += count_selector_value(a, a.child(&node, i), value)
160 }
161 return total
162}
163
164// test_typeof_expression_lowers_to_string_literal validates this v3 regression case.
165fn test_typeof_expression_lowers_to_string_literal() {
166 a := parse_transform_source('
167fn main() {
168 name := typeof(123)
169}
170')
171 main_fn := find_fn(a, 'main')
172 for i in 0 .. main_fn.children_count {
173 stmt := a.child_node(&main_fn, i)
174 if stmt.kind == .decl_assign && stmt.children_count == 2 {
175 rhs := a.child_node(stmt, 1)
176 assert rhs.kind == .string_literal
177 assert rhs.value == 'int literal'
178 return
179 }
180 }
181 assert false
182}
183
184// test_vmodroot_lowers_to_nearest_vmod_dir validates this v3 regression case.
185fn test_vmodroot_lowers_to_nearest_vmod_dir() {
186 root := os.join_path(os.temp_dir(), 'v3_vmodroot_transformer_parity')
187 os.mkdir_all(root) or { panic(err) }
188 os.write_file(os.join_path(root, 'v.mod'), 'Module { name: "parity" }') or { panic(err) }
189 src := os.join_path(root, 'main.v')
190 a := parse_transform_file(src, '
191fn main() {
192 root := @VMODROOT
193}
194')
195 rhs := first_decl_rhs(a, 'main')
196 assert rhs.kind == .string_literal
197 assert rhs.value == root
198}
199
200// test_return_match_lowers_to_explicit_branch_returns validates this v3 regression case.
201fn test_return_match_lowers_to_explicit_branch_returns() {
202 a := parse_transform_source('
203fn choose(x int) int {
204 return match x {
205 0 {
206 10
207 }
208 else {
209 20
210 }
211 }
212}
213')
214 choose_fn := find_fn(a, 'choose')
215 mut match_count := 0
216 mut return_count := 0
217 for i in 0 .. choose_fn.children_count {
218 child_id := a.child(&choose_fn, i)
219 match_count += count_kind(a, child_id, .match_stmt)
220 return_count += count_kind(a, child_id, .return_stmt)
221 }
222 assert match_count == 0
223 assert return_count == 2
224}
225
226// test_return_if_keeps_or_lowering_inside_branch validates this v3 regression case.
227fn test_return_if_keeps_or_lowering_inside_branch() {
228 a := parse_transform_source('
229fn maybe_int() ?int {
230 return 8
231}
232
233fn choose(flag bool) int {
234 return if flag {
235 maybe_int() or {
236 1
237 }
238 } else {
239 2
240 }
241}
242')
243 choose_fn := find_fn(a, 'choose')
244 mut body_ids := []flat.NodeId{}
245 for i in 0 .. choose_fn.children_count {
246 child_id := a.child(&choose_fn, i)
247 child := a.nodes[int(child_id)]
248 if child.kind != .param {
249 body_ids << child_id
250 }
251 }
252 assert body_ids.len == 1
253 assert a.nodes[int(body_ids[0])].kind == .if_expr
254}
255
256// test_if_expr_value_lowers_to_temp_and_branch_assigns validates this v3 regression case.
257fn test_if_expr_value_lowers_to_temp_and_branch_assigns() {
258 a := parse_transform_source('
259fn main() {
260 x := if true {
261 1
262 } else {
263 2
264 }
265}
266')
267 rhs := decl_rhs(a, 'main', 'x')
268 assert rhs.kind == .ident
269 assert rhs.value.starts_with('__if_val_')
270 main_fn := find_fn(a, 'main')
271 mut if_count := 0
272 mut assign_count := 0
273 for i in 0 .. main_fn.children_count {
274 child_id := a.child(&main_fn, i)
275 if_count += count_kind(a, child_id, .if_expr)
276 assign_count += count_kind(a, child_id, .assign)
277 }
278 assert if_count == 1
279 assert assign_count == 2
280}
281
282// test_if_expr_call_arg_lowers_before_call validates this v3 regression case.
283fn test_if_expr_call_arg_lowers_before_call() {
284 a := parse_transform_source('
285fn use(x int) int {
286 return x
287}
288
289fn main() {
290 x := use(if true { 1 } else { 2 })
291}
292')
293 rhs := decl_rhs(a, 'main', 'x')
294 assert rhs.kind == .call
295 assert rhs.children_count == 2
296 arg := a.child_node(&rhs, 1)
297 assert arg.kind == .ident
298 assert arg.value.starts_with('__if_val_')
299}
300
301// test_nested_if_expr_branch_lowers_to_outer_temp_assignment validates this v3 regression case.
302fn test_nested_if_expr_branch_lowers_to_outer_temp_assignment() {
303 a := parse_transform_source('
304fn main() {
305 x := if true {
306 if false {
307 1
308 } else {
309 2
310 }
311 } else {
312 3
313 }
314}
315')
316 rhs := decl_rhs(a, 'main', 'x')
317 assert rhs.kind == .ident
318 assert rhs.value.starts_with('__if_val_')
319 main_fn := find_fn(a, 'main')
320 mut if_count := 0
321 mut assign_count := 0
322 for i in 0 .. main_fn.children_count {
323 child_id := a.child(&main_fn, i)
324 if_count += count_kind(a, child_id, .if_expr)
325 assign_count += count_kind(a, child_id, .assign)
326 }
327 assert if_count == 2
328 assert assign_count == 4
329}
330
331// test_multi_return_decl_lowers_to_temp_field_decls validates this v3 regression case.
332fn test_multi_return_decl_lowers_to_temp_field_decls() {
333 a := parse_transform_source("
334fn pair() (int, string) {
335 return 1, 'ok'
336}
337
338fn main() {
339 a, b := pair()
340}
341")
342 main_fn := find_fn(a, 'main')
343 mut wide_decl_count := 0
344 for i in 0 .. main_fn.children_count {
345 wide_decl_count += count_wide_decl_assigns(a, a.child(&main_fn, i))
346 }
347 assert wide_decl_count == 0
348 a_rhs := decl_rhs(a, 'main', 'a')
349 b_rhs := decl_rhs(a, 'main', 'b')
350 assert a_rhs.kind == .selector
351 assert a_rhs.value == 'arg0'
352 assert b_rhs.kind == .selector
353 assert b_rhs.value == 'arg1'
354}
355
356// test_multi_return_assign_lowers_to_temp_field_assigns validates this v3 regression case.
357fn test_multi_return_assign_lowers_to_temp_field_assigns() {
358 a := parse_transform_source("
359fn pair() (int, string) {
360 return 1, 'ok'
361}
362
363fn main() {
364 mut a := 0
365 mut b := ''
366 a, b = pair()
367}
368")
369 main_fn := find_fn(a, 'main')
370 mut wide_assign_count := 0
371 mut arg0_count := 0
372 mut arg1_count := 0
373 for i in 0 .. main_fn.children_count {
374 child_id := a.child(&main_fn, i)
375 wide_assign_count += count_wide_assigns(a, child_id)
376 arg0_count += count_selector_value(a, child_id, 'arg0')
377 arg1_count += count_selector_value(a, child_id, 'arg1')
378 }
379 assert wide_assign_count == 0
380 assert arg0_count == 1
381 assert arg1_count == 1
382}
383
384// test_assoc_expr_lowers_to_temp_and_field_assigns validates this v3 regression case.
385fn test_assoc_expr_lowers_to_temp_and_field_assigns() {
386 a := parse_transform_source('
387struct Point {
388 x int
389 y int
390}
391
392fn main() {
393 p := Point{x: 1, y: 2}
394 q := Point{...p, y: 3}
395}
396')
397 rhs := decl_rhs(a, 'main', 'q')
398 assert rhs.kind == .ident
399 assert rhs.value.starts_with('__assoc_')
400 main_fn := find_fn(a, 'main')
401 mut assoc_count := 0
402 mut assign_count := 0
403 for i in 0 .. main_fn.children_count {
404 child_id := a.child(&main_fn, i)
405 assoc_count += count_kind(a, child_id, .assoc)
406 assign_count += count_kind(a, child_id, .assign)
407 }
408 assert assoc_count == 0
409 assert assign_count == 1
410}
411
412// test_return_assoc_expr_lowers_before_return validates this v3 regression case.
413fn test_return_assoc_expr_lowers_before_return() {
414 a := parse_transform_source('
415struct Point {
416 x int
417 y int
418}
419
420fn moved(p Point) Point {
421 return Point{...p, x: 4}
422}
423')
424 ret := first_return_expr(a, 'moved')
425 assert ret.kind == .ident
426 assert ret.value.starts_with('__assoc_')
427 moved_fn := find_fn(a, 'moved')
428 mut assoc_count := 0
429 for i in 0 .. moved_fn.children_count {
430 assoc_count += count_kind(a, a.child(&moved_fn, i), .assoc)
431 }
432 assert assoc_count == 0
433}
434
435// test_array_append_stmt_lowers_to_runtime_push validates this v3 regression case.
436fn test_array_append_stmt_lowers_to_runtime_push() {
437 a := parse_transform_source('
438fn main() {
439 mut xs := []int{}
440 xs << 3
441}
442')
443 main_fn := find_fn(a, 'main')
444 mut push_count := 0
445 mut left_shift_count := 0
446 for i in 0 .. main_fn.children_count {
447 child_id := a.child(&main_fn, i)
448 push_count += count_call_name(a, child_id, 'array_push')
449 left_shift_count += count_infix_op(a, child_id, .left_shift)
450 }
451 assert push_count == 1
452 assert left_shift_count == 0
453}
454
455// test_array_append_many_stmt_lowers_to_runtime_push_many validates this v3 regression case.
456fn test_array_append_many_stmt_lowers_to_runtime_push_many() {
457 a := parse_transform_source('
458fn main() {
459 mut xs := []int{}
460 ys := []int{}
461 xs << ys
462}
463')
464 main_fn := find_fn(a, 'main')
465 mut push_many_count := 0
466 mut left_shift_count := 0
467 for i in 0 .. main_fn.children_count {
468 child_id := a.child(&main_fn, i)
469 push_many_count += count_call_name(a, child_id, 'array__push_many')
470 left_shift_count += count_infix_op(a, child_id, .left_shift)
471 }
472 assert push_many_count == 1
473 assert left_shift_count == 0
474}
475
476fn test_array_push_many_method_lowers_to_runtime_ptr_call() {
477 a := parse_transform_source('
478fn main() {
479 mut xs := []u8{}
480 mut b := u8(7)
481 unsafe {
482 xs.push_many(&b, 1)
483 }
484}
485')
486 main_fn := find_fn(a, 'main')
487 mut push_many_ptr_count := 0
488 mut push_many_selector_count := 0
489 for i in 0 .. main_fn.children_count {
490 child_id := a.child(&main_fn, i)
491 push_many_ptr_count += count_call_name(a, child_id, 'array_push_many_ptr')
492 push_many_selector_count += count_selector_value(a, child_id, 'push_many')
493 }
494 assert push_many_ptr_count == 1
495 assert push_many_selector_count == 0
496}
497
498fn test_array_push_many_type_marker_lowers_to_runtime_ptr_call() {
499 a := parse_transform_source('
500struct PushManyItem {
501 value int
502}
503
504fn main() {
505 mut xs := []PushManyItem{}
506 item := PushManyItem{value: 7}
507 xs.push_many(item, PushManyItem)
508}
509')
510 main_fn := find_fn(a, 'main')
511 mut push_many_ptr_count := 0
512 mut push_many_selector_count := 0
513 for i in 0 .. main_fn.children_count {
514 child_id := a.child(&main_fn, i)
515 push_many_ptr_count += count_call_name(a, child_id, 'array_push_many_ptr')
516 push_many_selector_count += count_selector_value(a, child_id, 'push_many')
517 }
518 assert push_many_ptr_count == 1
519 assert push_many_selector_count == 0
520}
521
522fn test_sql_expr_lowers_to_success_result_default() {
523 a := parse_transform_source('
524struct User {
525 id int
526}
527
528fn main() {
529 db := 0
530 users := sql db {
531 select from User
532 }
533 count := sql db {
534 select count from User
535 }
536 created := sql db {
537 create table User
538 }
539}
540')
541 main_fn := find_fn(a, 'main')
542 mut sql_expr_count := 0
543 for i in 0 .. main_fn.children_count {
544 sql_expr_count += count_kind(a, a.child(&main_fn, i), .sql_expr)
545 }
546 assert sql_expr_count == 0
547 users := decl_rhs(a, 'main', 'users')
548 assert users.kind == .struct_init
549 assert users.value == '![]User'
550 count := decl_rhs(a, 'main', 'count')
551 assert count.kind == .struct_init
552 assert count.value == '!int'
553 created := decl_rhs(a, 'main', 'created')
554 assert created.kind == .struct_init
555 assert created.value == '!void'
556}
557
558// test_or_expr_lowers_to_temp_and_if validates this v3 regression case.
559fn test_or_expr_lowers_to_temp_and_if() {
560 a := parse_transform_source('
561fn maybe_int() ?int {
562 return 3
563}
564
565fn main() {
566 x := maybe_int() or {
567 7
568 }
569}
570')
571 main_fn := find_fn(a, 'main')
572 mut or_count := 0
573 mut if_count := 0
574 for i in 0 .. main_fn.children_count {
575 child_id := a.child(&main_fn, i)
576 or_count += count_kind(a, child_id, .or_expr)
577 if_count += count_kind(a, child_id, .if_expr)
578 }
579 assert or_count == 0
580 assert if_count == 1
581}
582
583// test_map_index_or_lowers_to_get_check validates this v3 regression case.
584fn test_map_index_or_lowers_to_get_check() {
585 a := parse_transform_source('
586fn main() {
587 mut m := map[string]int{}
588 x := m["a"] or {
589 7
590 }
591}
592')
593 main_fn := find_fn(a, 'main')
594 mut or_count := 0
595 mut get_check_count := 0
596 for i in 0 .. main_fn.children_count {
597 child_id := a.child(&main_fn, i)
598 or_count += count_kind(a, child_id, .or_expr)
599 get_check_count += count_call_name(a, child_id, 'map__get_check')
600 }
601 assert or_count == 0
602 assert get_check_count == 1
603}
604