v4 / vlib / v3 / tests / comptime_top_level_decl_codegen_test.v
173 lines · 153 sloc · 5.06 KB · 1498e02bf64c6e33255fc0d3055b6e72900af9a5
Raw
1import os
2
3const comptime_decl_vexe = @VEXE
4const comptime_decl_tests_dir = os.dir(@FILE)
5const comptime_decl_v3_dir = os.dir(comptime_decl_tests_dir)
6const comptime_decl_vlib_dir = os.dir(comptime_decl_v3_dir)
7const comptime_decl_v3_src = os.join_path(comptime_decl_v3_dir, 'v3.v')
8
9fn comptime_decl_build_v3() string {
10 v3_bin := os.join_path(os.temp_dir(), 'v3_comptime_top_level_decl_test')
11 build :=
12 os.execute('${comptime_decl_vexe} -gc none -path "${comptime_decl_vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${comptime_decl_v3_src}')
13 assert build.exit_code == 0, build.output
14 return v3_bin
15}
16
17fn comptime_decl_count(c_code string, needle string) int {
18 mut count := 0
19 mut rest := c_code
20 for {
21 idx := rest.index(needle) or { break }
22 count++
23 rest = rest[idx + needle.len..]
24 }
25 return count
26}
27
28fn comptime_decl_struct_body(c_code string, name string) string {
29 start := c_code.index('struct ${name} {') or { return '' }
30 rest := c_code[start..]
31 end := rest.index('\n};') or { return rest }
32 return rest[..end]
33}
34
35fn comptime_decl_gen_c(v3_bin string, name string, feature bool) string {
36 root := os.join_path(os.temp_dir(), 'v3_comptime_top_level_decl_${name}_${os.getpid()}')
37 os.rmdir_all(root) or {}
38 os.mkdir_all(root) or { panic(err) }
39 main_path := os.join_path(root, 'main.v')
40 os.write_file(main_path, "module main
41
42$if some_feature ? {
43 struct Choice {
44 x int
45 }
46} $else {
47 struct Choice {}
48}
49
50struct Holder {
51 choice Choice
52}
53
54fn main() {
55 $if some_feature ? {
56 holder := Holder{
57 choice: Choice{
58 x: 1
59 }
60 }
61 println(int_str(holder.choice.x))
62 } $else {
63 holder := Holder{
64 choice: Choice{}
65 }
66 _ = holder
67 println('dummy')
68 }
69}
70") or {
71 panic(err)
72 }
73 bin_path := os.join_path(root, 'out')
74 feature_arg := if feature { '-d some_feature' } else { '' }
75 compile := os.execute('${v3_bin} ${main_path} ${feature_arg} -b c -o ${bin_path}')
76 assert compile.exit_code == 0, '${name}: compile failed: ${compile.output}'
77 c_path := bin_path + '.c'
78 assert os.exists(c_path), '${name}: missing generated C ${c_path}'
79 return os.read_file(c_path) or { panic(err) }
80}
81
82fn comptime_decl_gen_c_source(v3_bin string, name string, source string, flags string) string {
83 root := os.join_path(os.temp_dir(), 'v3_comptime_top_level_decl_${name}_${os.getpid()}')
84 os.rmdir_all(root) or {}
85 os.mkdir_all(root) or { panic(err) }
86 main_path := os.join_path(root, 'main.v')
87 os.write_file(main_path, source) or { panic(err) }
88 c_path := os.join_path(root, 'out.c')
89 compile := os.execute('${v3_bin} ${main_path} ${flags} -b c -o ${c_path}')
90 assert compile.exit_code == 0, '${name}: C output failed: ${compile.output}'
91 assert os.exists(c_path), '${name}: missing generated C ${c_path}'
92 return os.read_file(c_path) or { panic(err) }
93}
94
95fn comptime_decl_compile_run_source(v3_bin string, name string, source string, flags string) os.Result {
96 root := os.join_path(os.temp_dir(), 'v3_comptime_top_level_decl_run_${name}_${os.getpid()}')
97 os.rmdir_all(root) or {}
98 os.mkdir_all(root) or { panic(err) }
99 main_path := os.join_path(root, 'main.v')
100 os.write_file(main_path, source) or { panic(err) }
101 bin_path := os.join_path(root, 'out')
102 compile := os.execute('${v3_bin} ${main_path} ${flags} -o ${bin_path}')
103 assert compile.exit_code == 0, '${name}: compile failed: ${compile.output}'
104 return os.execute(bin_path)
105}
106
107fn test_top_level_decls_inside_active_comptime_branch_are_codegen_visible() {
108 v3_bin := comptime_decl_build_v3()
109 else_c := comptime_decl_gen_c(v3_bin, 'else_branch', false)
110 else_choice := comptime_decl_struct_body(else_c, 'Choice')
111 assert comptime_decl_count(else_c, 'struct Choice {') == 1, else_c
112 assert else_choice.contains('_dummy'), else_c
113 assert !else_choice.contains('int x;'), else_c
114
115 feature_c := comptime_decl_gen_c(v3_bin, 'feature_branch', true)
116 feature_choice := comptime_decl_struct_body(feature_c, 'Choice')
117 assert comptime_decl_count(feature_c, 'struct Choice {') == 1, feature_c
118 assert feature_choice.contains('int x;'), feature_c
119 assert !feature_choice.contains('_dummy'), feature_c
120}
121
122fn test_declaration_only_top_level_comptime_block_does_not_synthesize_main() {
123 v3_bin := comptime_decl_build_v3()
124 c_code := comptime_decl_gen_c_source(v3_bin, 'decl_only_no_main', 'module main
125
126$if some_feature ? {
127 fn helper() int {
128 return 3
129 }
130} $else {
131 struct Helper {}
132}
133',
134 '-d some_feature')
135 assert !c_code.contains('int main('), c_code
136}
137
138fn test_top_level_comptime_block_with_statement_still_synthesizes_main() {
139 v3_bin := comptime_decl_build_v3()
140 c_code := comptime_decl_gen_c_source(v3_bin, 'stmt_synth_main', "module main
141
142$if some_feature ? {
143 println('active')
144} $else {
145 fn helper() int {
146 return 3
147 }
148}
149",
150 '-d some_feature')
151 assert c_code.contains('int main('), c_code
152 assert c_code.contains('active'), c_code
153}
154
155fn test_synthetic_top_level_block_keeps_main_scope_locals() {
156 v3_bin := comptime_decl_build_v3()
157 run := comptime_decl_compile_run_source(v3_bin, 'synthetic_block_main_scope', 'module main
158
159$if some_feature ? {
160 x := 1
161 y := 2
162}
163
164fn helper() int {
165 return 0
166}
167
168println(int_str(x + y))
169',
170 '-d some_feature')
171 assert run.exit_code == 0, run.output
172 assert run.output.trim_space() == '3'
173}
174