v / vlib / v2 / transformer / comptime_optional_test.v
167 lines · 150 sloc · 4.52 KB · 10a27a35f62541cee8c09d75d37629f27d89d055
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module transformer
5
6import os
7import v2.ast
8import v2.parser
9import v2.pref as vpref
10import v2.token
11import v2.types
12
13fn parse_optional_test_code(code string, target_os string, defines []string) []ast.File {
14 tmp_file := '/tmp/v2_parser_optional_cond_test_${os.getpid()}.v'
15 os.write_file(tmp_file, code) or { panic('failed to write temp file') }
16 defer {
17 os.rm(tmp_file) or {}
18 }
19 prefs := &vpref.Preferences{
20 backend: .cleanc
21 no_parallel: true
22 target_os: target_os
23 user_defines: defines
24 explicit_user_defines: defines.clone()
25 }
26 mut file_set := token.FileSet.new()
27 mut par := parser.Parser.new(prefs)
28 return par.parse_files([tmp_file], mut file_set)
29}
30
31fn transform_optional_test_code(code string, target_os string, defines []string) []ast.File {
32 tmp_file := '/tmp/v2_transformer_optional_cond_test_${os.getpid()}.v'
33 os.write_file(tmp_file, code) or { panic('failed to write temp file') }
34 defer {
35 os.rm(tmp_file) or {}
36 }
37 prefs := &vpref.Preferences{
38 backend: .cleanc
39 no_parallel: true
40 target_os: target_os
41 user_defines: defines
42 explicit_user_defines: defines.clone()
43 }
44 mut file_set := token.FileSet.new()
45 mut par := parser.Parser.new(prefs)
46 files := par.parse_files([tmp_file], mut file_set)
47 mut env := types.Environment.new()
48 mut checker := types.Checker.new(prefs, file_set, env)
49 checker.check_files(files)
50 mut trans := Transformer.new_with_pref(env, prefs)
51 return trans.transform_files(files)
52}
53
54fn optional_test_struct_field_names(file ast.File, struct_name string) []string {
55 for stmt in file.stmts {
56 if stmt is ast.StructDecl && stmt.name == struct_name {
57 mut names := []string{cap: stmt.fields.len}
58 for field in stmt.fields {
59 names << field.name
60 }
61 return names
62 }
63 }
64 return []string{}
65}
66
67fn optional_test_fn_stmt_count(files []ast.File, name string) int {
68 for file in files {
69 for stmt in file.stmts {
70 if stmt is ast.FnDecl && stmt.name == name {
71 return stmt.stmts.len
72 }
73 }
74 }
75 return -1
76}
77
78fn optional_test_first_return_number(files []ast.File, name string) string {
79 for file in files {
80 for stmt in file.stmts {
81 if stmt is ast.FnDecl && stmt.name == name {
82 for nested in stmt.stmts {
83 if nested is ast.ReturnStmt && nested.exprs.len == 1
84 && nested.exprs[0] is ast.BasicLiteral {
85 return (nested.exprs[0] as ast.BasicLiteral).value
86 }
87 }
88 }
89 }
90 }
91 return ''
92}
93
94fn test_parser_struct_field_attr_optional_os_requires_user_define() {
95 source := '
96module main
97
98struct Container {
99 name string
100 plain_linux int @[if linux]
101 optional_linux int @[if linux ?]
102}
103'
104 no_define_files := parse_optional_test_code(source, 'linux', [])
105 assert no_define_files.len == 1
106 assert optional_test_struct_field_names(no_define_files[0], 'Container') == [
107 'name',
108 'plain_linux',
109 ]
110
111 defined_files := parse_optional_test_code(source, 'linux', ['linux'])
112 assert defined_files.len == 1
113 assert optional_test_struct_field_names(defined_files[0], 'Container') == ['name', 'plain_linux',
114 'optional_linux']
115}
116
117fn test_transformer_comptime_optional_os_requires_user_define() {
118 source := '
119module main
120
121fn optional_branch() int {
122 $if linux ? {
123 return 1
124 } $else {
125 return 2
126 }
127}
128
129fn plain_os_branch() int {
130 $if linux {
131 return 3
132 } $else {
133 return 4
134 }
135}
136'
137 no_define_files := transform_optional_test_code(source, 'linux', [])
138 assert optional_test_first_return_number(no_define_files, 'optional_branch') == '2'
139 assert optional_test_first_return_number(no_define_files, 'plain_os_branch') == '3'
140
141 defined_files := transform_optional_test_code(source, 'linux', ['linux'])
142 assert optional_test_first_return_number(defined_files, 'optional_branch') == '1'
143 assert optional_test_first_return_number(defined_files, 'plain_os_branch') == '3'
144}
145
146fn test_transformer_function_attr_optional_os_requires_user_define() {
147 source := '
148module main
149
150@[if linux ?]
151fn optional_fn() int {
152 return 1
153}
154
155@[if linux]
156fn plain_os_fn() int {
157 return 2
158}
159'
160 no_define_files := transform_optional_test_code(source, 'linux', [])
161 assert optional_test_fn_stmt_count(no_define_files, 'optional_fn') == 0
162 assert optional_test_fn_stmt_count(no_define_files, 'plain_os_fn') > 0
163
164 defined_files := transform_optional_test_code(source, 'linux', ['linux'])
165 assert optional_test_fn_stmt_count(defined_files, 'optional_fn') > 0
166 assert optional_test_fn_stmt_count(defined_files, 'plain_os_fn') > 0
167}
168