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

@ -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())
}
}
}
}

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
}
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
}

View File

@ -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() {

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)!
} $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 {

View File

@ -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")
}

View File

@ -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
}

View File

@ -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]