vxx2 / vlib / v3 / tests / mini_calculator_markused_codegen_test.v
307 lines · 253 sloc · 7.96 KB · 288feee4702b35beadb4037d02b96b5c8674156b
Raw
1import os
2
3const mini_calc_vexe = @VEXE
4const mini_calc_tests_dir = os.dir(@FILE)
5const mini_calc_v3_dir = os.dir(mini_calc_tests_dir)
6const mini_calc_vlib_dir = os.dir(mini_calc_v3_dir)
7const mini_calc_v3_src = os.join_path(mini_calc_v3_dir, 'v3.v')
8const mini_calc_repo_root = os.dir(mini_calc_vlib_dir)
9
10fn mini_calc_build_v3() string {
11 v3_bin := os.join_path(os.temp_dir(), 'v3_mini_calc_markused_test_${os.getpid()}')
12 os.rm(v3_bin) or {}
13 build :=
14 os.execute('${mini_calc_vexe} -gc none -path "${mini_calc_vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${mini_calc_v3_src}')
15 assert build.exit_code == 0, build.output
16 return v3_bin
17}
18
19fn mini_calc_write_file(root string, rel string, src string) {
20 path := os.join_path(root, rel)
21 os.mkdir_all(os.dir(path)) or { panic(err) }
22 os.write_file(path, src) or { panic(err) }
23}
24
25fn mini_calc_compile_run(v3_bin string, name string, files map[string]string, main_file string) (string, string) {
26 root := os.join_path(os.temp_dir(), 'v3_mini_calc_markused_${name}_${os.getpid()}')
27 os.rmdir_all(root) or {}
28 mini_calc_write_file(root, 'v.mod', "Module { name: 'mini_calc_markused' }\n")
29 for rel, src in files {
30 mini_calc_write_file(root, rel, src)
31 }
32 main_path := os.join_path(root, main_file)
33 bin := os.join_path(root, 'out')
34 compile := os.execute('${v3_bin} ${main_path} -b c -o ${bin}')
35 assert compile.exit_code == 0, compile.output
36 run := os.execute(bin)
37 assert run.exit_code == 0, run.output
38 generated := os.read_file(bin + '.c') or { panic(err) }
39 return run.output.trim_space(), generated
40}
41
42fn mini_calc_compile_bad(v3_bin string, name string, files map[string]string, main_file string) string {
43 root := os.join_path(os.temp_dir(), 'v3_mini_calc_markused_bad_${name}_${os.getpid()}')
44 os.rmdir_all(root) or {}
45 mini_calc_write_file(root, 'v.mod', "Module { name: 'mini_calc_markused_bad' }\n")
46 for rel, src in files {
47 mini_calc_write_file(root, rel, src)
48 }
49 main_path := os.join_path(root, main_file)
50 bin := os.join_path(root, 'out')
51 compile := os.execute('${v3_bin} ${main_path} -b c -o ${bin}')
52 assert compile.exit_code != 0, '${name}: compile unexpectedly succeeded: ${compile.output}'
53 return compile.output
54}
55
56fn test_top_level_for_local_receiver_roots_recursive_chain_only() {
57 v3_bin := mini_calc_build_v3()
58 output, generated := mini_calc_compile_run(v3_bin, 'for_top_level_receiver', {
59 'main.v': 'module main
60
61struct Parser {}
62
63fn (mut p Parser) expr() !int {
64 return p.term()!
65}
66
67fn (mut p Parser) term() !int {
68 return 8
69}
70
71fn (mut p Parser) unused() !int {
72 return 99
73}
74
75for i := 0; i < 1; i++ {
76 mut parser := Parser{}
77 result := parser.expr() or { 0 }
78 println(int_str(result))
79}
80'
81 }, 'main.v')
82 assert output == '8'
83 assert generated.contains('Parser__expr('), generated
84 assert generated.contains('Parser__term('), generated
85 assert !generated.contains('Parser__unused('), generated
86}
87
88fn test_top_level_future_local_receiver_is_not_rooted() {
89 v3_bin := mini_calc_build_v3()
90 output := mini_calc_compile_bad(v3_bin, 'future_local_receiver', {
91 'main.v': 'module main
92
93struct Parser {}
94
95fn (mut p Parser) expr() !int {
96 return 7
97}
98
99result := parser.expr() or { 0 }
100mut parser := Parser{}
101println(int_str(result))
102'
103 }, 'main.v')
104 assert output.contains('unknown function `parser.expr`') || output.contains('unknown__expr')
105 || output.contains('C compilation failed'), output
106}
107
108fn test_top_level_same_declaration_receiver_is_not_rooted() {
109 v3_bin := mini_calc_build_v3()
110 output := mini_calc_compile_bad(v3_bin, 'same_decl_receiver', {
111 'main.v': 'module main
112
113struct Parser {}
114
115fn (mut p Parser) expr() !int {
116 return 7
117}
118
119parser := parser.expr() or { 0 }
120println(int_str(parser))
121'
122 }, 'main.v')
123 assert output.contains('unknown function `parser.expr`') || output.contains('unknown__expr')
124 || output.contains('C compilation failed'), output
125}
126
127fn test_top_level_multi_decl_same_statement_receiver_is_not_rooted() {
128 v3_bin := mini_calc_build_v3()
129 output := mini_calc_compile_bad(v3_bin, 'multi_decl_same_statement_receiver', {
130 'main.v': 'module main
131
132struct Parser {}
133
134fn (mut p Parser) expr() !int {
135 return 7
136}
137
138parser, result := Parser{}, parser.expr() or { 0 }
139_ := parser
140println(int_str(result))
141'
142 }, 'main.v')
143 assert output.contains('unknown function `parser.expr`') || output.contains('unknown__expr')
144 || output.contains('C compilation failed'), output
145}
146
147fn test_top_level_block_and_if_scope_do_not_leak_receiver_type() {
148 v3_bin := mini_calc_build_v3()
149 output, generated := mini_calc_compile_run(v3_bin, 'block_scope', {
150 'main.v': 'module main
151
152struct Parser {}
153
154fn (mut p Parser) expr() !int {
155 return 1
156}
157
158{
159 mut parser := Parser{}
160 _ := parser
161}
162if true {
163 mut parser := Parser{}
164 _ := parser
165}
166println("ok")
167'
168 }, 'main.v')
169 assert output == 'ok'
170 assert !generated.contains('Parser__expr('), generated
171}
172
173fn test_explicit_main_ignores_top_level_receiver_calls() {
174 v3_bin := mini_calc_build_v3()
175 output, generated := mini_calc_compile_run(v3_bin, 'explicit_main', {
176 'main.v': 'module main
177
178struct Parser {}
179
180fn (mut p Parser) expr() !int {
181 return p.term()!
182}
183
184fn (mut p Parser) term() !int {
185 return 7
186}
187
188mut parser := Parser{}
189_ := parser.expr() or { 0 }
190
191fn main() {
192 println("entry")
193}
194'
195 }, 'main.v')
196 assert output == 'entry'
197 assert !generated.contains('Parser__expr('), generated
198 assert !generated.contains('Parser__term('), generated
199}
200
201fn test_top_level_local_receiver_does_not_root_imported_homonym() {
202 v3_bin := mini_calc_build_v3()
203 output, generated := mini_calc_compile_run(v3_bin, 'imported_homonym', {
204 'main.v': 'module main
205
206import othermod
207
208struct Parser {}
209
210fn (mut p Parser) expr() !int {
211 return 5
212}
213
214mut parser := Parser{}
215println(int_str(parser.expr() or { 0 }))
216println(int_str(othermod.touch()))
217'
218 'othermod/mod.v': 'module othermod
219
220pub struct Parser {}
221
222pub fn touch() int {
223 return 2
224}
225
226pub fn (mut p Parser) expr() !int {
227 return 100
228}
229'
230 }, 'main.v')
231 assert output == '5\n2'
232 assert generated.contains('Parser__expr('), generated
233 assert !generated.contains('othermod__Parser__expr('), generated
234}
235
236fn test_top_level_local_receiver_shadows_module_alias() {
237 v3_bin := mini_calc_build_v3()
238 output, generated := mini_calc_compile_run(v3_bin, 'local_receiver_alias_shadow', {
239 'main.v': 'module main
240
241import parsermod as parser
242
243struct Parser {}
244
245fn (mut p Parser) expr() !int {
246 return 12
247}
248
249mut parser := Parser{}
250println(int_str(parser.expr() or { 0 }))
251'
252 'parsermod/mod.v': 'module parsermod
253
254pub fn expr() int {
255 return 3
256}
257'
258 }, 'main.v')
259 assert output == '12'
260 assert generated.contains('Parser__expr('), generated
261 assert !generated.contains('parsermod__expr('), generated
262}
263
264fn test_top_level_import_alias_then_local_receiver_shadow_direct_calls() {
265 v3_bin := mini_calc_build_v3()
266 output, generated := mini_calc_compile_run(v3_bin, 'import_alias_then_local_receiver_shadow', {
267 'main.v': 'module main
268
269import parsermod as parser
270
271struct Parser {}
272
273fn (mut p Parser) expr() !int {
274 return 99
275}
276
277println(int_str(parser.expr()))
278mut parser := Parser{}
279println(int_str(parser.expr() or { 0 }))
280'
281 'parsermod/mod.v': 'module parsermod
282
283pub fn expr() int {
284 return 17
285}
286'
287 }, 'main.v')
288 assert output == '17\n99'
289 assert generated.contains('parsermod__expr('), generated
290 assert generated.contains('Parser__expr('), generated
291}
292
293fn test_mini_calculator_recursive_descent_compiles_and_runs() {
294 v3_bin := mini_calc_build_v3()
295 example := os.join_path(mini_calc_repo_root, 'examples', 'mini_calculator_recursive_descent.v')
296 bin := os.join_path(os.temp_dir(), 'v3_mini_calculator_recursive_descent_${os.getpid()}')
297 compile := os.execute('${v3_bin} ${example} -b c -o ${bin}')
298 assert compile.exit_code == 0, compile.output
299 run := os.execute("printf '2 * (5-1)\\nexit\\n' | ${bin}")
300 assert run.exit_code == 0, run.output
301 assert run.output.contains('8'), run.output
302 generated := os.read_file(bin + '.c') or { panic(err) }
303 assert generated.contains('Parser__expr('), generated
304 assert generated.contains('Parser__term('), generated
305 assert generated.contains('Parser__factor('), generated
306 assert generated.contains('Parser__number('), generated
307}
308