1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen, json: fix option ptr declaration and dumping (#18119)

This commit is contained in:
Felipe Pena 2023-05-06 21:54:43 -03:00 committed by GitHub
parent a82fc5bea0
commit 1c3af091f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 13 deletions

View File

@ -185,15 +185,24 @@ fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string)
g.auto_str_funcs.writeln('string indent_${str_fn_name}(${styp} it, int indent_count) {')
g.auto_str_funcs.writeln('\tstring res;')
g.auto_str_funcs.writeln('\tif (it.state == 0) {')
deref := if typ.is_ptr() { '**(${sym.cname}**)&' } else { '*(${sym.cname}*)' }
if sym.kind == .string {
tmp_res := '${parent_str_fn_name}(*(${sym.cname}*)it.data)'
g.auto_str_funcs.writeln('\t\tres = ${str_intp_sq(tmp_res)};')
if typ.nr_muls() > 1 {
g.auto_str_funcs.writeln('\t\tres = ptr_str(*(${sym.cname}**)&it.data);')
} else {
tmp_res := '${parent_str_fn_name}(${deref}it.data)'
g.auto_str_funcs.writeln('\t\tres = ${str_intp_sq(tmp_res)};')
}
} else if should_use_indent_func(sym.kind) && !sym_has_str_method {
g.auto_str_funcs.writeln('\t\tres = indent_${parent_str_fn_name}(*(${sym.cname}*)it.data, indent_count);')
g.auto_str_funcs.writeln('\t\tres = indent_${parent_str_fn_name}(${deref}it.data, indent_count);')
} else if sym.kind == .function {
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}();')
} else {
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}(*(${sym.cname}*)it.data);')
if typ.nr_muls() > 1 {
g.auto_str_funcs.writeln('\t\tres = ptr_str(*(${sym.cname}**)&it.data);')
} else {
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}(${deref}it.data);')
}
}
g.auto_str_funcs.writeln('\t\treturn ${str_intp_sub('Option(%%)', 'res')};')
g.auto_str_funcs.writeln('\t}')
@ -962,13 +971,14 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
} else if ftyp_noshared.is_ptr() {
// reference types can be "nil"
if ftyp_noshared.has_flag(.option) {
funcprefix += 'isnil(&it.${field_name})'
funcprefix += 'isnil(&it.${field_name}) || isnil(&it.${field_name}.data)'
} else {
funcprefix += 'isnil(it.${field_name})'
}
funcprefix += ' ? _SLIT("nil") : '
// struct, floats and ints have a special case through the _str function
if sym.kind !in [.struct_, .alias, .enum_, .sum_type, .map, .interface_]
if !ftyp_noshared.has_flag(.option)
&& sym.kind !in [.struct_, .alias, .enum_, .sum_type, .map, .interface_]
&& !field.typ.is_int_valptr() && !field.typ.is_float_valptr() {
funcprefix += '*'
}

View File

@ -1099,6 +1099,8 @@ fn (g Gen) option_type_text(styp string, base string) string {
'u8'
} else if base.starts_with('anon_fn') {
'void*'
} else if base.starts_with('_option_') {
base.replace('*', '')
} else {
if base.starts_with('struct ') && !base.ends_with('*') { '${base}*' } else { base }
}
@ -1116,6 +1118,8 @@ fn (g Gen) result_type_text(styp string, base string) string {
'u8'
} else if base.starts_with('anon_fn') {
'void*'
} else if base.starts_with('_option_') {
base.replace('*', '')
} else {
if base.starts_with('struct ') && !base.ends_with('*') { '${base}*' } else { base }
}

View File

@ -26,7 +26,7 @@ import strings
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
utyp := g.unwrap_generic(typ)
sym := g.table.sym(utyp)
if is_js_prim(sym.name) && !utyp.has_flag(.option) {
if is_js_prim(sym.name) && !utyp.has_flag(.option) && !typ.is_ptr() {
return
}
g.json_types << utyp
@ -45,7 +45,11 @@ fn (mut g Gen) gen_jsons() {
sym := g.table.sym(utyp)
styp := g.typ(utyp)
ret_styp := styp.replace('*', '_ptr')
if utyp.is_ptr() && utyp.has_flag(.option) {
g.register_option(utyp.set_nr_muls(0))
}
g.register_result(utyp)
// decode_TYPE funcs receive an actual cJSON* object to decode
// cJSON_Parse(str) call is added by the compiler
// Codegen decoder
@ -118,7 +122,9 @@ ${dec_fn_dec} {
enc.writeln('
${enc_fn_dec} {
\tcJSON *o;')
if sym.kind == .array || sym.kind == .array_fixed {
if is_js_prim(sym.name) && utyp.is_ptr() {
g.gen_prim_enc_dec(utyp, mut enc, mut dec)
} else if sym.kind == .array || sym.kind == .array_fixed {
array_size := if sym.kind == .array_fixed {
(sym.info as ast.ArrayFixed).size
} else {
@ -262,12 +268,42 @@ fn (mut g Gen) gen_enum_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc strin
[inline]
fn (mut g Gen) gen_prim_enc_dec(typ ast.Type, mut enc strings.Builder, mut dec strings.Builder) {
type_str := g.typ(typ.clear_flag(.option))
encode_name := js_enc_name(type_str)
enc.writeln('\to = ${encode_name}(val);')
if typ.is_ptr() {
type_str := g.typ(typ.clear_flag(.option).set_nr_muls(typ.nr_muls() - 1))
type_str_0 := g.typ(typ.clear_flag(.option).set_nr_muls(0))
encode_name := js_enc_name(type_str_0)
dec_name := js_dec_name(type_str)
if typ.has_flag(.option) {
enc.writeln('\to = ${encode_name}(${'*'.repeat(typ.nr_muls() + 1)}(${type_str_0}${'*'.repeat(typ.nr_muls())}*)&val.data);')
} else {
enc.writeln('\to = ${encode_name}(${'*'.repeat(typ.nr_muls())}val);')
}
dec_name := js_dec_name(type_str)
dec.writeln('\tres = ${dec_name}(root);')
if typ.nr_muls() > 1 {
g.gen_json_for_type(typ.clear_flag(.option).set_nr_muls(typ.nr_muls() - 1))
if typ.has_flag(.option) {
tmp_var := g.new_tmp_var()
dec.writeln('${type_str}* ${tmp_var} = HEAP(${type_str}, *(${type_str}*) ${dec_name}(root).data);')
dec.writeln('\t_option_ok(&(${type_str}*[]) { &(*(${tmp_var})) }, (${option_name}*)&res, sizeof(${type_str}*));')
} else {
dec.writeln('\tres = HEAP(${type_str}, *(${type_str}*) ${dec_name}(root).data);')
}
} else {
if typ.has_flag(.option) {
tmp_var := g.new_tmp_var()
dec.writeln('${type_str}* ${tmp_var} = HEAP(${type_str}, ${dec_name}(root));')
dec.writeln('\t_option_ok(&(${type_str}*[]) { &(*(${tmp_var})) }, (${option_name}*)&res, sizeof(${type_str}*));')
} else {
dec.writeln('\tres = HEAP(${type_str}, ${dec_name}(root));')
}
}
} else {
type_str := g.typ(typ.clear_flag(.option))
encode_name := js_enc_name(type_str)
dec_name := js_dec_name(type_str)
enc.writeln('\to = ${encode_name}(val);')
dec.writeln('\tres = ${dec_name}(root);')
}
}
[inline]

View File

@ -0,0 +1,47 @@
import json
[heap]
struct Foo {
a &int
b &string
c &f64
d &&int
e &&&string
}
struct FooOption {
mut:
a ?&int
b ?&string
c ?&f64
d ?&&int
e ?&&&string
}
fn test_ptr() {
data := '{ "a": 123, "b": "foo", "c": 1.2, "d": 321, "e": "bar"}'
foo := json.decode(Foo, data)!
println(foo)
assert dump(*foo.a) == 123
assert dump(*foo.b) == 'foo'
assert dump(*foo.c) == 1.2
assert dump(**foo.d) == 321
assert dump(***foo.e) == 'bar'
assert dump(json.encode(foo)) == '{"a":123,"b":"foo","c":1.2,"d":321,"e":"bar"}'
}
fn test_option_ptr() ? {
data := '{ "a": 123, "b": "foo", "c": 1.2, "d": 321, "e": "bar"}'
foo := json.decode(FooOption, data) or { return none }
println(foo)
assert dump(*foo.a?) == 123
assert dump(*foo.b?) == 'foo'
assert dump(*foo.c?) == 1.2
assert dump(**foo.d?) == 321
assert dump(***foo.e?) == 'bar'
assert dump(json.encode(foo)) == '{"a":123,"b":"foo","c":1.2,"d":321,"e":"bar"}'
}