v4 / vlib / v3 / gen / c / if.v
557 lines · 540 sloc · 15.01 KB · 351709f1031b64c6175612e9e459d8216eeca7f5
Raw
1module c
2
3import v3.flat
4import v3.types
5
6struct MultiReturnTailParts {
7 prefix_count int
8 values []flat.NodeId
9}
10
11// gen_if emits if output for c.
12fn (mut g FlatGen) gen_if(node flat.Node) {
13 // Iterate the `else if` chain rather than recursing through gen_if/gen_if_else for
14 // each link. A lowered match can produce hundreds of chained `if_expr` nodes (one
15 // per arm); recursing once per arm overflows the stack on big matches. The emitted
16 // C is identical — only the generation is flattened into a loop.
17 mut cur := node
18 for {
19 if cur.children_count < 2 {
20 return
21 }
22 cond_id := g.a.child(&cur, 0)
23 if !g.valid_node_id(cond_id) {
24 return
25 }
26 cond := g.a.nodes[int(cond_id)]
27 if cond.kind == .decl_assign {
28 g.gen_if_guard(cur, cond)
29 return
30 }
31 if cond.kind != .empty {
32 g.write('if (')
33 g.gen_expr(cond_id)
34 g.writeln(') {')
35 } else {
36 g.writeln('{')
37 }
38 g.tc.push_scope()
39 defer_start := g.defers.len
40 g.indent++
41 if cond.kind == .is_expr {
42 g.smartcast_is_expr(&cond)
43 }
44 then_id := g.a.child(&cur, 1)
45 if g.valid_node_id(then_id) {
46 then_block := g.a.nodes[int(then_id)]
47 for i in 0 .. then_block.children_count {
48 child_id := g.a.child(&then_block, i)
49 if g.valid_node_id(child_id) {
50 g.gen_node(child_id)
51 }
52 }
53 }
54 g.gen_defers_from(defer_start)
55 g.trim_defers(defer_start)
56 g.indent--
57 g.tc.pop_scope()
58 // else handling — continue the loop for a plain `else if`, recurse only for the
59 // rare guard-else (`else if x := ...`).
60 if cur.children_count <= 2 {
61 g.writeln('}')
62 return
63 }
64 else_id := g.a.child(&cur, 2)
65 if !g.valid_node_id(else_id) {
66 g.writeln('}')
67 return
68 }
69 else_node := g.a.nodes[int(else_id)]
70 if else_node.kind == .if_expr {
71 else_cond_id := g.a.child(&else_node, 0)
72 else_cond_is_guard := if g.valid_node_id(else_cond_id) {
73 g.a.nodes[int(else_cond_id)].kind == .decl_assign
74 } else {
75 false
76 }
77 if else_cond_is_guard {
78 g.writeln('} else {')
79 g.tc.push_scope()
80 g.indent++
81 g.gen_if(else_node)
82 g.indent--
83 g.tc.pop_scope()
84 g.writeln('}')
85 return
86 }
87 g.write('} else ')
88 cur = else_node
89 continue
90 } else if else_node.kind == .block {
91 g.writeln('} else {')
92 g.tc.push_scope()
93 else_defer_start := g.defers.len
94 g.indent++
95 for i in 0 .. else_node.children_count {
96 child_id := g.a.child(&else_node, i)
97 if g.valid_node_id(child_id) {
98 g.gen_node(child_id)
99 }
100 }
101 g.gen_defers_from(else_defer_start)
102 g.trim_defers(else_defer_start)
103 g.indent--
104 g.tc.pop_scope()
105 g.writeln('}')
106 return
107 } else {
108 g.writeln('}')
109 return
110 }
111 }
112}
113
114// smartcast_is_expr supports smartcast is expr handling for FlatGen.
115fn (mut g FlatGen) smartcast_is_expr(cond &flat.Node) {
116 expr_id := g.a.child(cond, 0)
117 expr_node := g.a.nodes[int(expr_id)]
118 if expr_node.kind == .ident {
119 sum_type := g.tc.resolve_type(expr_id)
120 clean_sum0 := types.unwrap_pointer(sum_type)
121 mut clean_sum := clean_sum0
122 if clean_sum0 is types.Alias {
123 clean_sum = clean_sum0.base_type
124 }
125 if clean_sum is types.SumType {
126 variant_name := g.resolve_variant(clean_sum.name, cond.value)
127 variant_type := g.tc.parse_type(variant_name)
128 if variant_type is types.Void {
129 return
130 }
131 variant_ct := g.tc.c_type(variant_type)
132 field_name := g.sum_field_name(variant_name)
133 is_ptr_variant := g.variant_references_sum(variant_name, clean_sum.name)
134 var_name := c_name(expr_node.value)
135 tmp := g.tmp_name()
136 if is_ptr_variant {
137 g.writeln('${variant_ct} ${tmp} = *${var_name}.${field_name};')
138 } else {
139 g.writeln('${variant_ct} ${tmp} = ${var_name}.${field_name};')
140 }
141 g.writeln('${variant_ct} ${var_name} = ${tmp};')
142 g.tc.cur_scope.insert(expr_node.value, variant_type)
143 }
144 }
145}
146
147// expr_key supports expr key handling for FlatGen.
148fn (g &FlatGen) expr_key(id flat.NodeId) string {
149 node := g.a.nodes[int(id)]
150 if node.kind == .ident {
151 return node.value
152 }
153 if node.kind == .selector && node.children_count > 0 {
154 base_key := g.expr_key(g.a.child(&node, 0))
155 if base_key.len > 0 {
156 return '${base_key}.${node.value}'
157 }
158 }
159 return ''
160}
161
162// gen_if_guard emits if guard output for c.
163fn (mut g FlatGen) gen_if_guard(node flat.Node, cond flat.Node) {
164 if cond.children_count < 2 {
165 return
166 }
167 lhs_id := g.a.child(&cond, 0)
168 rhs_id := g.a.child(&cond, 1)
169 if !g.valid_node_id(lhs_id) || !g.valid_node_id(rhs_id) {
170 return
171 }
172 lhs := g.a.nodes[int(lhs_id)]
173 rhs := g.a.nodes[int(rhs_id)]
174 var_name := c_name(lhs.value)
175 tmp := g.tmp_name()
176 defer_start := g.defers.len
177 if rhs.kind == .index {
178 base_id := g.a.child(rhs, 0)
179 base_type := g.tc.resolve_type(base_id)
180 if base_type is types.Map {
181 c_val_type := g.tc.c_type(base_type.value_type)
182 c_key_type := g.tc.c_type(base_type.key_type)
183 g.write('void* ${tmp} = map__get_check(&')
184 g.gen_expr(base_id)
185 g.write(', &(${c_key_type}[]){')
186 g.gen_expr(g.a.child(rhs, 1))
187 g.writeln('});')
188 g.writeln('if (${tmp} != NULL) {')
189 g.tc.push_scope()
190 g.indent++
191 g.writeln('${c_val_type} ${var_name} = *(${c_val_type}*)${tmp};')
192 g.tc.cur_scope.insert(lhs.value, base_type.value_type)
193 } else {
194 rhs_type := g.tc.resolve_type(rhs_id)
195 opt_ct := g.optional_type_name(rhs_type)
196 val_ct, val_type := g.optional_value_ct(rhs_type)
197 g.write('${opt_ct} ${tmp} = ')
198 g.gen_expr(rhs_id)
199 g.writeln(';')
200 g.writeln('if (${tmp}.ok) {')
201 g.tc.push_scope()
202 g.indent++
203 g.writeln('${val_ct} ${var_name} = ${tmp}.value;')
204 g.tc.cur_scope.insert(lhs.value, val_type)
205 }
206 } else {
207 rhs_type := g.tc.resolve_type(rhs_id)
208 opt_ct := g.optional_type_name(rhs_type)
209 val_ct, val_type := g.optional_value_ct(rhs_type)
210 g.write('${opt_ct} ${tmp} = ')
211 g.gen_expr(rhs_id)
212 g.writeln(';')
213 g.writeln('if (${tmp}.ok) {')
214 g.tc.push_scope()
215 g.indent++
216 g.writeln('${val_ct} ${var_name} = ${tmp}.value;')
217 g.tc.cur_scope.insert(lhs.value, val_type)
218 }
219 then_id := g.a.child(&node, 1)
220 if g.valid_node_id(then_id) {
221 then_block := g.a.nodes[int(then_id)]
222 for i in 0 .. then_block.children_count {
223 child_id := g.a.child(&then_block, i)
224 if g.valid_node_id(child_id) {
225 g.gen_node(child_id)
226 }
227 }
228 }
229 g.gen_defers_from(defer_start)
230 g.trim_defers(defer_start)
231 g.indent--
232 g.tc.pop_scope()
233 g.gen_if_else(node)
234}
235
236// gen_if_else emits if else output for c.
237fn (mut g FlatGen) gen_if_else(node flat.Node) {
238 if node.children_count > 2 {
239 else_id := g.a.child(&node, 2)
240 if !g.valid_node_id(else_id) {
241 g.writeln('}')
242 return
243 }
244 else_node := g.a.nodes[int(else_id)]
245 if else_node.kind == .if_expr {
246 else_cond_id := g.a.child(&else_node, 0)
247 else_cond_is_guard := if g.valid_node_id(else_cond_id) {
248 g.a.nodes[int(else_cond_id)].kind == .decl_assign
249 } else {
250 false
251 }
252 if else_cond_is_guard {
253 g.writeln('} else {')
254 g.tc.push_scope()
255 g.indent++
256 g.gen_if(else_node)
257 g.indent--
258 g.tc.pop_scope()
259 g.writeln('}')
260 } else {
261 g.write('} else ')
262 g.gen_if(else_node)
263 }
264 } else if else_node.kind == .block {
265 g.writeln('} else {')
266 g.tc.push_scope()
267 defer_start := g.defers.len
268 g.indent++
269 for i in 0 .. else_node.children_count {
270 child_id := g.a.child(&else_node, i)
271 if g.valid_node_id(child_id) {
272 g.gen_node(child_id)
273 }
274 }
275 g.gen_defers_from(defer_start)
276 g.trim_defers(defer_start)
277 g.indent--
278 g.tc.pop_scope()
279 g.writeln('}')
280 } else {
281 g.writeln('}')
282 }
283 } else {
284 g.writeln('}')
285 }
286}
287
288// gen_if_expr emits if expr output for c.
289fn (mut g FlatGen) gen_if_expr(node flat.Node) {
290 then_block := g.a.child_node(&node, 1)
291 mut needs_stmt_expr := then_block.children_count > 1
292 if !needs_stmt_expr && node.children_count > 2 {
293 else_node := g.a.child_node(&node, 2)
294 if else_node.kind == .block && else_node.children_count > 1 {
295 needs_stmt_expr = true
296 } else if else_node.kind == .if_expr {
297 needs_stmt_expr = true
298 }
299 }
300 if needs_stmt_expr {
301 g.gen_if_expr_stmt(node)
302 return
303 }
304 g.write('(')
305 g.gen_expr(g.a.child(&node, 0))
306 g.write(' ? ')
307 if then_block.children_count > 0 {
308 last := g.a.child_node(then_block, then_block.children_count - 1)
309 if last.kind == .expr_stmt {
310 g.gen_expr(g.a.child(last, 0))
311 } else {
312 g.gen_expr(g.a.child(then_block, then_block.children_count - 1))
313 }
314 }
315 g.write(' : ')
316 if node.children_count > 2 {
317 else_node := g.a.child_node(&node, 2)
318 if else_node.kind == .if_expr {
319 g.gen_if_expr(*else_node)
320 } else if else_node.kind == .block {
321 if else_node.children_count > 0 {
322 last := g.a.child_node(else_node, else_node.children_count - 1)
323 if last.kind == .expr_stmt {
324 g.gen_expr(g.a.child(last, 0))
325 } else {
326 g.gen_expr(g.a.child(else_node, else_node.children_count - 1))
327 }
328 } else {
329 g.write('0')
330 }
331 }
332 } else {
333 g.write('0')
334 }
335 g.write(')')
336}
337
338// gen_if_expr_block emits if expr block output for c.
339fn (mut g FlatGen) gen_if_expr_block(block &flat.Node, ret_type types.Type) {
340 if ret_type is types.MultiReturn {
341 if g.gen_if_expr_multi_return_block(block, ret_type) {
342 return
343 }
344 }
345 for i in 0 .. block.children_count {
346 child_id := g.a.child(block, i)
347 child := g.a.nodes[int(child_id)]
348 if i == block.children_count - 1 {
349 if child.kind == .expr_stmt {
350 g.write('_ifexpr = ')
351 g.gen_expr(g.a.child(child, 0))
352 g.writeln(';')
353 } else if child.kind == .if_expr {
354 g.write('_ifexpr = ')
355 g.gen_if_expr(child)
356 g.writeln(';')
357 } else if g.is_expr_kind(child.kind) {
358 g.write('_ifexpr = ')
359 g.gen_expr(child_id)
360 g.writeln(';')
361 } else {
362 g.gen_node(child_id)
363 }
364 } else {
365 g.gen_node(child_id)
366 }
367 }
368}
369
370fn (g &FlatGen) multi_return_tail_parts(block &flat.Node, count int) ?MultiReturnTailParts {
371 if block.kind != .block || count <= 0 || block.children_count == 0 {
372 return none
373 }
374 last_id := g.a.child(block, block.children_count - 1)
375 last := g.a.nodes[int(last_id)]
376 if last.kind == .block {
377 if nested := g.multi_return_tail_parts(&last, count) {
378 if nested.prefix_count == 0 {
379 return MultiReturnTailParts{
380 prefix_count: int(block.children_count) - 1
381 values: nested.values.clone()
382 }
383 }
384 }
385 }
386 mut values := []flat.NodeId{}
387 for i := int(block.children_count) - 1; i >= 0; i-- {
388 child_id := g.a.child(block, i)
389 child := g.a.nodes[int(child_id)]
390 if child.kind != .expr_stmt || child.children_count != 1 {
391 break
392 }
393 values.prepend(g.a.child(&child, 0))
394 if values.len == count {
395 return MultiReturnTailParts{
396 prefix_count: i
397 values: values.clone()
398 }
399 }
400 }
401 return none
402}
403
404fn (mut g FlatGen) gen_if_expr_multi_return_block(block &flat.Node, ret_type types.MultiReturn) bool {
405 parts := g.multi_return_tail_parts(block, ret_type.types.len) or { return false }
406 for i in 0 .. parts.prefix_count {
407 g.gen_node(g.a.child(block, i))
408 }
409 g.write('_ifexpr = (${g.tc.c_type(types.Type(ret_type))}){')
410 for i, value_id in parts.values {
411 if i > 0 {
412 g.write(', ')
413 }
414 g.write('.arg${i} = ')
415 g.gen_expr(value_id)
416 }
417 g.writeln('};')
418 return true
419}
420
421// is_expr_kind reports whether is expr kind applies in c.
422fn (g &FlatGen) is_expr_kind(kind flat.NodeKind) bool {
423 return match kind {
424 .int_literal, .float_literal, .bool_literal, .char_literal, .string_literal,
425 .string_interp, .ident, .infix, .prefix, .postfix, .paren, .call, .selector, .index,
426 .if_expr, .struct_init, .field_init, .array_literal, .array_init, .map_init, .fn_literal,
427 .or_expr, .cast_expr, .as_expr, .enum_val, .assoc, .range, .nil_literal, .none_expr,
428 .spawn_expr, .lock_expr, .lambda_expr, .sizeof_expr, .typeof_expr, .dump_expr,
429 .offsetof_expr, .is_expr, .in_expr {
430 true
431 }
432 else {
433 false
434 }
435 }
436}
437
438// seed_scope_from_decl converts seed scope from decl data for c.
439fn (mut g FlatGen) seed_scope_from_decl(node flat.Node) {
440 if node.kind != .decl_assign || node.children_count < 2 {
441 return
442 }
443 lhs := g.a.child_node(&node, 0)
444 if lhs.kind != .ident || lhs.value.len == 0 {
445 return
446 }
447 rhs_id := g.a.child(&node, 1)
448 g.tc.cur_scope.insert(lhs.value, g.tc.resolve_type(rhs_id))
449}
450
451// if_expr_block_tail_type supports if expr block tail type handling for FlatGen.
452fn (mut g FlatGen) if_expr_block_tail_type(block &flat.Node) types.Type {
453 if block.children_count == 0 {
454 return types.Type(types.void_)
455 }
456 g.tc.push_scope()
457 for i in 0 .. block.children_count - 1 {
458 g.seed_scope_from_decl(*g.a.child_node(block, i))
459 }
460 last := g.a.child_node(block, block.children_count - 1)
461 ret := if last.kind == .expr_stmt {
462 g.tc.resolve_type(g.a.child(last, 0))
463 } else {
464 g.tc.resolve_type(g.a.child(block, block.children_count - 1))
465 }
466 g.tc.pop_scope()
467 return ret
468}
469
470// if_expr_type supports if expr type handling for FlatGen.
471fn (mut g FlatGen) if_expr_type(node &flat.Node) types.Type {
472 if node.children_count < 2 {
473 return types.Type(types.void_)
474 }
475 then_block := g.a.child_node(node, 1)
476 mut ret_type := g.if_expr_block_tail_type(then_block)
477 if ret_type is types.Primitive && node.children_count > 2 {
478 else_node := g.a.child_node(node, 2)
479 if else_node.kind == .block && else_node.children_count > 0 {
480 et := g.if_expr_block_tail_type(else_node)
481 if et !is types.Primitive {
482 ret_type = et
483 }
484 } else if else_node.kind == .if_expr && else_node.children_count > 2 {
485 inner_else := g.a.child_node(else_node, 2)
486 if inner_else.kind == .block && inner_else.children_count > 0 {
487 et := g.if_expr_block_tail_type(inner_else)
488 if et !is types.Primitive {
489 ret_type = et
490 }
491 }
492 }
493 }
494 return ret_type
495}
496
497// gen_if_expr_stmt emits if expr stmt output for c.
498fn (mut g FlatGen) gen_if_expr_stmt(node flat.Node) {
499 ret_type := if g.expected_expr_type !is types.Void {
500 g.expected_expr_type
501 } else if node.typ.len > 0 {
502 g.tc.parse_type(node.typ)
503 } else {
504 g.if_expr_type(&node)
505 }
506 then_block := g.a.child_node(&node, 1)
507 ct := g.tc.c_type(ret_type)
508 g.writeln('({${ct} _ifexpr;')
509 g.write('if (')
510 g.gen_expr(g.a.child(&node, 0))
511 g.writeln(') {')
512 g.gen_if_expr_block(then_block, ret_type)
513 g.write('} else ')
514 if node.children_count > 2 {
515 else_node := g.a.child_node(&node, 2)
516 if else_node.kind == .if_expr {
517 g.gen_if_expr_else_if(*else_node, ret_type)
518 } else if else_node.kind == .block {
519 g.writeln('{')
520 g.gen_if_expr_block(else_node, ret_type)
521 g.writeln('}')
522 }
523 } else {
524 g.writeln('{ _ifexpr = (${ct}){0}; }')
525 }
526 g.write('_ifexpr;})')
527}
528
529// gen_if_expr_else_if emits if expr else if output for c. The `else if` chain is
530// iterated rather than recursed: a lowered match-expression can chain hundreds of
531// `if_expr` nodes (one per arm), and recursing once per arm — each frame copying a
532// `flat.Node` and a `Type` by value — overflows the stack. The emitted C is identical.
533fn (mut g FlatGen) gen_if_expr_else_if(node flat.Node, ret_type types.Type) {
534 mut cur := node
535 for {
536 then_block := g.a.child_node(&cur, 1)
537 g.write('if (')
538 g.gen_expr(g.a.child(&cur, 0))
539 g.writeln(') {')
540 g.gen_if_expr_block(then_block, ret_type)
541 g.write('} else ')
542 if cur.children_count > 2 {
543 else_node := g.a.child_node(&cur, 2)
544 if else_node.kind == .if_expr {
545 cur = *else_node
546 continue
547 } else if else_node.kind == .block {
548 g.writeln('{')
549 g.gen_if_expr_block(else_node, ret_type)
550 g.writeln('}')
551 }
552 return
553 }
554 g.writeln('{ _ifexpr = (typeof(_ifexpr)){0}; }')
555 return
556 }
557}
558