| 1 | module c |
| 2 | |
| 3 | import v.ast |
| 4 | import v.util |
| 5 | import strings |
| 6 | |
| 7 | fn (mut g Gen) dump_arg_needs_gc_pin(typ ast.Type) bool { |
| 8 | if g.pref.gc_mode !in [.boehm_full, .boehm_incr, .boehm_full_opt, .boehm_incr_opt] { |
| 9 | return false |
| 10 | } |
| 11 | return typ.is_any_kind_of_pointer() || g.contains_ptr(typ) |
| 12 | } |
| 13 | |
| 14 | fn (mut g Gen) dump_expr(node ast.DumpExpr) { |
| 15 | sexpr := ctoslit(node.expr.str()) |
| 16 | fpath := cestring(g.file.path) |
| 17 | line := node.pos.line_nr + 1 |
| 18 | if 'nop_dump' in g.pref.compile_defines { |
| 19 | g.expr(ast.Expr(node.expr)) |
| 20 | return |
| 21 | } |
| 22 | mut name := node.cname |
| 23 | mut expr_type := node.expr_type |
| 24 | if node.expr is ast.CallExpr { |
| 25 | if node.expr.return_type_generic != 0 { |
| 26 | resolved_call_type := g.resolve_return_type(node.expr) |
| 27 | if resolved_call_type != ast.void_type { |
| 28 | expr_type = g.unwrap_generic(resolved_call_type) |
| 29 | name = g.styp(expr_type.clear_flags(.shared_f, .result)).replace('*', '') |
| 30 | } |
| 31 | } |
| 32 | } |
| 33 | if node.expr is ast.PostfixExpr { |
| 34 | if node.expr.expr is ast.CallExpr && node.expr.expr.return_type_generic != 0 { |
| 35 | resolved_postfix_type := g.resolve_return_type(node.expr.expr) |
| 36 | if resolved_postfix_type != ast.void_type { |
| 37 | expr_type = g.unwrap_generic(resolved_postfix_type) |
| 38 | name = g.styp(expr_type.clear_flags(.shared_f, .result)).replace('*', '') |
| 39 | } |
| 40 | } |
| 41 | } |
| 42 | resolved_expr_type := |
| 43 | g.unwrap_generic(g.type_resolver.get_type_or_default(node.expr, expr_type)) |
| 44 | if resolved_expr_type != 0 && resolved_expr_type != expr_type { |
| 45 | expr_type = resolved_expr_type |
| 46 | name = g.styp(expr_type.clear_flags(.shared_f, .result)).replace('*', '') |
| 47 | } |
| 48 | |
| 49 | if node.expr is ast.CallExpr { |
| 50 | g.inside_dump_fn = true |
| 51 | defer(fn) { |
| 52 | g.inside_dump_fn = false |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | if g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0 { |
| 57 | // generic func with recursion rewrite node.expr_type |
| 58 | if node.expr is ast.Ident { |
| 59 | // var |
| 60 | if node.expr.info is ast.IdentVar { |
| 61 | ident_info := node.expr.var_info() |
| 62 | current_fn_ident_type := g.resolve_current_fn_generic_param_type(node.expr.name) |
| 63 | if current_fn_ident_type != 0 { |
| 64 | is_auto_deref := node.expr.obj is ast.Var && node.expr.obj.is_auto_deref |
| 65 | expr_type = if is_auto_deref && current_fn_ident_type.is_ptr() { |
| 66 | current_fn_ident_type.deref() |
| 67 | } else { |
| 68 | current_fn_ident_type |
| 69 | } |
| 70 | } else { |
| 71 | resolved_ident_type := g.unwrap_generic(g.type_resolver.get_type_or_default(ast.Expr(node.expr), |
| 72 | expr_type)) |
| 73 | if resolved_ident_type != 0 && resolved_ident_type != expr_type { |
| 74 | expr_type = resolved_ident_type |
| 75 | } else { |
| 76 | // For variables assigned from generic expressions |
| 77 | // (e.g. `a := T{}`), scope types may be stale from a |
| 78 | // previous generic instantiation. Look up the variable's |
| 79 | // init expression and resolve through generic params. |
| 80 | if node.expr.obj is ast.Var && node.expr.obj.expr is ast.StructInit { |
| 81 | generic_names := g.current_fn_generic_names() |
| 82 | short_name := node.expr.obj.expr.typ_str.all_after_last('.') |
| 83 | idx := generic_names.index(short_name) |
| 84 | if idx >= 0 && idx < g.cur_concrete_types.len { |
| 85 | expr_type = g.cur_concrete_types[idx] |
| 86 | } |
| 87 | } |
| 88 | if expr_type == node.expr_type { |
| 89 | re := g.resolved_expr_type(node.expr, expr_type) |
| 90 | if re != 0 { |
| 91 | expr_type = re |
| 92 | } else { |
| 93 | expr_type = g.unwrap_generic(ident_info.typ) |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | name = g.styp(expr_type.clear_flags(.shared_f, .result)).replace('*', '') |
| 99 | } |
| 100 | } else if node.expr is ast.CallExpr { |
| 101 | name = |
| 102 | g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', '') |
| 103 | } else { |
| 104 | expr_type = g.unwrap_generic(g.type_resolver.get_type_or_default(ast.Expr(node.expr), |
| 105 | expr_type)) |
| 106 | name = g.styp(expr_type.clear_flags(.shared_f, .result)).replace('*', '') |
| 107 | } |
| 108 | } |
| 109 | // var.$(field.name) |
| 110 | if node.expr is ast.ComptimeSelector && node.expr.is_name { |
| 111 | if node.expr.field_expr is ast.SelectorExpr && node.expr.field_expr.expr is ast.Ident { |
| 112 | if node.expr.field_expr.expr.name == g.comptime.comptime_for_field_var { |
| 113 | left_type := g.resolved_expr_type(node.expr.left, node.expr.left_type) |
| 114 | field, _ := g.resolve_comptime_selector_field(node.expr, left_type) |
| 115 | name = g.styp(g.unwrap_generic(field.typ.clear_flags(.shared_f, .result))) |
| 116 | expr_type = field.typ |
| 117 | } |
| 118 | } |
| 119 | } else if node.expr is ast.Ident && node.expr.ct_expr { |
| 120 | for { |
| 121 | if node.expr.obj is ast.Var { |
| 122 | if node.expr.obj.ct_type_var == .field_var && g.comptime.inside_comptime_for |
| 123 | && g.comptime.comptime_for_field_var != '' { |
| 124 | expr_type = if node.expr.obj.ct_type_unwrapped || node.expr.obj.is_unwrapped { |
| 125 | g.comptime.comptime_for_field_type.clear_flag(.option) |
| 126 | } else { |
| 127 | g.comptime.comptime_for_field_type |
| 128 | } |
| 129 | break |
| 130 | } |
| 131 | ct_var := node.expr.obj.ct_type_var |
| 132 | if ct_var == .generic_param || ct_var == .generic_var { |
| 133 | if scope_var := node.expr.scope.find_var(node.expr.name) { |
| 134 | if scope_var.ct_type_var == .smartcast { |
| 135 | // The scope var was updated to smartcast (e.g. inside |
| 136 | // `if val is v` in a comptime $for variants loop). |
| 137 | // Use the comptime variant type directly. |
| 138 | ctyp := g.type_resolver.get_ct_type_or_default('${g.comptime.comptime_for_variant_var}.typ', |
| 139 | scope_var.typ) |
| 140 | expr_type = if scope_var.is_unwrapped { |
| 141 | ctyp.clear_flag(.option) |
| 142 | } else { |
| 143 | ctyp |
| 144 | } |
| 145 | break |
| 146 | } else if scope_var.ct_type_var == ct_var && g.cur_fn != unsafe { nil } |
| 147 | && g.cur_fn.generic_names.len > 0 { |
| 148 | // For generic_param/generic_var, node.obj.typ is a stale |
| 149 | // copy from checker time. Use the refreshed scope var. |
| 150 | expr_type = scope_var.typ |
| 151 | break |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | } |
| 156 | expr_type = g.type_resolver.get_type(ast.Expr(node.expr)) |
| 157 | break |
| 158 | } |
| 159 | name = g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', '') |
| 160 | } else if node.expr is ast.SelectorExpr && node.expr.expr is ast.Ident |
| 161 | && (node.expr.expr as ast.Ident).ct_expr { |
| 162 | ct_expr_type := g.comptime_selector_type(node.expr) |
| 163 | // Only override if the checker hasn't already resolved to a more |
| 164 | // specific (smartcasted) type. When inside a sumtype/option smartcast |
| 165 | // branch, node.expr_type is the concrete unwrapped type from the |
| 166 | // checker which is more accurate than what comptime_selector_type |
| 167 | // resolves (it uses a stale struct_type for scope lookups in generics). |
| 168 | ct_sym := g.table.sym(ct_expr_type) |
| 169 | node_sym := g.table.sym(expr_type) |
| 170 | if ct_sym.kind !in [.sum_type, .interface] || node_sym.kind in [.sum_type, .interface] |
| 171 | || expr_type.has_option_or_result() { |
| 172 | expr_type = ct_expr_type |
| 173 | name = |
| 174 | g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', '') |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | if g.table.sym(node.expr_type).language == .c { |
| 179 | name = name[3..] |
| 180 | } |
| 181 | if node.expr is ast.Ident { |
| 182 | // Don't override with the generic param type when inside a comptime |
| 183 | // variant smartcast, as the variant type is more specific. |
| 184 | mut is_comptime_smartcast := false |
| 185 | if node.expr.ct_expr && node.expr.obj is ast.Var { |
| 186 | if scope_var := node.expr.scope.find_var(node.expr.name) { |
| 187 | is_comptime_smartcast = scope_var.ct_type_var == .smartcast |
| 188 | } |
| 189 | } |
| 190 | if !is_comptime_smartcast { |
| 191 | current_fn_ident_type := g.resolve_current_fn_generic_param_type(node.expr.name) |
| 192 | if current_fn_ident_type != 0 { |
| 193 | is_auto_deref := node.expr.obj is ast.Var && node.expr.obj.is_auto_deref |
| 194 | expr_type = if is_auto_deref && current_fn_ident_type.is_ptr() { |
| 195 | current_fn_ident_type.deref() |
| 196 | } else { |
| 197 | current_fn_ident_type |
| 198 | } |
| 199 | name = g.styp(expr_type.clear_flags(.shared_f, .result)).replace('*', '') |
| 200 | } |
| 201 | } |
| 202 | if (expr_type.is_ptr() || expr_type.has_flag(.option_mut_param_t)) |
| 203 | && expr_type.has_flag(.option) { |
| 204 | if scope_var := node.expr.scope.find_var(node.expr.name) { |
| 205 | if scope_var.typ.has_flag(.option_mut_param_t) { |
| 206 | expr_type = scope_var.typ |
| 207 | // For mut option params, the type is ?&T. Strip the inner pointer |
| 208 | // from the name since __ptr is appended separately from is_ptr(). |
| 209 | mut cleared_typ := expr_type.clear_flags(.shared_f, .result, |
| 210 | .option_mut_param_t) |
| 211 | if cleared_typ.has_flag(.option) { |
| 212 | inner := cleared_typ.clear_option_and_result() |
| 213 | if inner.is_ptr() { |
| 214 | cleared_typ = inner.deref().set_flag(.option) |
| 215 | } |
| 216 | } |
| 217 | name = g.styp(cleared_typ).replace('*', '') |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | dump_fn_name := '_v_dump_expr_${name}' + (if expr_type.is_ptr() && !expr_type.has_flag(.option_mut_param_t) { |
| 223 | '__ptr'.repeat(expr_type.nr_muls()) |
| 224 | } else { |
| 225 | '' |
| 226 | }) |
| 227 | g.write(' ${dump_fn_name}(${ctoslit(fpath)}, ${line}, ${sexpr}, ') |
| 228 | if expr_type.has_flag(.shared_f) { |
| 229 | g.write('&') |
| 230 | g.expr(ast.Expr(node.expr)) |
| 231 | g.write('->val') |
| 232 | } else if expr_type.has_flag(.result) { |
| 233 | old_inside_opt_or_res := g.inside_opt_or_res |
| 234 | g.inside_opt_or_res = true |
| 235 | g.write('(*(${name}*)') |
| 236 | g.expr(ast.Expr(node.expr)) |
| 237 | g.write('.data)') |
| 238 | g.inside_opt_or_res = old_inside_opt_or_res |
| 239 | } else if node.expr is ast.ArrayInit { |
| 240 | if node.expr.is_fixed { |
| 241 | s := g.styp(node.expr.typ) |
| 242 | if !node.expr.has_index { |
| 243 | g.write('(${s})') |
| 244 | } |
| 245 | } |
| 246 | g.expr(ast.Expr(node.expr)) |
| 247 | } else { |
| 248 | old_inside_opt_or_res := g.inside_opt_or_res |
| 249 | g.inside_opt_or_res = true |
| 250 | if expr_type.has_flag(.option_mut_param_t) { |
| 251 | g.write('*') |
| 252 | } |
| 253 | if node.expr is ast.Ident && node.expr.obj is ast.Var { |
| 254 | if node.expr.obj.is_auto_deref && !expr_type.is_ptr() { |
| 255 | g.write('*') |
| 256 | } |
| 257 | } |
| 258 | for { |
| 259 | if node.expr is ast.Ident { |
| 260 | if node.expr.obj is ast.Var { |
| 261 | if node.expr.obj.ct_type_var == .field_var && g.comptime.inside_comptime_for |
| 262 | && (node.expr.obj.ct_type_unwrapped || node.expr.obj.is_unwrapped) { |
| 263 | field_type := g.comptime.comptime_for_field_type |
| 264 | if field_type.has_flag(.option) { |
| 265 | styp := g.base_type(field_type.clear_flag(.option)) |
| 266 | is_auto_heap := node.expr.is_auto_heap() |
| 267 | ptr := if is_auto_heap { '->' } else { '.' } |
| 268 | g.write('(*(${styp}*)${c_name(node.expr.name)}${ptr}data)') |
| 269 | break |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | } |
| 274 | g.expr(ast.Expr(node.expr)) |
| 275 | break |
| 276 | } |
| 277 | g.inside_opt_or_res = old_inside_opt_or_res |
| 278 | } |
| 279 | g.write(')') |
| 280 | if (g.inside_assign || g.expected_fixed_arr) && !expr_type.has_option_or_result() |
| 281 | && g.table.final_sym(expr_type).kind == .array_fixed { |
| 282 | g.write('.ret_arr') |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | fn (mut g Gen) dump_expr_definitions() { |
| 287 | mut dump_already_generated_fns := map[string]bool{} |
| 288 | mut dump_typedefs := map[string]bool{} |
| 289 | mut dump_fns := strings.new_builder(100) |
| 290 | mut dump_fn_defs := strings.new_builder(100) |
| 291 | for dump_type, cname in g.table.dumps { |
| 292 | raw_typ := ast.idx_to_type(dump_type) |
| 293 | typ := if raw_typ.has_flag(.option_mut_param_t) && raw_typ.is_ptr() { |
| 294 | raw_typ.deref().clear_flag(.option_mut_param_t) |
| 295 | } else { |
| 296 | raw_typ |
| 297 | } |
| 298 | dump_sym := g.table.sym(typ) |
| 299 | // eprintln('>>> dump_type: ${dump_type} | cname: ${cname} | dump_sym: ${dump_sym.name}') |
| 300 | mut name := cname |
| 301 | if dump_sym.language == .c { |
| 302 | name = name[3..] |
| 303 | } |
| 304 | _, str_method_expects_ptr, _ := dump_sym.str_method_info() |
| 305 | if g.pref.skip_unused |
| 306 | && (!g.table.used_features.dump || typ.idx() !in g.table.used_features.used_syms) { |
| 307 | continue |
| 308 | } |
| 309 | is_ptr := typ.is_ptr() |
| 310 | deref, _ := deref_kind(str_method_expects_ptr, is_ptr, typ) |
| 311 | to_string_fn_name := g.get_str_fn(typ.clear_flags(.shared_f, .result)) |
| 312 | is_option := typ.has_option_or_result() |
| 313 | mut ptr_asterisk := if is_ptr { '*'.repeat(typ.nr_muls()) } else { '' } |
| 314 | mut str_dumparg_type := '' |
| 315 | mut str_dumparg_ret_type := '' |
| 316 | if dump_sym.kind == .none { |
| 317 | str_dumparg_type = 'IError' + ptr_asterisk |
| 318 | } else if dump_sym.kind == .function { |
| 319 | if is_option { |
| 320 | ptr_asterisk = ptr_asterisk.replace('*', '_ptr') |
| 321 | } |
| 322 | str_dumparg_type += g.styp(typ).replace('*', '') + ptr_asterisk |
| 323 | } else { |
| 324 | if is_option { |
| 325 | str_dumparg_type += '_option_' |
| 326 | ptr_asterisk = ptr_asterisk.replace('*', '_ptr') |
| 327 | } |
| 328 | str_dumparg_type += g.cc_type(typ, true) + ptr_asterisk |
| 329 | } |
| 330 | mut is_fixed_arr_ret := false |
| 331 | if dump_sym.info is ast.FnType && !is_option { |
| 332 | str_dumparg_type = 'DumpFNType_${name}' |
| 333 | tdef_pos := g.out.len |
| 334 | g.write_fn_ptr_decl(&dump_sym.info, str_dumparg_type) |
| 335 | str_tdef := g.out.after(tdef_pos) |
| 336 | g.go_back(str_tdef.len) |
| 337 | dump_typedefs['typedef ${str_tdef};'] = true |
| 338 | str_dumparg_ret_type = str_dumparg_type |
| 339 | } else if !is_option && dump_sym.is_array_fixed() { |
| 340 | match dump_sym.kind { |
| 341 | .array_fixed { |
| 342 | if (dump_sym.info as ast.ArrayFixed).is_fn_ret { |
| 343 | str_dumparg_ret_type = str_dumparg_type |
| 344 | str_dumparg_type = str_dumparg_type.trim_string_left('_v_') |
| 345 | } else { |
| 346 | // fixed array returned from function |
| 347 | str_dumparg_ret_type = '_v_' + str_dumparg_type |
| 348 | } |
| 349 | } |
| 350 | .alias { |
| 351 | parent_sym := g.table.sym((dump_sym.info as ast.Alias).parent_type) |
| 352 | if parent_sym.kind == .array_fixed { |
| 353 | str_dumparg_ret_type = |
| 354 | if (parent_sym.info as ast.ArrayFixed).is_fn_ret { '' } else { '_v_' } + |
| 355 | g.cc_type((dump_sym.info as ast.Alias).parent_type, true) |
| 356 | str_dumparg_type = str_dumparg_ret_type.trim_string_left('_v_') |
| 357 | is_fixed_arr_ret = true |
| 358 | } |
| 359 | } |
| 360 | else {} |
| 361 | } |
| 362 | |
| 363 | is_fixed_arr_ret = true |
| 364 | } else { |
| 365 | str_dumparg_ret_type = str_dumparg_type |
| 366 | } |
| 367 | dump_fn_name := '_v_dump_expr_${name}' + |
| 368 | (if is_ptr { '__ptr'.repeat(typ.nr_muls()) } else { '' }) |
| 369 | |
| 370 | // protect against duplicate declarations: |
| 371 | if dump_already_generated_fns[dump_fn_name] { |
| 372 | continue |
| 373 | } |
| 374 | dump_already_generated_fns[dump_fn_name] = true |
| 375 | |
| 376 | dump_fn_defs.writeln('${str_dumparg_ret_type} ${dump_fn_name}(string fpath, ${ast.int_type_name} line, string sexpr, ${str_dumparg_type} dump_arg);') |
| 377 | if g.writeln_fn_header('${str_dumparg_ret_type} ${dump_fn_name}(string fpath, ${ast.int_type_name} line, string sexpr, ${str_dumparg_type} dump_arg)', mut |
| 378 | dump_fns) |
| 379 | { |
| 380 | continue |
| 381 | } |
| 382 | mut surrounder := util.new_surrounder(2) |
| 383 | int_str := g.get_str_fn(ast.int_type) |
| 384 | surrounder.add('\tstring sline = ${int_str}(line);', '\tbuiltin__string_free(&sline);') |
| 385 | if dump_sym.kind == .function && !is_option { |
| 386 | surrounder.add('\tstring value = ${to_string_fn_name}();', |
| 387 | '\tbuiltin__string_free(&value);') |
| 388 | } else if dump_sym.kind == .none { |
| 389 | surrounder.add('\tstring value = _S("none");', '\tbuiltin__string_free(&value);') |
| 390 | } else if is_ptr { |
| 391 | if typ.has_flag(.option) { |
| 392 | surrounder.add('\tstring value = builtin__isnil(&dump_arg.data) ? _S("nil") : ${to_string_fn_name}(${deref}dump_arg);', |
| 393 | '\tbuiltin__string_free(&value);') |
| 394 | } else { |
| 395 | prefix := if dump_sym.is_c_struct() { |
| 396 | c_struct_ptr(dump_sym, typ, str_method_expects_ptr) |
| 397 | } else { |
| 398 | deref |
| 399 | } |
| 400 | surrounder.add('\tstring value = (dump_arg == NULL) ? _S("nil") : ${to_string_fn_name}(${prefix}dump_arg);', |
| 401 | '\tbuiltin__string_free(&value);') |
| 402 | } |
| 403 | } else { |
| 404 | prefix := if dump_sym.is_c_struct() { |
| 405 | c_struct_ptr(dump_sym, typ, str_method_expects_ptr) |
| 406 | } else { |
| 407 | deref |
| 408 | } |
| 409 | surrounder.add('\tstring value = ${to_string_fn_name}(${prefix}dump_arg);', |
| 410 | '\tbuiltin__string_free(&value);') |
| 411 | } |
| 412 | surrounder.builder_write_befores(mut dump_fns) |
| 413 | dump_fns.writeln('\tbuiltin__flush_stdout();') |
| 414 | dump_fns.writeln('\tbuiltin__flush_stderr();') |
| 415 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, _S("[").str, _S("[").len);') |
| 416 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, fpath.str, fpath.len);') |
| 417 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, _S(":").str, _S(":").len);') |
| 418 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, sline.str, sline.len);') |
| 419 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, _S("] ").str, _S("] ").len);') |
| 420 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, sexpr.str, sexpr.len);') |
| 421 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, _S(": ").str, _S(": ").len);') |
| 422 | if is_ptr { |
| 423 | ptr_prefix := '&'.repeat(typ.nr_muls()) |
| 424 | dump_fns.writeln('\tbuiltin___write_buf_to_fd(2, _S("${ptr_prefix}").str, _S("${ptr_prefix}").len);') |
| 425 | } |
| 426 | dump_fns.writeln('\tbuiltin___writeln_to_fd(2, value);') |
| 427 | dump_fns.writeln('\tbuiltin__flush_stderr();') |
| 428 | if g.dump_arg_needs_gc_pin(typ) { |
| 429 | if is_ptr && !typ.has_flag(.option) { |
| 430 | dump_fns.writeln('\tGC_reachable_here(dump_arg);') |
| 431 | } else { |
| 432 | dump_fns.writeln('\tGC_reachable_here(&dump_arg);') |
| 433 | } |
| 434 | } |
| 435 | surrounder.builder_write_afters(mut dump_fns) |
| 436 | if is_fixed_arr_ret && !is_ptr { |
| 437 | tmp_var := g.new_tmp_var() |
| 438 | init_str := if dump_sym.is_empty_struct_array() { |
| 439 | '{E_STRUCT}' |
| 440 | } else { |
| 441 | '{0}' |
| 442 | } |
| 443 | dump_fns.writeln('\t${str_dumparg_ret_type} ${tmp_var} = ${init_str};') |
| 444 | dump_fns.writeln('\tmemcpy(${tmp_var}.ret_arr, dump_arg, sizeof(${str_dumparg_type}));') |
| 445 | dump_fns.writeln('\treturn ${tmp_var};') |
| 446 | } else { |
| 447 | dump_fns.writeln('\treturn dump_arg; /* ${str_dumparg_type} */') |
| 448 | } |
| 449 | dump_fns.writeln('}') |
| 450 | } |
| 451 | for tdef, _ in dump_typedefs { |
| 452 | g.definitions.writeln(tdef) |
| 453 | } |
| 454 | if dump_fn_defs.len > 0 { |
| 455 | g.definitions.writeln(dump_fn_defs.str()) |
| 456 | g.dump_funcs.writeln(dump_fns.str()) |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | fn (mut g Gen) writeln_fn_header(s string, mut sb strings.Builder) bool { |
| 461 | if g.pref.build_mode == .build_module { |
| 462 | sb.writeln('${s};') |
| 463 | return true |
| 464 | } |
| 465 | sb.writeln('${s} {') |
| 466 | return false |
| 467 | } |
| 468 | |