v2 / vlib / v / gen / c / dumpexpr.v
467 lines · 456 sloc · 16.69 KB · 07c796b670d9e498ccb25605af189617f61ec295
Raw
1module c
2
3import v.ast
4import v.util
5import strings
6
7fn (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
14fn (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
286fn (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
460fn (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