vxx / vlib / v3 / gen / c / for.v
283 lines · 274 sloc · 8.76 KB · 2b81918e62db9ab38787518603a7f93bee80868c
Raw
1module c
2
3import v3.flat
4import v3.types
5
6// gen_for emits for output for c.
7fn (mut g FlatGen) gen_for(node flat.Node) {
8 g.tc.push_scope()
9 defer_start := g.defers.len
10 init_node := g.a.child_node(&node, 0)
11 cond_id := g.a.child(&node, 1)
12 cond_node := g.a.nodes[int(cond_id)]
13 post_node := g.a.child_node(&node, 2)
14
15 if init_node.kind == .empty && cond_node.kind == .empty && post_node.kind == .empty {
16 g.writeln('for (;;) {')
17 } else if init_node.kind == .empty && post_node.kind == .empty {
18 g.write('while (')
19 g.gen_expr(cond_id)
20 g.writeln(') {')
21 } else {
22 g.write('for (')
23 if init_node.kind != .empty {
24 g.gen_node_inline(g.a.child(&node, 0))
25 }
26 g.write('; ')
27 if cond_node.kind != .empty {
28 g.gen_expr(cond_id)
29 }
30 g.write('; ')
31 if post_node.kind != .empty {
32 g.gen_node_inline(g.a.child(&node, 2))
33 }
34 g.writeln(') {')
35 }
36 g.indent++
37 for i in 3 .. node.children_count {
38 g.gen_node(g.a.child(&node, i))
39 }
40 g.gen_defers_from(defer_start)
41 g.trim_defers(defer_start)
42 g.indent--
43 g.writeln('}')
44 g.tc.pop_scope()
45}
46
47// gen_for_in emits for in output for c.
48fn (mut g FlatGen) gen_for_in(node flat.Node) {
49 g.tc.push_scope()
50 header_count := node.value.int()
51 val_id := g.a.child(&node, 1)
52 var_node := if int(val_id) >= 0 {
53 g.a.child_node(&node, 1)
54 } else {
55 g.a.child_node(&node, 0)
56 }
57 var_name := g.c_loop_local_name(var_node.value)
58 g.tc.cur_scope.insert(var_node.value, types.Type(types.int_))
59 body_start := header_count
60
61 if header_count == 4 {
62 panic('internal error: range for-in reached C backend after transform')
63 } else if header_count == 3 {
64 container := g.a.child_node(&node, 2)
65 if container.kind == .range {
66 panic('internal error: range for-in reached C backend after transform')
67 } else {
68 container_type := g.usable_expr_type(g.a.child(&node, 2))
69 has_index := int(val_id) >= 0
70 idx_var := if has_index {
71 g.c_loop_local_name(g.a.child_node(&node, 0).value)
72 } else {
73 '__iter_${var_name}'
74 }
75 elem_var := if has_index {
76 g.c_loop_local_name(g.a.child_node(&node, 1).value)
77 } else {
78 var_name
79 }
80 clean_container_type := types.unwrap_pointer(container_type)
81 mut map_snapshot_var := ''
82 if clean_container_type is types.Map {
83 c_key := g.value_c_type(clean_container_type.key_type)
84 c_val := g.value_c_type(clean_container_type.value_type)
85 container_str := g.expr_to_string(g.a.child(&node, 2))
86 iter_var := '__mi_${g.tmp_count}'
87 g.tmp_count++
88 key_var := if has_index { idx_var } else { '__mk_${g.tmp_count}' }
89 val_var_ := if has_index { elem_var } else { var_name }
90 use_snapshot := g.for_in_body_contains_delete_call(node, body_start)
91 key_values := if use_snapshot {
92 map_snapshot_var = '__for_map_${g.tmp_count}'
93 g.tmp_count++
94 if container_type is types.Pointer {
95 g.writeln('map ${map_snapshot_var} = map__clone(${container_str});')
96 } else {
97 map_src := '__for_map_src_${g.tmp_count}'
98 g.tmp_count++
99 g.writeln('map ${map_src} = ${container_str};')
100 g.writeln('map ${map_snapshot_var} = map__clone(&${map_src});')
101 }
102 '${map_snapshot_var}.key_values'
103 } else {
104 access := if container_type is types.Pointer { '->' } else { '.' }
105 '(${container_str})${access}key_values'
106 }
107 g.writeln('for (int ${iter_var} = 0; ${iter_var} < ${key_values}.len; ${iter_var}++) {')
108 g.indent++
109 g.writeln('if (${key_values}.all_deleted && ${key_values}.all_deleted[${iter_var}]) continue;')
110 key_slot := '${key_values}.keys + ${iter_var} * ${key_values}.key_bytes'
111 if key_fixed := array_fixed_type(clean_container_type.key_type) {
112 c_elem, dims := g.fixed_array_decl_parts(key_fixed)
113 g.writeln('${c_elem} ${key_var}${dims};')
114 g.writeln('memmove(${key_var}, ${key_slot}, sizeof(${key_var}));')
115 } else {
116 g.writeln('${c_key} ${key_var} = *(${c_key}*)(${key_slot});')
117 }
118 val_slot := '${key_values}.values + ${iter_var} * ${key_values}.value_bytes'
119 if val_fixed := array_fixed_type(clean_container_type.value_type) {
120 c_elem, dims := g.fixed_array_decl_parts(val_fixed)
121 g.writeln('${c_elem} ${val_var_}${dims};')
122 g.writeln('memmove(${val_var_}, ${val_slot}, sizeof(${val_var_}));')
123 } else {
124 g.writeln('${c_val} ${val_var_} = *(${c_val}*)(${val_slot});')
125 }
126 if has_index {
127 g.tc.cur_scope.insert(key_var, clean_container_type.key_type)
128 }
129 g.tc.cur_scope.insert(val_var_, clean_container_type.value_type)
130 } else if container_type is types.Array {
131 c_elem := g.value_c_type(container_type.elem_type)
132 mut container_str := g.expr_to_string(g.a.child(&node, 2))
133 // A call-valued container (e.g. `threads.wait()`, `xs.map(..)`) is not
134 // idempotent and is referenced multiple times below; bind it to a temp so
135 // it runs exactly once.
136 if g.a.nodes[int(g.a.child(&node, 2))].kind == .call {
137 arr_tmp := '__for_arr_${g.tmp_count}'
138 g.tmp_count++
139 g.writeln('Array ${arr_tmp} = ${container_str};')
140 container_str = arr_tmp
141 }
142 g.writeln('for (int ${idx_var} = 0; ${idx_var} < ${container_str}.len; ${idx_var}++) {')
143 g.indent++
144 g.write('${c_elem} ${elem_var} = *(')
145 g.write(c_elem)
146 g.writeln('*)array_get(${container_str}, ${idx_var});')
147 g.tc.cur_scope.insert(elem_var, container_type.elem_type)
148 } else if container_type is types.String {
149 container_str := g.expr_to_string(g.a.child(&node, 2))
150 g.writeln('for (int ${idx_var} = 0; ${idx_var} < ${container_str}.len; ${idx_var}++) {')
151 g.indent++
152 g.writeln('u8 ${elem_var} = ((u8*)${container_str}.str)[${idx_var}];')
153 g.tc.cur_scope.insert(elem_var, types.Type(types.u8_))
154 } else if container_type is types.ArrayFixed {
155 af := container_type
156 c_elem := g.value_c_type(af.elem_type)
157 arr_len := g.fixed_array_len_value(af)
158 g.writeln('for (int ${idx_var} = 0; ${idx_var} < ${arr_len}; ${idx_var}++) {')
159 g.indent++
160 g.write('${c_elem} ${elem_var} = ')
161 g.gen_expr(g.a.child(&node, 2))
162 g.writeln('[${idx_var}];')
163 g.tc.cur_scope.insert(elem_var, af.elem_type)
164 } else {
165 g.writeln('for (int ${idx_var} = 0; ${idx_var} < 0; ${idx_var}++) {')
166 g.indent++
167 g.writeln('int ${elem_var} = 0;')
168 g.tc.cur_scope.insert(elem_var, types.Type(types.int_))
169 }
170 if has_index && container_type !is types.Map {
171 g.tc.cur_scope.insert(idx_var, types.Type(types.int_))
172 }
173 for i in body_start .. node.children_count {
174 g.gen_node(g.a.child(&node, i))
175 }
176 g.indent--
177 g.writeln('}')
178 if map_snapshot_var.len > 0 {
179 g.writeln('map__free(&${map_snapshot_var});')
180 }
181 g.tc.pop_scope()
182 return
183 }
184 } else {
185 g.tc.pop_scope()
186 return
187 }
188 g.indent++
189 for i in body_start .. node.children_count {
190 g.gen_node(g.a.child(&node, i))
191 }
192 g.indent--
193 g.writeln('}')
194 g.tc.pop_scope()
195}
196
197fn (g &FlatGen) for_in_body_contains_delete_call(node flat.Node, body_start int) bool {
198 for i in body_start .. node.children_count {
199 if g.node_contains_delete_call(g.a.child(&node, i)) {
200 return true
201 }
202 }
203 return false
204}
205
206fn (g &FlatGen) node_contains_delete_call(id flat.NodeId) bool {
207 if int(id) < 0 || int(id) >= g.a.nodes.len {
208 return false
209 }
210 node := g.a.nodes[int(id)]
211 if node.kind == .call && node.children_count > 0 {
212 fn_node := g.a.child_node(&node, 0)
213 if fn_node.kind == .selector && fn_node.value == 'delete' {
214 return true
215 }
216 if fn_node.kind == .ident && fn_node.value in ['map.delete', 'map__delete'] {
217 return true
218 }
219 }
220 for i in 0 .. node.children_count {
221 if g.node_contains_delete_call(g.a.child(&node, i)) {
222 return true
223 }
224 }
225 return false
226}
227
228fn (g &FlatGen) c_loop_local_name(name string) string {
229 if name.contains('.') {
230 return c_name(name.all_after_last('.'))
231 }
232 if name.contains('__') {
233 prefix := name.all_before_last('__')
234 suffix := name.all_after_last('__')
235 if suffix == 'index' {
236 return c_name(suffix)
237 }
238 if g.has_import_alias(prefix) {
239 return c_name(suffix)
240 }
241 for _, mod_name in g.modules {
242 short_mod := if mod_name.contains('.') { mod_name.all_after_last('.') } else { mod_name }
243 if prefix == short_mod {
244 return c_name(suffix)
245 }
246 }
247 }
248 return c_name(name)
249}
250
251// gen_node_inline emits node inline output for c.
252fn (mut g FlatGen) gen_node_inline(id flat.NodeId) {
253 node := g.a.nodes[int(id)]
254 match node.kind {
255 .expr_stmt {
256 g.gen_expr(g.a.child(&node, 0))
257 }
258 .decl_assign {
259 lhs_id := g.a.child(&node, 0)
260 rhs_id := g.a.child(&node, 1)
261 lhs := g.a.nodes[int(lhs_id)]
262 v_type := g.tc.resolve_type(rhs_id)
263 typ := g.tc.c_type(v_type)
264 g.write('${typ} ')
265 if lhs.kind == .ident {
266 g.write(g.c_loop_local_name(lhs.value))
267 } else {
268 g.gen_expr(lhs_id)
269 }
270 g.write(' = ')
271 g.gen_expr(rhs_id)
272 if lhs.kind == .ident {
273 g.tc.cur_scope.insert(lhs.value, v_type)
274 }
275 }
276 .assign {
277 g.gen_expr(g.a.child(&node, 0))
278 g.write(' ${g.op_str(node.op)} ')
279 g.gen_expr(g.a.child(&node, 1))
280 }
281 else {}
282 }
283}
284