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

checker,json2: relax checking of x.enum = integer at comptime; refactor json2 to clean it up (#16926)

This commit is contained in:
Hitalo Souza 2023-01-11 05:18:45 -03:00 committed by GitHub
parent 09f48455c5
commit d1306ffcf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 24 deletions

View File

@ -592,11 +592,20 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', c.warn('pointer arithmetic is only allowed in `unsafe` blocks',
node.pos) node.pos)
} }
} else {
// allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum
if c.inside_comptime_for_field && left is ast.ComptimeSelector {
field_sym := c.table.sym(c.unwrap_generic(c.comptime_fields_default_type))
if field_sym.kind == .enum_ && !right_type.is_int() {
c.error('enums can only be assigned `int` values', right.pos())
}
} else { } else {
c.error('cannot assign to `${left}`: ${err.msg()}', right.pos()) c.error('cannot assign to `${left}`: ${err.msg()}', right.pos())
} }
} }
} }
}
if left_sym.kind == .interface_ { if left_sym.kind == .interface_ {
if c.type_implements(right_type, left_type, right.pos()) { if c.type_implements(right_type, left_type, right.pos()) {
if !right_type.is_ptr() && !right_type.is_pointer() && right_sym.kind != .interface_ if !right_type.is_ptr() && !right_type.is_pointer() && right_sym.kind != .interface_

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/assign_enum_at_comptime.vv:13:21: error: enums can only be assigned `int` values
11 |
12 | $for field in TestStruct.fields {
13 | t.$(field.name) = '1'
| ~~~
14 | }
15 | }

View File

@ -0,0 +1,15 @@
enum TestEnum {
one = 1
}
struct TestStruct {
test TestEnum
}
fn main() {
mut t := TestStruct{}
$for field in TestStruct.fields {
t.$(field.name) = '1'
}
}

View File

@ -5,6 +5,14 @@ mut:
name string name string
} }
enum TestEnum {
one = 1
}
struct TestStruct {
test TestEnum
}
fn comptime_field_selector_read[T]() []string { fn comptime_field_selector_read[T]() []string {
mut t := T{} mut t := T{}
t.name = '2' t.name = '2'
@ -42,6 +50,15 @@ fn test_comptime_field_selector_write() {
assert res.name == '1' assert res.name == '1'
} }
fn test_comptime_field_selector_write_enum() {
mut t := TestStruct{}
$for field in TestStruct.fields {
t.$(field.name) = 1
}
assert t.test == .one
}
struct Foo2 { struct Foo2 {
f Foo f Foo
} }

View File

@ -63,6 +63,12 @@ fn test_types() {
val: 1 val: 1
} }
}) == '{"val":{"val":1}}' }) == '{"val":{"val":1}}'
assert json.encode(StructType[Enumerates]{}) == '{"val":0}'
assert json.encode(StructType[Enumerates]{ val: Enumerates.a }) == '{"val":0}'
assert json.encode(StructType[Enumerates]{ val: Enumerates.d }) == '{"val":3}'
assert json.encode(StructType[Enumerates]{ val: Enumerates.e }) == '{"val":99}'
assert json.encode(StructType[Enumerates]{ val: Enumerates.f }) == '{"val":100}'
} }
fn test_option_types() { fn test_option_types() {

View File

@ -207,6 +207,9 @@ fn (e &Encoder) encode_struct[U](val U, level int, mut wr io.Writer) ! {
e.encode_string(parsed_time.format_rfc3339(), mut wr)! e.encode_string(parsed_time.format_rfc3339(), mut wr)!
} $else $if field.is_array { } $else $if field.is_array {
e.encode_array(value, level + 1, mut wr)! e.encode_array(value, level + 1, mut wr)!
} $else $if field.is_enum {
option_value := val.$(field.name) as ?int
wr.write(Any(option_value).int().str().bytes())!
} $else $if field.is_alias { } $else $if field.is_alias {
match field.unaliased_typ { match field.unaliased_typ {
typeof[string]().idx { typeof[string]().idx {
@ -253,6 +256,8 @@ fn (e &Encoder) encode_struct[U](val U, level int, mut wr io.Writer) ! {
e.encode_array(value, level + 1, mut wr)! e.encode_array(value, level + 1, mut wr)!
} $else $if field.is_struct { } $else $if field.is_struct {
e.encode_struct(value, level + 1, mut wr)! e.encode_struct(value, level + 1, mut wr)!
} $else $if field.is_enum {
wr.write(int(val.$(field.name)).str().bytes())!
} $else $if field.is_alias { } $else $if field.is_alias {
match field.unaliased_typ { match field.unaliased_typ {
typeof[string]().idx { typeof[string]().idx {

View File

@ -51,6 +51,13 @@ pub fn decode[T](src string) !T {
typ.$(field.name) = res[field.name]!.str() typ.$(field.name) = res[field.name]!.str()
} $else $if field.typ is time.Time { } $else $if field.typ is time.Time {
typ.$(field.name) = res[field.name]!.to_time()! typ.$(field.name) = res[field.name]!.to_time()!
} $else $if field.is_array {
// typ.$(field.name) = res[field.name]!.arr()
} $else $if field.is_struct {
} $else $if field.is_enum {
typ.$(field.name) = res[field.name]!.int()
} $else $if field.is_alias {
} $else $if field.is_map {
} $else { } $else {
return error("The type of `${field.name}` can't be decoded. Please open an issue at https://github.com/vlang/v/issues/new/choose") return error("The type of `${field.name}` can't be decoded. Please open an issue at https://github.com/vlang/v/issues/new/choose")
} }

View File

@ -12,25 +12,25 @@ pub mut:
name string name string
age int age int
salary f32 salary f32
// title JobTitle //! FIXME - decode title JobTitle
// sub_employee SubEmployee //! FIXME - decode sub_employee SubEmployee //! FIXME - decode
} }
struct SubEmployee { pub struct SubEmployee {
pub mut: pub mut:
name string name string
age int age int
salary f32 salary f32
// title JobTitle //! FIXME - decode title JobTitle
} }
fn test_simple() { fn test_simple() {
sub_employee := SubEmployee{ sub_employee := SubEmployee{
name: 'João' name: 'João'
} }
x := Employee{'Peter', 28, 95000.5} x := Employee{'Peter', 28, 95000.5, .worker, sub_employee}
s := json.encode[Employee](x) s := json.encode[Employee](x)
assert s == '{"name":"Peter","age":28,"salary":95000.5}' assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2,"sub_employee":{"name":"João","age":0,"salary":0.0,"title":0}}'
y := json.decode[Employee](s) or { y := json.decode[Employee](s) or {
println(err) println(err)
@ -40,10 +40,10 @@ fn test_simple() {
assert y.name == 'Peter' assert y.name == 'Peter'
assert y.age == 28 assert y.age == 28
assert y.salary == 95000.5 assert y.salary == 95000.5
// assert y.title == .worker //! FIXME assert y.title == .worker
// assert y.sub_employee.name == 'Peter' // assert y.sub_employee.name == 'João'
// assert y.sub_employee.age == 0 assert y.sub_employee.age == 0
// assert y.sub_employee.salary == 0.0 assert y.sub_employee.salary == 0.0
// assert y.sub_employee.title == .worker //! FIXME // assert y.sub_employee.title == .worker //! FIXME
} }

View File

@ -25,7 +25,7 @@ pub struct Price {
//! BUGFIX //! BUGFIX
fn test_field_with_default_expr() { fn test_field_with_default_expr() {
data := '[{"net":1},{"net":2,"currencyId":"cjson"}]' data := '[{"net":1},{"net":2,"currencyId":"cjson"}]'
prices := json.decode<[]Price>(data)! prices := json.decode[[]Price](data)!
assert prices == [Price{ assert prices == [Price{
net: 1 net: 1
currency_id: 'cconst' currency_id: 'cconst'
@ -38,7 +38,7 @@ fn test_field_with_default_expr() {
//! BUGFIX - .from_json(res) //! BUGFIX - .from_json(res)
fn test_decode_top_level_array() { fn test_decode_top_level_array() {
s := '[{"name":"Peter", "age": 29}, {"name":"Bob", "age":31}]' s := '[{"name":"Peter", "age": 29}, {"name":"Bob", "age":31}]'
x := json.decode<[]Employee>(s) or { panic(err) } x := json.decode[[]Employee](s) or { panic(err) }
assert x.len == 2 assert x.len == 2
assert x[0].name == 'Peter' assert x[0].name == 'Peter'
assert x[0].age == 29 assert x[0].age == 29
@ -86,7 +86,7 @@ fn test_encode_decode_sumtype() {
assert enc == '{"title":"Super Mega Game","player":{"name":"Monke","_type":"Human"},"other":[{"tag":"Pen","_type":"Item"},{"tag":"Cookie","_type":"Item"},1,"Stool",{"_type":"Time","value":${t.unix_time()}}]}' assert enc == '{"title":"Super Mega Game","player":{"name":"Monke","_type":"Human"},"other":[{"tag":"Pen","_type":"Item"},{"tag":"Cookie","_type":"Item"},1,"Stool",{"_type":"Time","value":${t.unix_time()}}]}'
dec := json.decode<SomeGame>(enc)! dec := json.decode[SomeGame](enc)!
assert game.title == dec.title assert game.title == dec.title
assert game.player == dec.player assert game.player == dec.player
@ -114,8 +114,8 @@ pub mut:
fn test_parse_user() { fn test_parse_user() {
s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}' s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}'
u2 := json.decode<User2>(s)! u2 := json.decode[User2](s)!
u := json.decode<User>(s)! u := json.decode[User](s)!
assert u.age == 10 assert u.age == 10
assert u.last_name == 'Johnson' assert u.last_name == 'Johnson'
assert u.is_registered == true assert u.is_registered == true
@ -135,7 +135,7 @@ fn test_encode_decode_time() {
} }
s := json.encode(user) s := json.encode(user)
assert s.contains('"reg_date":1608621780') assert s.contains('"reg_date":1608621780')
user2 := json.decode<User2>(s)! user2 := json.decode[User2](s)!
assert user2.reg_date.str() == '2020-12-22 07:23:00' assert user2.reg_date.str() == '2020-12-22 07:23:00'
} }
@ -150,7 +150,7 @@ struct Country {
//! BUGFIX - .from_json(res) //! BUGFIX - .from_json(res)
fn test_struct_in_struct() { fn test_struct_in_struct() {
country := json.decode<Country>('{ "name": "UK", "cities": [{"name":"London"}, {"name":"Manchester"}]}')! country := json.decode[Country]('{ "name": "UK", "cities": [{"name":"London"}, {"name":"Manchester"}]}')!
assert country.name == 'UK' assert country.name == 'UK'
assert country.cities.len == 2 assert country.cities.len == 2
assert country.cities[0].name == 'London' assert country.cities[0].name == 'London'
@ -165,7 +165,7 @@ fn test_parse_map() {
'three': 3 'three': 3
'four': 4 'four': 4
} }
out := json.decode<map[string]int>('{"one":1,"two":2,"three":3,"four":4}')! out := json.decode[map[string]int]('{"one":1,"two":2,"three":3,"four":4}')!
assert out == expected assert out == expected
} }
@ -224,7 +224,7 @@ fn test_nested_type() {
} }
out := json.encode(data) out := json.encode(data)
assert out == data_expected assert out == data_expected
data2 := json.decode<Data>(data_expected)! data2 := json.decode[Data](data_expected)!
assert data2.countries.len == data.countries.len assert data2.countries.len == data.countries.len
for i in 0 .. 1 { for i in 0 .. 1 {
assert data2.countries[i].name == data.countries[i].name assert data2.countries[i].name == data.countries[i].name
@ -333,7 +333,6 @@ fn test_decode_missing_maps_field() {
assert '${info.maps}' == '{}' assert '${info.maps}' == '{}'
} }
struct Foo3 { struct Foo3 {
name string name string
age int [omitempty] age int [omitempty]