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)
|
||||
}
|
||||
} 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
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
one = 1
|
||||
}
|
||||
|
||||
struct TestStruct {
|
||||
test TestEnum
|
||||
}
|
||||
|
||||
fn comptime_field_selector_read[T]() []string {
|
||||
mut t := T{}
|
||||
t.name = '2'
|
||||
@ -42,6 +50,15 @@ fn test_comptime_field_selector_write() {
|
||||
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 {
|
||||
f Foo
|
||||
}
|
||||
|
@ -63,6 +63,12 @@ fn test_types() {
|
||||
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() {
|
||||
|
@ -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)!
|
||||
} $else $if field.is_array {
|
||||
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 {
|
||||
match field.unaliased_typ {
|
||||
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)!
|
||||
} $else $if field.is_struct {
|
||||
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 {
|
||||
match field.unaliased_typ {
|
||||
typeof[string]().idx {
|
||||
|
@ -51,6 +51,13 @@ pub fn decode[T](src string) !T {
|
||||
typ.$(field.name) = res[field.name]!.str()
|
||||
} $else $if field.typ is time.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 {
|
||||
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 {
|
||||
pub mut:
|
||||
name string
|
||||
age int
|
||||
salary f32
|
||||
// title JobTitle //! FIXME - decode
|
||||
// sub_employee SubEmployee //! FIXME - decode
|
||||
name string
|
||||
age int
|
||||
salary f32
|
||||
title JobTitle
|
||||
sub_employee SubEmployee //! FIXME - decode
|
||||
}
|
||||
|
||||
struct SubEmployee {
|
||||
pub struct SubEmployee {
|
||||
pub mut:
|
||||
name string
|
||||
age int
|
||||
salary f32
|
||||
// title JobTitle //! FIXME - decode
|
||||
title JobTitle
|
||||
}
|
||||
|
||||
fn test_simple() {
|
||||
sub_employee := SubEmployee{
|
||||
name: 'João'
|
||||
}
|
||||
x := Employee{'Peter', 28, 95000.5}
|
||||
x := Employee{'Peter', 28, 95000.5, .worker, sub_employee}
|
||||
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 {
|
||||
println(err)
|
||||
@ -40,10 +40,10 @@ fn test_simple() {
|
||||
assert y.name == 'Peter'
|
||||
assert y.age == 28
|
||||
assert y.salary == 95000.5
|
||||
// assert y.title == .worker //! FIXME
|
||||
// assert y.sub_employee.name == 'Peter'
|
||||
// assert y.sub_employee.age == 0
|
||||
// assert y.sub_employee.salary == 0.0
|
||||
assert y.title == .worker
|
||||
// assert y.sub_employee.name == 'João'
|
||||
assert y.sub_employee.age == 0
|
||||
assert y.sub_employee.salary == 0.0
|
||||
// assert y.sub_employee.title == .worker //! FIXME
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ pub struct Price {
|
||||
//! BUGFIX
|
||||
fn test_field_with_default_expr() {
|
||||
data := '[{"net":1},{"net":2,"currencyId":"cjson"}]'
|
||||
prices := json.decode<[]Price>(data)!
|
||||
prices := json.decode[[]Price](data)!
|
||||
assert prices == [Price{
|
||||
net: 1
|
||||
currency_id: 'cconst'
|
||||
@ -38,7 +38,7 @@ fn test_field_with_default_expr() {
|
||||
//! BUGFIX - .from_json(res)
|
||||
fn test_decode_top_level_array() {
|
||||
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[0].name == 'Peter'
|
||||
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()}}]}'
|
||||
|
||||
dec := json.decode<SomeGame>(enc)!
|
||||
dec := json.decode[SomeGame](enc)!
|
||||
|
||||
assert game.title == dec.title
|
||||
assert game.player == dec.player
|
||||
@ -114,8 +114,8 @@ pub mut:
|
||||
|
||||
fn test_parse_user() {
|
||||
s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}'
|
||||
u2 := json.decode<User2>(s)!
|
||||
u := json.decode<User>(s)!
|
||||
u2 := json.decode[User2](s)!
|
||||
u := json.decode[User](s)!
|
||||
assert u.age == 10
|
||||
assert u.last_name == 'Johnson'
|
||||
assert u.is_registered == true
|
||||
@ -135,7 +135,7 @@ fn test_encode_decode_time() {
|
||||
}
|
||||
s := json.encode(user)
|
||||
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'
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ struct Country {
|
||||
|
||||
//! BUGFIX - .from_json(res)
|
||||
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.cities.len == 2
|
||||
assert country.cities[0].name == 'London'
|
||||
@ -165,7 +165,7 @@ fn test_parse_map() {
|
||||
'three': 3
|
||||
'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
|
||||
}
|
||||
|
||||
@ -224,7 +224,7 @@ fn test_nested_type() {
|
||||
}
|
||||
out := json.encode(data)
|
||||
assert out == data_expected
|
||||
data2 := json.decode<Data>(data_expected)!
|
||||
data2 := json.decode[Data](data_expected)!
|
||||
assert data2.countries.len == data.countries.len
|
||||
for i in 0 .. 1 {
|
||||
assert data2.countries[i].name == data.countries[i].name
|
||||
@ -333,7 +333,6 @@ fn test_decode_missing_maps_field() {
|
||||
assert '${info.maps}' == '{}'
|
||||
}
|
||||
|
||||
|
||||
struct Foo3 {
|
||||
name string
|
||||
age int [omitempty]
|
||||
|
Loading…
Reference in New Issue
Block a user