v4 / vlib / v3 / gen / c / for.v
219 lines · 212 sloc · 6.75 KB · 351709f1031b64c6175612e9e459d8216eeca7f5
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 if clean_container_type is types.Map {
82 c_key := g.value_c_type(clean_container_type.key_type)
83 c_val := g.value_c_type(clean_container_type.value_type)
84 container_str := g.expr_to_string(g.a.child(&node, 2))
85 iter_var := '__mi_${g.tmp_count}'
86 g.tmp_count++
87 key_var := if has_index { idx_var } else { '__mk_${g.tmp_count}' }
88 val_var_ := if has_index { elem_var } else { var_name }
89 access := if container_type is types.Pointer { '->' } else { '.' }
90 key_values := '(${container_str})${access}key_values'
91 g.writeln('for (int ${iter_var} = 0; ${iter_var} < ${key_values}.len; ${iter_var}++) {')
92 g.indent++
93 g.writeln('if (${key_values}.all_deleted && ${key_values}.all_deleted[${iter_var}]) continue;')
94 g.writeln('${c_key} ${key_var} = *(${c_key}*)(${key_values}.keys + ${iter_var} * ${key_values}.key_bytes);')
95 g.writeln('${c_val} ${val_var_} = *(${c_val}*)(${key_values}.values + ${iter_var} * ${key_values}.value_bytes);')
96 if has_index {
97 g.tc.cur_scope.insert(key_var, clean_container_type.key_type)
98 }
99 g.tc.cur_scope.insert(val_var_, clean_container_type.value_type)
100 } else if container_type is types.Array {
101 c_elem := g.value_c_type(container_type.elem_type)
102 mut container_str := g.expr_to_string(g.a.child(&node, 2))
103 // A call-valued container (e.g. `threads.wait()`, `xs.map(..)`) is not
104 // idempotent and is referenced multiple times below; bind it to a temp so
105 // it runs exactly once.
106 if g.a.nodes[int(g.a.child(&node, 2))].kind == .call {
107 arr_tmp := '__for_arr_${g.tmp_count}'
108 g.tmp_count++
109 g.writeln('Array ${arr_tmp} = ${container_str};')
110 container_str = arr_tmp
111 }
112 g.writeln('for (int ${idx_var} = 0; ${idx_var} < ${container_str}.len; ${idx_var}++) {')
113 g.indent++
114 g.write('${c_elem} ${elem_var} = *(')
115 g.write(c_elem)
116 g.writeln('*)array_get(${container_str}, ${idx_var});')
117 g.tc.cur_scope.insert(elem_var, container_type.elem_type)
118 } else if container_type is types.String {
119 container_str := g.expr_to_string(g.a.child(&node, 2))
120 g.writeln('for (int ${idx_var} = 0; ${idx_var} < ${container_str}.len; ${idx_var}++) {')
121 g.indent++
122 g.writeln('u8 ${elem_var} = ((u8*)${container_str}.str)[${idx_var}];')
123 g.tc.cur_scope.insert(elem_var, types.Type(types.u8_))
124 } else if container_type is types.ArrayFixed {
125 af := container_type
126 c_elem := g.value_c_type(af.elem_type)
127 arr_len := g.fixed_array_len_value(af)
128 g.writeln('for (int ${idx_var} = 0; ${idx_var} < ${arr_len}; ${idx_var}++) {')
129 g.indent++
130 g.write('${c_elem} ${elem_var} = ')
131 g.gen_expr(g.a.child(&node, 2))
132 g.writeln('[${idx_var}];')
133 g.tc.cur_scope.insert(elem_var, af.elem_type)
134 } else {
135 g.writeln('for (int ${idx_var} = 0; ${idx_var} < 0; ${idx_var}++) {')
136 g.indent++
137 g.writeln('int ${elem_var} = 0;')
138 g.tc.cur_scope.insert(elem_var, types.Type(types.int_))
139 }
140 if has_index && container_type !is types.Map {
141 g.tc.cur_scope.insert(idx_var, types.Type(types.int_))
142 }
143 for i in body_start .. node.children_count {
144 g.gen_node(g.a.child(&node, i))
145 }
146 g.indent--
147 g.writeln('}')
148 g.tc.pop_scope()
149 return
150 }
151 } else {
152 g.tc.pop_scope()
153 return
154 }
155 g.indent++
156 for i in body_start .. node.children_count {
157 g.gen_node(g.a.child(&node, i))
158 }
159 g.indent--
160 g.writeln('}')
161 g.tc.pop_scope()
162}
163
164fn (g &FlatGen) c_loop_local_name(name string) string {
165 if name.contains('.') {
166 return c_name(name.all_after_last('.'))
167 }
168 if name.contains('__') {
169 prefix := name.all_before_last('__')
170 suffix := name.all_after_last('__')
171 if suffix == 'index' {
172 return c_name(suffix)
173 }
174 if g.has_import_alias(prefix) {
175 return c_name(suffix)
176 }
177 for _, mod_name in g.modules {
178 short_mod := if mod_name.contains('.') { mod_name.all_after_last('.') } else { mod_name }
179 if prefix == short_mod {
180 return c_name(suffix)
181 }
182 }
183 }
184 return c_name(name)
185}
186
187// gen_node_inline emits node inline output for c.
188fn (mut g FlatGen) gen_node_inline(id flat.NodeId) {
189 node := g.a.nodes[int(id)]
190 match node.kind {
191 .expr_stmt {
192 g.gen_expr(g.a.child(&node, 0))
193 }
194 .decl_assign {
195 lhs_id := g.a.child(&node, 0)
196 rhs_id := g.a.child(&node, 1)
197 lhs := g.a.nodes[int(lhs_id)]
198 v_type := g.tc.resolve_type(rhs_id)
199 typ := g.tc.c_type(v_type)
200 g.write('${typ} ')
201 if lhs.kind == .ident {
202 g.write(g.c_loop_local_name(lhs.value))
203 } else {
204 g.gen_expr(lhs_id)
205 }
206 g.write(' = ')
207 g.gen_expr(rhs_id)
208 if lhs.kind == .ident {
209 g.tc.cur_scope.insert(lhs.value, v_type)
210 }
211 }
212 .assign {
213 g.gen_expr(g.a.child(&node, 0))
214 g.write(' ${g.op_str(node.op)} ')
215 g.gen_expr(g.a.child(&node, 1))
216 }
217 else {}
218 }
219}
220