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:
parent
a82fc5bea0
commit
1c3af091f7
@ -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('string indent_${str_fn_name}(${styp} it, int indent_count) {')
|
||||||
g.auto_str_funcs.writeln('\tstring res;')
|
g.auto_str_funcs.writeln('\tstring res;')
|
||||||
g.auto_str_funcs.writeln('\tif (it.state == 0) {')
|
g.auto_str_funcs.writeln('\tif (it.state == 0) {')
|
||||||
|
deref := if typ.is_ptr() { '**(${sym.cname}**)&' } else { '*(${sym.cname}*)' }
|
||||||
if sym.kind == .string {
|
if sym.kind == .string {
|
||||||
tmp_res := '${parent_str_fn_name}(*(${sym.cname}*)it.data)'
|
if typ.nr_muls() > 1 {
|
||||||
g.auto_str_funcs.writeln('\t\tres = ${str_intp_sq(tmp_res)};')
|
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 {
|
} 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 {
|
} else if sym.kind == .function {
|
||||||
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}();')
|
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}();')
|
||||||
} else {
|
} 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\treturn ${str_intp_sub('Option(%%)', 'res')};')
|
||||||
g.auto_str_funcs.writeln('\t}')
|
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() {
|
} else if ftyp_noshared.is_ptr() {
|
||||||
// reference types can be "nil"
|
// reference types can be "nil"
|
||||||
if ftyp_noshared.has_flag(.option) {
|
if ftyp_noshared.has_flag(.option) {
|
||||||
funcprefix += 'isnil(&it.${field_name})'
|
funcprefix += 'isnil(&it.${field_name}) || isnil(&it.${field_name}.data)'
|
||||||
} else {
|
} else {
|
||||||
funcprefix += 'isnil(it.${field_name})'
|
funcprefix += 'isnil(it.${field_name})'
|
||||||
}
|
}
|
||||||
funcprefix += ' ? _SLIT("nil") : '
|
funcprefix += ' ? _SLIT("nil") : '
|
||||||
// struct, floats and ints have a special case through the _str function
|
// 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() {
|
&& !field.typ.is_int_valptr() && !field.typ.is_float_valptr() {
|
||||||
funcprefix += '*'
|
funcprefix += '*'
|
||||||
}
|
}
|
||||||
|
@ -1099,6 +1099,8 @@ fn (g Gen) option_type_text(styp string, base string) string {
|
|||||||
'u8'
|
'u8'
|
||||||
} else if base.starts_with('anon_fn') {
|
} else if base.starts_with('anon_fn') {
|
||||||
'void*'
|
'void*'
|
||||||
|
} else if base.starts_with('_option_') {
|
||||||
|
base.replace('*', '')
|
||||||
} else {
|
} else {
|
||||||
if base.starts_with('struct ') && !base.ends_with('*') { '${base}*' } else { base }
|
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'
|
'u8'
|
||||||
} else if base.starts_with('anon_fn') {
|
} else if base.starts_with('anon_fn') {
|
||||||
'void*'
|
'void*'
|
||||||
|
} else if base.starts_with('_option_') {
|
||||||
|
base.replace('*', '')
|
||||||
} else {
|
} else {
|
||||||
if base.starts_with('struct ') && !base.ends_with('*') { '${base}*' } else { base }
|
if base.starts_with('struct ') && !base.ends_with('*') { '${base}*' } else { base }
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import strings
|
|||||||
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
|
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
|
||||||
utyp := g.unwrap_generic(typ)
|
utyp := g.unwrap_generic(typ)
|
||||||
sym := g.table.sym(utyp)
|
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
|
return
|
||||||
}
|
}
|
||||||
g.json_types << utyp
|
g.json_types << utyp
|
||||||
@ -45,7 +45,11 @@ fn (mut g Gen) gen_jsons() {
|
|||||||
sym := g.table.sym(utyp)
|
sym := g.table.sym(utyp)
|
||||||
styp := g.typ(utyp)
|
styp := g.typ(utyp)
|
||||||
ret_styp := styp.replace('*', '_ptr')
|
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)
|
g.register_result(utyp)
|
||||||
|
|
||||||
// decode_TYPE funcs receive an actual cJSON* object to decode
|
// decode_TYPE funcs receive an actual cJSON* object to decode
|
||||||
// cJSON_Parse(str) call is added by the compiler
|
// cJSON_Parse(str) call is added by the compiler
|
||||||
// Codegen decoder
|
// Codegen decoder
|
||||||
@ -118,7 +122,9 @@ ${dec_fn_dec} {
|
|||||||
enc.writeln('
|
enc.writeln('
|
||||||
${enc_fn_dec} {
|
${enc_fn_dec} {
|
||||||
\tcJSON *o;')
|
\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 {
|
array_size := if sym.kind == .array_fixed {
|
||||||
(sym.info as ast.ArrayFixed).size
|
(sym.info as ast.ArrayFixed).size
|
||||||
} else {
|
} else {
|
||||||
@ -262,12 +268,42 @@ fn (mut g Gen) gen_enum_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc strin
|
|||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut g Gen) gen_prim_enc_dec(typ ast.Type, mut enc strings.Builder, mut dec strings.Builder) {
|
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))
|
if typ.is_ptr() {
|
||||||
encode_name := js_enc_name(type_str)
|
type_str := g.typ(typ.clear_flag(.option).set_nr_muls(typ.nr_muls() - 1))
|
||||||
enc.writeln('\to = ${encode_name}(val);')
|
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)
|
if typ.nr_muls() > 1 {
|
||||||
dec.writeln('\tres = ${dec_name}(root);')
|
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]
|
[inline]
|
||||||
|
47
vlib/v/tests/option_ptr_ptr_test.v
Normal file
47
vlib/v/tests/option_ptr_ptr_test.v
Normal 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"}'
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user