v2 / vlib / v / gen / c / defer.v
90 lines · 82 sloc · 2.62 KB · 80538516b34a0d2a254b56b1d306e6f3af9187c4
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module c
5
6import v.ast
7import v.token
8
9fn (g &Gen) defer_flag_var(stmt &ast.DeferStmt) string {
10 return '${g.last_fn_c_name}_defer_${stmt.idx_in_fn}'
11}
12
13fn (g &Gen) innermost_active_defer_scope(pos token.Pos) &ast.Scope {
14 pos_i := pos.pos
15 mut scope := g.cur_fn.scope
16 for defer_stmt in g.defer_stmts {
17 if defer_stmt.scope == unsafe { nil } {
18 continue
19 }
20 if defer_stmt.scope.start_pos <= pos_i && pos_i <= defer_stmt.scope.end_pos
21 && defer_stmt.scope.start_pos >= scope.start_pos
22 && defer_stmt.scope.end_pos <= scope.end_pos {
23 scope = defer_stmt.scope
24 }
25 }
26 return scope
27}
28
29// this function is called at the end of each block (`for`, `if` branches,
30// `match` branches, etc.)
31fn (mut g Gen) write_defer_stmts(scope &ast.Scope, lookup bool, pos token.Pos) {
32 if scope == unsafe { nil } {
33 // this should never happen
34 g.error('Gen.write_defer_stmts() has received a scope that is nil', pos)
35 }
36
37 prev_inside_defer_generation := g.inside_defer_generation
38 g.inside_defer_generation = true
39 defer {
40 g.inside_defer_generation = prev_inside_defer_generation
41 }
42 g.indent++
43 for i := g.defer_stmts.len - 1; i >= 0; i-- {
44 defer_stmt := g.defer_stmts[i]
45 if defer_stmt.scope == unsafe { nil } {
46 // this should never happen
47 g.error('Gen.write_defer_stmts(): defer_stmt.scope is nil', pos)
48 }
49
50 if defer_stmt.mode == .scoped {
51 if !((lookup && defer_stmt.scope.start_pos < scope.start_pos
52 && defer_stmt.scope.end_pos > scope.end_pos)
53 || defer_stmt.scope == scope) {
54 // generate only `defer`s of the current scope (and previous ones if necessary)
55 continue
56 }
57 g.writeln('{ // defer begin')
58 } else {
59 if scope != g.cur_fn.scope && !lookup {
60 continue
61 }
62 g.writeln('if (${g.defer_flag_var(defer_stmt)}) { // defer begin')
63 }
64
65 if defer_stmt.ifdef.len > 0 {
66 g.writeln(defer_stmt.ifdef)
67 g.stmts(defer_stmt.stmts)
68 g.writeln2('', '#endif')
69 } else {
70 g.stmts(defer_stmt.stmts)
71 }
72 g.writeln('} // defer end')
73 }
74 g.indent--
75}
76
77// this function is called when returning with `return`, or when the end of a function
78// is reached.
79fn (mut g Gen) write_defer_stmts_when_needed(scope &ast.Scope, lookup bool, pos token.Pos) {
80 // unlock all mutexes, in case we are in a lock statement. defers are not
81 // allowed in lock statements.
82 g.unlock_locks()
83 if g.defer_stmts.len > 0 {
84 g.write_defer_stmts(scope, lookup, pos)
85 }
86 if g.defer_profile_code.len > 0 {
87 g.writeln2('', '\t// defer_profile_code')
88 g.writeln2(g.defer_profile_code, '')
89 }
90}
91