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

all: attr for enum fields (+ json encode/decode) (#18163)

This commit is contained in:
Felipe Pena 2023-05-12 20:08:30 -03:00 committed by GitHub
parent 8482bc4626
commit 47761a42e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 85 additions and 6 deletions

View File

@ -111,6 +111,7 @@ pub struct EnumData {
pub:
name string
value i64
attrs []string
}
// FieldData holds information about a field. Fields reside on structs.

View File

@ -1296,6 +1296,7 @@ pub:
comments []Comment // comment after Enumfield in the same line
next_comments []Comment // comments between current EnumField and next EnumField
has_expr bool // true, when .expr has a value
attrs []Attr
pub mut:
expr Expr // the value of current EnumField; 123 in `ename = 123`
}

View File

@ -512,7 +512,7 @@ pub fn (x Expr) str() string {
return "'${x.val}'"
}
TypeNode {
return 'TypeNode(${x.typ})'
return 'TypeNode(${global_table.type_str(x.typ)})'
}
TypeOf {
if x.is_type {

View File

@ -193,6 +193,7 @@ pub:
is_multi_allowed bool
uses_exprs bool
typ Type
attrs map[string][]Attr
}
[minify]

View File

@ -986,6 +986,10 @@ pub fn (mut f Fmt) enum_decl(node ast.EnumDecl) {
f.write(' = ')
f.expr(field.expr)
}
if field.attrs.len > 0 {
f.write(' ')
f.single_line_attrs(field.attrs, inline: true)
}
f.comments(field.comments, inline: true, has_nl: false, level: .indent)
f.writeln('')
f.comments(field.next_comments, inline: false, has_nl: true, level: .indent)

View File

@ -942,6 +942,15 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
} else {
g.writeln('${g.typ(g.comptime_for_field_type)}__${g.comptime_enum_field_value};')
}
enum_attrs := sym.info.attrs[val]
if enum_attrs.len == 0 {
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
} else {
attrs := cgen_attrs(enum_attrs)
g.writeln(
'\t${node.val_var}.attrs = new_array_from_c_array(${attrs.len}, ${attrs.len}, sizeof(string), _MOV((string[${attrs.len}]){' +
attrs.join(', ') + '}));\n')
}
g.stmts(node.stmts)
g.writeln('}')
i++

View File

@ -205,7 +205,15 @@ fn (mut g Gen) gen_enum_to_str(utyp ast.Type, sym ast.TypeSymbol, enum_var strin
enc.writeln('${ident}switch (${enum_var}) {')
for val in (sym.info as ast.Enum).vals {
enc.write_string('${ident}\tcase ${enum_prefix}${val}:\t')
enc.writeln('${result_var} = json__encode_string(_SLIT("${val}")); break;')
// read [json:] attr from the Enum value
attr := g.table.enum_decls[sym.name].fields.filter(it.name == val)[0].attrs.find_first('json') or {
ast.Attr{}
}
if attr.has_arg {
enc.writeln('${result_var} = json__encode_string(_SLIT("${attr.arg}")); break;')
} else {
enc.writeln('${result_var} = json__encode_string(_SLIT("${val}")); break;')
}
}
enc.writeln('${ident}}')
}
@ -215,11 +223,19 @@ fn (mut g Gen) gen_str_to_enum(utyp ast.Type, sym ast.TypeSymbol, val_var string
enum_prefix := g.gen_enum_prefix(utyp.clear_flag(.option))
is_option := utyp.has_flag(.option)
for k, val in (sym.info as ast.Enum).vals {
if k == 0 {
dec.write_string('${ident}if (string__eq(_SLIT("${val}"), ${val_var}))\t')
} else {
dec.write_string('${ident}else if (string__eq(_SLIT("${val}"), ${val_var}))\t')
// read [json:] attr from the Enum value
attr := g.table.enum_decls[sym.name].fields.filter(it.name == val)[0].attrs.find_first('json') or {
ast.Attr{}
}
if k == 0 {
dec.write_string('${ident}if (string__eq(_SLIT("${val}"), ${val_var})')
} else {
dec.write_string('${ident}else if (string__eq(_SLIT("${val}"), ${val_var})')
}
if attr.has_arg {
dec.write_string(' || string__eq(_SLIT("${attr.arg}"), ${val_var})')
}
dec.write_string(')\t')
if is_option {
base_typ := g.base_type(utyp)
dec.writeln('_option_ok(&(${base_typ}[]){ ${enum_prefix}${val} }, ${result_var}, sizeof(${base_typ}));')

View File

@ -3922,6 +3922,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
// mut default_exprs := []ast.Expr{}
mut fields := []ast.EnumField{}
mut uses_exprs := false
mut enum_attrs := map[string][]ast.Attr{}
for p.tok.kind != .eof && p.tok.kind != .rcbr {
pos := p.tok.pos()
val := p.check_name()
@ -3935,6 +3936,13 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
has_expr = true
uses_exprs = true
}
mut attrs := []ast.Attr{}
if p.tok.kind == .lsbr {
p.attributes()
attrs << p.attrs
enum_attrs[val] = attrs
p.attrs = []
}
fields << ast.EnumField{
name: val
pos: pos
@ -3942,6 +3950,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
has_expr: has_expr
comments: p.eat_comments(same_line: true)
next_comments: p.eat_comments()
attrs: attrs
}
}
p.top_level_statement_end()
@ -3983,6 +3992,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
is_multi_allowed: is_multi_allowed
uses_exprs: uses_exprs
typ: enum_type
attrs: enum_attrs
}
is_pub: is_pub
})

View File

@ -0,0 +1,37 @@
import json
enum Foo {
yay [json: 'A'; yay]
foo [foo; json: 'B']
}
struct FooStruct {
item Foo
}
fn test_comptime() {
$for f in Foo.values {
println(f)
if f.value == Foo.yay {
assert f.attrs[0] == 'json: A'
assert f.attrs[1] == 'yay'
}
if f.value == Foo.foo {
assert f.attrs[1] == 'json: B'
assert f.attrs[0] == 'foo'
}
}
}
fn test_json_encode() {
assert dump(json.encode(Foo.yay)) == '"A"'
assert dump(json.encode(Foo.foo)) == '"B"'
assert dump(json.encode(FooStruct{ item: Foo.yay })) == '{"item":"A"}'
assert dump(json.encode(FooStruct{ item: Foo.foo })) == '{"item":"B"}'
}
fn test_json_decode() {
dump(json.decode(FooStruct, '{"item": "A"}')!)
dump(json.decode(FooStruct, '{"item": "B"}')!)
}