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:
parent
09f48455c5
commit
d1306ffcf5
@ -593,7 +593,16 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.error('cannot assign to `${left}`: ${err.msg()}', right.pos())
|
// 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 {
|
||||||
|
c.error('cannot assign to `${left}`: ${err.msg()}', right.pos())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
vlib/v/checker/tests/assign_enum_at_comptime.out
Normal file
7
vlib/v/checker/tests/assign_enum_at_comptime.out
Normal 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 | }
|
15
vlib/v/checker/tests/assign_enum_at_comptime.vv
Normal file
15
vlib/v/checker/tests/assign_enum_at_comptime.vv
Normal 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'
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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 {
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -9,28 +9,28 @@ enum JobTitle {
|
|||||||
|
|
||||||
struct Employee {
|
struct Employee {
|
||||||
pub mut:
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
Loading…
Reference in New Issue
Block a user