| 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. |
| 4 | module c |
| 5 | |
| 6 | import v.util |
| 7 | |
| 8 | const trace_gen_wanted_value = $d('trace_gen_wanted_value', '') |
| 9 | |
| 10 | @[if trace_gen_wanted ?] |
| 11 | fn (mut g Gen) trace_gen_wanted_context(last_character_len int, s string) { |
| 12 | last_n := g.out.last_n(last_character_len) |
| 13 | eprintln('> trace_gen_wanted, last characters:\n${last_n}\n') |
| 14 | eprintln("> trace_gen_wanted, found wanted cgen string `${trace_gen_wanted_value}` in generated string: \"${s}\"") |
| 15 | print_backtrace() |
| 16 | } |
| 17 | |
| 18 | @[if trace_gen_wanted ?] |
| 19 | fn (mut g Gen) trace_gen_wanted(s string) { |
| 20 | if s.contains(trace_gen_wanted_value) { |
| 21 | g.trace_gen_wanted_context(256, s) |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | @[if trace_gen_wanted ?] |
| 26 | fn (mut g Gen) trace_gen_wanted2(s1 string, s2 string) { |
| 27 | if s1.contains(trace_gen_wanted_value) || s2.contains(trace_gen_wanted_value) { |
| 28 | g.trace_gen_wanted_context(256, s1 + s2) |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | @[if trace_gen ?] |
| 33 | fn (mut g Gen) trace_gen(reason string, s string) { |
| 34 | if g.file == unsafe { nil } { |
| 35 | eprintln('gen file: <nil> | last_fn_c_name: ${g.last_fn_c_name:-45} | ${reason}: ${s}') |
| 36 | } else { |
| 37 | eprintln('gen file: ${g.file.path:-30} | last_fn_c_name: ${g.last_fn_c_name:-45} | ${reason}: ${s}') |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | @[expand_simple_interpolation] |
| 42 | fn (mut g Gen) write(s string) { |
| 43 | g.trace_gen_wanted(s) |
| 44 | g.trace_gen('write', s) |
| 45 | if g.indent > 0 && g.empty_line { |
| 46 | g.out.write_string(util.tabs(g.indent)) |
| 47 | } |
| 48 | g.out.write_string(s) |
| 49 | g.empty_line = false |
| 50 | } |
| 51 | |
| 52 | fn (mut g Gen) write2(s1 string, s2 string) { |
| 53 | g.trace_gen_wanted2(s1, s2) |
| 54 | g.trace_gen('write2 s1', s1) |
| 55 | if g.indent > 0 && g.empty_line { |
| 56 | g.out.write_string(util.tabs(g.indent)) |
| 57 | } |
| 58 | g.out.write_string(s1) |
| 59 | g.empty_line = false |
| 60 | |
| 61 | g.trace_gen('write2 s2', s2) |
| 62 | if g.indent > 0 && g.empty_line { |
| 63 | g.out.write_string(util.tabs(g.indent)) |
| 64 | } |
| 65 | g.out.write_string(s2) |
| 66 | g.empty_line = false |
| 67 | } |
| 68 | |
| 69 | fn (mut g Gen) write_decimal(x i64) { |
| 70 | g.trace_gen('write_decimal', x.str()) |
| 71 | if g.indent > 0 && g.empty_line { |
| 72 | g.out.write_string(util.tabs(g.indent)) |
| 73 | } |
| 74 | g.out.write_decimal(x) |
| 75 | g.empty_line = false |
| 76 | } |
| 77 | |
| 78 | fn (mut g Gen) writeln(s string) { |
| 79 | g.trace_gen_wanted(s) |
| 80 | g.trace_gen('writeln', s) |
| 81 | if g.indent > 0 && g.empty_line { |
| 82 | g.out.write_string(util.tabs(g.indent)) |
| 83 | // g.out_parallel[g.out_idx].write_string(util.tabs(g.indent)) |
| 84 | } |
| 85 | // println('w len=${g.out_parallel.len}') |
| 86 | g.out.writeln(s) |
| 87 | // g.out_parallel[g.out_idx].writeln(s) |
| 88 | g.empty_line = true |
| 89 | // g.line_nr++ |
| 90 | } |
| 91 | |
| 92 | fn (mut g Gen) writeln2(s1 string, s2 string) { |
| 93 | g.trace_gen_wanted2(s1, s2) |
| 94 | g.trace_gen('writeln2 s1', s1) |
| 95 | // expansion for s1 |
| 96 | if g.indent > 0 && g.empty_line { |
| 97 | g.out.write_string(util.tabs(g.indent)) |
| 98 | } |
| 99 | g.out.writeln(s1) |
| 100 | g.empty_line = true |
| 101 | |
| 102 | // expansion for s2 |
| 103 | g.trace_gen('writeln2 s2', s2) |
| 104 | if g.indent > 0 && g.empty_line { |
| 105 | g.out.write_string(util.tabs(g.indent)) |
| 106 | } |
| 107 | g.out.writeln(s2) |
| 108 | g.empty_line = true |
| 109 | } |
| 110 | |
| 111 | // Below are hacks that should be removed at some point. |
| 112 | |
| 113 | fn (mut g Gen) go_back(n int) { |
| 114 | g.out.go_back(n) |
| 115 | // g.out_parallel[g.out_idx].go_back(n) |
| 116 | } |
| 117 | |
| 118 | fn (mut g Gen) go_back_to(n int) { |
| 119 | g.out.go_back_to(n) |
| 120 | // g.out_parallel[g.out_idx].go_back_to(n) |
| 121 | } |
| 122 | |
| 123 | @[inline] |
| 124 | fn (g &Gen) nth_stmt_pos(n int) int { |
| 125 | return g.stmt_path_pos[g.stmt_path_pos.len - (1 + n)] |
| 126 | } |
| 127 | |
| 128 | @[inline] |
| 129 | fn (mut g Gen) set_current_pos_as_last_stmt_pos() { |
| 130 | g.stmt_path_pos << g.out.len |
| 131 | } |
| 132 | |
| 133 | @[inline] |
| 134 | fn (mut g Gen) go_before_last_stmt() string { |
| 135 | return g.out.cut_to(g.nth_stmt_pos(0)) |
| 136 | } |
| 137 | |
| 138 | @[inline] |
| 139 | fn (mut g Gen) go_before_ternary() string { |
| 140 | return g.out.cut_to(g.nth_stmt_pos(g.inside_ternary)) |
| 141 | } |
| 142 | |
| 143 | fn (mut g Gen) insert_before_stmt(s string) { |
| 144 | cur_line := g.out.cut_to(g.nth_stmt_pos(g.inside_ternary)) |
| 145 | g.writeln(s) |
| 146 | g.write(cur_line) |
| 147 | } |
| 148 | |
| 149 | fn (mut g Gen) insert_at(pos int, s string) { |
| 150 | cur_line := g.out.cut_to(pos) |
| 151 | // g.out_parallel[g.out_idx].cut_to(pos) |
| 152 | g.writeln(s) |
| 153 | g.write(cur_line) |
| 154 | |
| 155 | // After modifying the code in the buffer, we need to adjust the positions of the statements |
| 156 | // to account for the added line of code. |
| 157 | // This is necessary to ensure that autofree can properly insert string declarations |
| 158 | // in the correct positions, considering the surgically made changes. |
| 159 | for index, stmt_pos in g.stmt_path_pos { |
| 160 | if stmt_pos >= pos { |
| 161 | g.stmt_path_pos[index] += s.len + 1 |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | |