vxx2 / vlib / v3 / tests / c_global_static_codegen_test.v
254 lines · 229 sloc · 7.08 KB · 288feee4702b35beadb4037d02b96b5c8674156b
Raw
1import os
2import v3.flat
3import v3.gen.c as cgen
4import v3.markused
5import v3.parser
6import v3.pref
7import v3.transform
8import v3.types
9
10// gen_c_for_source emits c for source output for v3 tests.
11fn gen_c_for_source(name string, source string) string {
12 src := os.join_path(os.temp_dir(), 'v3_${name}.v')
13 os.write_file(src, source) or { panic(err) }
14 prefs := pref.new_preferences()
15 mut p := parser.Parser.new(prefs)
16 mut a := p.parse_file(src)
17 mut tc := types.TypeChecker.new(a)
18 tc.collect(a)
19 tc.diagnose_unknown_calls = true
20 tc.diagnostic_files[src] = true
21 tc.check_semantics()
22 assert tc.errors.len == 0, tc.errors.str()
23 transform.transform(mut a, &tc)
24 tc.annotate_types()
25 used_fns := markused.mark_used(a, tc)
26 mut g := cgen.FlatGen.new()
27 return g.gen_with_used_options(a, used_fns, &tc, true)
28}
29
30// gen_c_for_sources emits c for sources output for v3 tests.
31fn gen_c_for_sources(name string, files map[string]string) string {
32 root := os.join_path(os.temp_dir(), 'v3_${name}')
33 if os.exists(root) {
34 os.rmdir_all(root) or { panic(err) }
35 }
36 os.mkdir_all(root) or { panic(err) }
37 mut paths := []string{}
38 mut rels := files.keys()
39 rels.sort()
40 for rel in rels {
41 path := os.join_path(root, rel)
42 os.mkdir_all(os.dir(path)) or { panic(err) }
43 os.write_file(path, files[rel]) or { panic(err) }
44 paths << path
45 }
46 prefs := pref.new_preferences()
47 mut p := parser.Parser.new(prefs)
48 mut a := p.parse_files(paths)
49 mut tc := types.TypeChecker.new(a)
50 tc.collect(a)
51 tc.diagnose_unknown_calls = true
52 for path in paths {
53 tc.diagnostic_files[path] = true
54 }
55 tc.check_semantics()
56 assert tc.errors.len == 0, tc.errors.str()
57 transform.transform(mut a, &tc)
58 tc.annotate_types()
59 used_fns := markused.mark_used(a, tc)
60 mut g := cgen.FlatGen.new()
61 return g.gen_with_used_options(a, used_fns, &tc, true)
62}
63
64// gen_c_for_source_with_scalar_zero_decl supports gen_c_for_source_with_scalar_zero_decl handling.
65fn gen_c_for_source_with_scalar_zero_decl(name string, source string, decl_name string, decl_type string) string {
66 src := os.join_path(os.temp_dir(), 'v3_${name}.v')
67 os.write_file(src, source) or { panic(err) }
68 prefs := pref.new_preferences()
69 mut p := parser.Parser.new(prefs)
70 mut a := p.parse_file(src)
71 mut tc := types.TypeChecker.new(a)
72 tc.collect(a)
73 tc.diagnose_unknown_calls = true
74 tc.diagnostic_files[src] = true
75 tc.check_semantics()
76 assert tc.errors.len == 0, tc.errors.str()
77 transform.transform(mut a, &tc)
78 tc.annotate_types()
79 zero_id := a.add_node(flat.Node{
80 kind: .int_literal
81 value: '0'
82 })
83 mut patched := false
84 for i, node in a.nodes {
85 if node.kind != .decl_assign || node.children_count != 2 {
86 continue
87 }
88 lhs_id := a.child(&node, 0)
89 lhs := a.nodes[int(lhs_id)]
90 if lhs.kind == .ident && lhs.value == decl_name {
91 a.nodes[i].typ = decl_type
92 a.children[int(node.children_start) + 1] = zero_id
93 patched = true
94 }
95 }
96 assert patched
97 used_fns := markused.mark_used(a, tc)
98 mut g := cgen.FlatGen.new()
99 return g.gen_with_used_options(a, used_fns, &tc, true)
100}
101
102// test_c_global_pointer_arg_is_not_addressed_again validates this v3 regression case.
103fn test_c_global_pointer_arg_is_not_addressed_again() {
104 c_code := gen_c_for_source('c_global_stdout_arg', '__global C.stdout &C.FILE
105
106fn set_stream_unbuffered(stream &C.FILE) {}
107
108fn main() {
109 set_stream_unbuffered(C.stdout)
110}
111')
112 assert c_code.contains('set_stream_unbuffered(stdout);')
113 assert !c_code.contains('set_stream_unbuffered(&stdout);')
114}
115
116// test_mut_static_local_decl_codegen validates this v3 regression case.
117fn test_mut_static_local_decl_codegen() {
118 c_code := gen_c_for_source('static_local_decl', 'fn next_value() int {
119 mut static x := 0
120 x++
121 return x
122}
123
124fn main() {
125 _ := next_value()
126}
127')
128 assert c_code.contains('static int x = 0;')
129}
130
131// test_aggregate_globals_are_brace_zero_initialized validates this v3 regression case.
132fn test_aggregate_globals_are_brace_zero_initialized() {
133 c_code := gen_c_for_source('aggregate_global_zero_init', 'const zero_len = 1 - 1
134
135struct Box {
136 value int
137}
138
139struct ZeroLeading {
140 z [0]int
141 value int
142}
143
144struct NestedZeroLeading {
145 zero ZeroLeading
146 value int
147}
148
149struct ZeroLeadingConst {
150 z [zero_len]int
151 value int
152}
153
154__global (
155 names []string
156 lookup map[string]int
157 box Box
158 empty [0]int
159 slots [2]int
160 zero ZeroLeading
161 nested NestedZeroLeading
162 zero_slots [2]ZeroLeading
163 const_empty [zero_len]int
164 const_zero ZeroLeadingConst
165 const_zero_slots [2]ZeroLeadingConst
166)
167
168fn main() {}
169')
170 assert c_code.contains('Array names = {0};')
171 assert c_code.contains('map lookup = {0};')
172 assert c_code.contains('Box box = {0};')
173 assert c_code.contains('int empty[0];')
174 assert c_code.contains('int slots[2] = {0};')
175 assert c_code.contains('\nZeroLeading zero;\n')
176 assert c_code.contains('\nNestedZeroLeading nested;\n')
177 assert c_code.contains('\nZeroLeading zero_slots[2];\n')
178 assert c_code.contains('\nint const_empty[0];\n')
179 assert c_code.contains('\nZeroLeadingConst const_zero;\n')
180 assert c_code.contains('\nZeroLeadingConst const_zero_slots[2];\n')
181 assert !c_code.contains('Array names = 0;')
182 assert !c_code.contains('map lookup = 0;')
183 assert !c_code.contains('Box box = 0;')
184 assert !c_code.contains('int empty[0] = {0};')
185 assert !c_code.contains('ZeroLeading zero = {0};')
186 assert !c_code.contains('NestedZeroLeading nested = {0};')
187 assert !c_code.contains('ZeroLeading zero_slots[2] = {0};')
188 assert !c_code.contains('\nint const_empty[0] = {0};\n')
189 assert !c_code.contains('ZeroLeadingConst const_zero = {0};')
190 assert !c_code.contains('ZeroLeadingConst const_zero_slots[2] = {0};')
191}
192
193// test_imported_zero_length_leading_field_global_uses_decl_only validates this v3 regression case.
194fn test_imported_zero_length_leading_field_global_uses_decl_only() {
195 c_code := gen_c_for_sources('imported_zero_leading_global', {
196 'main.v': 'module main
197
198import moda
199
200__global imported moda.ImportedZero
201__global imported_slots [2]moda.ImportedZero
202
203fn main() {}
204'
205 'moda/moda.v': 'module moda
206
207const zero_len = 1 - 1
208
209pub struct ImportedZero {
210 z [zero_len]int
211 value int
212}
213'
214 })
215 assert c_code.contains('\nmoda__ImportedZero imported;\n')
216 assert c_code.contains('\nmoda__ImportedZero imported_slots[2];\n')
217 assert !c_code.contains('moda__ImportedZero imported = {0};')
218 assert !c_code.contains('moda__ImportedZero imported_slots[2] = {0};')
219}
220
221// test_aggregate_decl_with_scalar_zero_uses_brace_initializer validates this v3 regression case.
222fn test_aggregate_decl_with_scalar_zero_uses_brace_initializer() {
223 c_code := gen_c_for_source_with_scalar_zero_decl('aggregate_decl_scalar_zero', 'struct Box {
224 value int
225}
226
227fn main() {
228 box := Box{}
229 _ = box.value
230}
231',
232 'box', 'Box')
233 assert c_code.contains('Box box = {0};'), c_code
234 assert !c_code.contains('Box box = 0;')
235}
236
237// test_defer_capture_aggregate_decl_with_scalar_zero_uses_compound_literal
238// validates this v3 regression case.
239fn test_defer_capture_aggregate_decl_with_scalar_zero_uses_compound_literal() {
240 c_code := gen_c_for_source_with_scalar_zero_decl('defer_capture_aggregate_decl_scalar_zero', 'struct Box {
241 value int
242}
243
244fn main() {
245 box := Box{}
246 defer(fn) {
247 _ = box.value
248 }
249}
250',
251 'box', 'Box')
252 assert c_code.contains('box = (Box){0};'), c_code
253 assert !c_code.contains('box = {0};')
254}
255