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: pub:
name string name string
value i64 value i64
attrs []string
} }
// FieldData holds information about a field. Fields reside on structs. // 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 comments []Comment // comment after Enumfield in the same line
next_comments []Comment // comments between current EnumField and next EnumField next_comments []Comment // comments between current EnumField and next EnumField
has_expr bool // true, when .expr has a value has_expr bool // true, when .expr has a value
attrs []Attr
pub mut: pub mut:
expr Expr // the value of current EnumField; 123 in `ename = 123` 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}'" return "'${x.val}'"
} }
TypeNode { TypeNode {
return 'TypeNode(${x.typ})' return 'TypeNode(${global_table.type_str(x.typ)})'
} }
TypeOf { TypeOf {
if x.is_type { if x.is_type {

View File

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

View File

@ -986,6 +986,10 @@ pub fn (mut f Fmt) enum_decl(node ast.EnumDecl) {
f.write(' = ') f.write(' = ')
f.expr(field.expr) 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.comments(field.comments, inline: true, has_nl: false, level: .indent)
f.writeln('') f.writeln('')
f.comments(field.next_comments, inline: false, has_nl: true, level: .indent) 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 { } else {
g.writeln('${g.typ(g.comptime_for_field_type)}__${g.comptime_enum_field_value};') 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.stmts(node.stmts)
g.writeln('}') g.writeln('}')
i++ 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}) {') enc.writeln('${ident}switch (${enum_var}) {')
for val in (sym.info as ast.Enum).vals { for val in (sym.info as ast.Enum).vals {
enc.write_string('${ident}\tcase ${enum_prefix}${val}:\t') 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}}') 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)) enum_prefix := g.gen_enum_prefix(utyp.clear_flag(.option))
is_option := utyp.has_flag(.option) is_option := utyp.has_flag(.option)
for k, val in (sym.info as ast.Enum).vals { for k, val in (sym.info as ast.Enum).vals {
if k == 0 { // read [json:] attr from the Enum value
dec.write_string('${ident}if (string__eq(_SLIT("${val}"), ${val_var}))\t') attr := g.table.enum_decls[sym.name].fields.filter(it.name == val)[0].attrs.find_first('json') or {
} else { ast.Attr{}
dec.write_string('${ident}else if (string__eq(_SLIT("${val}"), ${val_var}))\t')
} }
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 { if is_option {
base_typ := g.base_type(utyp) base_typ := g.base_type(utyp)
dec.writeln('_option_ok(&(${base_typ}[]){ ${enum_prefix}${val} }, ${result_var}, sizeof(${base_typ}));') 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 default_exprs := []ast.Expr{}
mut fields := []ast.EnumField{} mut fields := []ast.EnumField{}
mut uses_exprs := false mut uses_exprs := false
mut enum_attrs := map[string][]ast.Attr{}
for p.tok.kind != .eof && p.tok.kind != .rcbr { for p.tok.kind != .eof && p.tok.kind != .rcbr {
pos := p.tok.pos() pos := p.tok.pos()
val := p.check_name() val := p.check_name()
@ -3935,6 +3936,13 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
has_expr = true has_expr = true
uses_exprs = 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{ fields << ast.EnumField{
name: val name: val
pos: pos pos: pos
@ -3942,6 +3950,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
has_expr: has_expr has_expr: has_expr
comments: p.eat_comments(same_line: true) comments: p.eat_comments(same_line: true)
next_comments: p.eat_comments() next_comments: p.eat_comments()
attrs: attrs
} }
} }
p.top_level_statement_end() p.top_level_statement_end()
@ -3983,6 +3992,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
is_multi_allowed: is_multi_allowed is_multi_allowed: is_multi_allowed
uses_exprs: uses_exprs uses_exprs: uses_exprs
typ: enum_type typ: enum_type
attrs: enum_attrs
} }
is_pub: is_pub 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"}')!)
}