parser: add support for multiple struct field attributes
parent
c29f76454e
commit
5b47ec49af
|
@ -27,10 +27,11 @@ struct User {
|
||||||
last_name string [json:lastName]
|
last_name string [json:lastName]
|
||||||
is_registered bool [json:IsRegistered]
|
is_registered bool [json:IsRegistered]
|
||||||
typ int [json:'type']
|
typ int [json:'type']
|
||||||
|
pets string [raw; json:'pet_animals']
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_parse_user() {
|
fn test_parse_user() {
|
||||||
s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true}'
|
s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}'
|
||||||
u2 := json.decode(User2, s) or {
|
u2 := json.decode(User2, s) or {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
@ -47,11 +48,12 @@ fn test_parse_user() {
|
||||||
assert u.nums[1] == 2
|
assert u.nums[1] == 2
|
||||||
assert u.nums[2] == 3
|
assert u.nums[2] == 3
|
||||||
assert u.typ == 1
|
assert u.typ == 1
|
||||||
|
assert u.pets == '{"name":"Bob","animal":"Dog"}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_user(){
|
fn test_encode_user(){
|
||||||
usr := User{ age: 10, nums: [1,2,3], last_name: 'Johnson', is_registered: true, typ: 0}
|
usr := User{ age: 10, nums: [1,2,3], last_name: 'Johnson', is_registered: true, typ: 0, pets: 'foo'}
|
||||||
expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0}'
|
expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"foo"}'
|
||||||
out := json.encode(usr)
|
out := json.encode(usr)
|
||||||
println(out)
|
println(out)
|
||||||
assert out == expected
|
assert out == expected
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub:
|
||||||
comment Comment
|
comment Comment
|
||||||
default_expr Expr
|
default_expr Expr
|
||||||
has_default_expr bool
|
has_default_expr bool
|
||||||
attr string
|
attrs []string
|
||||||
mut:
|
mut:
|
||||||
typ table.Type
|
typ table.Type
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
vlib/v/checker/tests/multiple_fn_attributes.v:2:1: error: multiple attributes detected
|
||||||
|
1 | [inline;deprecated]
|
||||||
|
2 | fn foo(name string) string {}
|
||||||
|
| ~~
|
|
@ -0,0 +1,2 @@
|
||||||
|
[inline;deprecated]
|
||||||
|
fn foo(name string) string {}
|
|
@ -0,0 +1,6 @@
|
||||||
|
vlib/v/checker/tests/trailing_comma_struct_attr.v:3:31: error: unexpected `]`, expecting `name`
|
||||||
|
1 | struct User {
|
||||||
|
2 | name string
|
||||||
|
3 | jobs []string [json:jobss;]
|
||||||
|
| ^
|
||||||
|
4 | }
|
|
@ -0,0 +1,4 @@
|
||||||
|
struct User {
|
||||||
|
name string
|
||||||
|
jobs []string [json:jobss;]
|
||||||
|
}
|
|
@ -70,13 +70,19 @@ cJSON* ${enc_fn_name}($styp val) {
|
||||||
}
|
}
|
||||||
info := sym.info as table.Struct
|
info := sym.info as table.Struct
|
||||||
for field in info.fields {
|
for field in info.fields {
|
||||||
if field.attr == 'skip' {
|
if 'skip' in field.attrs {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name := if field.attr.starts_with('json:') { field.attr[5..] } else { field.name }
|
mut name := field.name
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.starts_with('json:') {
|
||||||
|
name = attr[5..]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
field_type := g.typ(field.typ)
|
field_type := g.typ(field.typ)
|
||||||
enc_name := js_enc_name(field_type)
|
enc_name := js_enc_name(field_type)
|
||||||
if field.attr == 'raw' {
|
if 'raw' in field.attrs {
|
||||||
dec.writeln(' res . $field.name = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));')
|
dec.writeln(' res . $field.name = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));')
|
||||||
} else {
|
} else {
|
||||||
// Now generate decoders for all field types in this struct
|
// Now generate decoders for all field types in this struct
|
||||||
|
|
|
@ -310,7 +310,12 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.lsbr {
|
.lsbr {
|
||||||
return p.attribute()
|
attrs := p.attributes()
|
||||||
|
|
||||||
|
if attrs.len > 1 {
|
||||||
|
p.error('multiple attributes detected')
|
||||||
|
}
|
||||||
|
return attrs[0]
|
||||||
}
|
}
|
||||||
.key_interface {
|
.key_interface {
|
||||||
return p.interface_decl()
|
return p.interface_decl()
|
||||||
|
@ -481,8 +486,29 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) attribute() ast.Attr {
|
fn (mut p Parser) attributes() []ast.Attr {
|
||||||
|
mut attrs := []ast.Attr{}
|
||||||
|
|
||||||
p.check(.lsbr)
|
p.check(.lsbr)
|
||||||
|
for p.tok.kind != .rsbr {
|
||||||
|
attr := p.parse_attr()
|
||||||
|
attrs << attr
|
||||||
|
if p.tok.kind != .semicolon {
|
||||||
|
expected := `;`
|
||||||
|
if p.tok.kind == .rsbr {
|
||||||
|
p.next()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
p.error('unexpected `${p.tok.kind.str()}`, expecting `${expected.str()}`')
|
||||||
|
}
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) parse_attr() ast.Attr {
|
||||||
mut is_if_attr := false
|
mut is_if_attr := false
|
||||||
if p.tok.kind == .key_if {
|
if p.tok.kind == .key_if {
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -499,7 +525,6 @@ fn (mut p Parser) attribute() ast.Attr {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.check(.rsbr)
|
|
||||||
p.attr = name
|
p.attr = name
|
||||||
if is_if_attr {
|
if is_if_attr {
|
||||||
p.attr_ctdefine = name
|
p.attr_ctdefine = name
|
||||||
|
|
|
@ -117,9 +117,12 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
}
|
}
|
||||||
has_default_expr = true
|
has_default_expr = true
|
||||||
}
|
}
|
||||||
mut attr := ast.Attr{}
|
mut attrs := []string{}
|
||||||
if p.tok.kind == .lsbr {
|
if p.tok.kind == .lsbr {
|
||||||
attr = p.attribute()
|
parsed_attrs := p.attributes()
|
||||||
|
for attr in parsed_attrs {
|
||||||
|
attrs << attr.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if p.tok.kind == .comment {
|
if p.tok.kind == .comment {
|
||||||
comment = p.comment()
|
comment = p.comment()
|
||||||
|
@ -132,7 +135,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
comment: comment
|
comment: comment
|
||||||
default_expr: default_expr
|
default_expr: default_expr
|
||||||
has_default_expr: has_default_expr
|
has_default_expr: has_default_expr
|
||||||
attr: attr.name
|
attrs: attrs
|
||||||
}
|
}
|
||||||
fields << table.Field{
|
fields << table.Field{
|
||||||
name: field_name
|
name: field_name
|
||||||
|
@ -142,7 +145,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
is_pub: is_field_pub
|
is_pub: is_field_pub
|
||||||
is_mut: is_field_mut
|
is_mut: is_field_mut
|
||||||
is_global: is_field_global
|
is_global: is_field_global
|
||||||
attr: attr.name
|
attrs: attrs
|
||||||
}
|
}
|
||||||
// println('struct field $ti.name $field_name')
|
// println('struct field $ti.name $field_name')
|
||||||
}
|
}
|
||||||
|
|
|
@ -564,7 +564,7 @@ mut:
|
||||||
default_expr FExpr
|
default_expr FExpr
|
||||||
has_default_expr bool
|
has_default_expr bool
|
||||||
default_val string
|
default_val string
|
||||||
attr string
|
attrs []string
|
||||||
is_pub bool
|
is_pub bool
|
||||||
is_mut bool
|
is_mut bool
|
||||||
is_global bool
|
is_global bool
|
||||||
|
|
Loading…
Reference in New Issue