From 7488dd829d12fca437767e4d920c88164d1ab4b2 Mon Sep 17 00:00:00 2001 From: Emily Hudson Date: Fri, 10 Jul 2020 15:43:02 +0100 Subject: [PATCH] all: _allow_multiple_values enum attribute (#5772) --- vlib/v/ast/ast.v | 13 +++++++------ vlib/v/checker/checker.v | 2 +- vlib/v/gen/cgen.v | 7 +++++++ vlib/v/parser/parser.v | 3 +++ vlib/v/table/atypes.v | 1 + 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 3b069979e1..3120167c8d 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -623,12 +623,13 @@ pub: pub struct EnumDecl { pub: - name string - is_pub bool - is_flag bool // true when the enum has [flag] tag - comments []Comment // enum Abc { /* comments */ ... } - fields []EnumField - pos token.Position + name string + is_pub bool + is_flag bool // true when the enum has [flag] tag + is_multi_allowed bool + comments []Comment // enum Abc { /* comments */ ... } + fields []EnumField + pos token.Position } pub struct AliasTypeDecl { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 980f7e7b0b..9fb0fb24e7 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1467,7 +1467,7 @@ pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) { val := field_expr.val.i64() if val < enum_min || val > enum_max { c.error('enum value `$val` overflows int', field_expr.pos) - } else if int(val) in seen { + } else if !decl.is_multi_allowed && int(val) in seen { c.error('enum value `$val` already exists', field_expr.pos) } seen << int(val) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index eaf94d5b22..2605f8d897 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -4120,7 +4120,14 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) { g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto') g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */') g.auto_str_funcs.writeln('\tswitch(it) {') + // Only use the first multi value on the lookup + mut seen := []string{len:info.vals.len} for val in info.vals { + if info.is_multi_allowed && val in seen { + continue + } else if info.is_multi_allowed { + seen << val + } g.auto_str_funcs.writeln('\t\tcase ${s}_$val: return tos_lit("$val");') } g.auto_str_funcs.writeln('\t\tdefault: return tos_lit("unknown enum value");') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index c30fe1e745..56610aeec9 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1503,6 +1503,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { p.top_level_statement_end() p.check(.rcbr) is_flag := 'flag' in p.attrs + is_multi_allowed := '_allow_multiple_values' in p.attrs if is_flag { if fields.len > 32 { p.error('when an enum is used as bit field, it must have a max of 32 fields') @@ -1524,12 +1525,14 @@ $pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = int(*e) ^ ( info: table.Enum{ vals: vals is_flag: is_flag + is_multi_allowed: is_multi_allowed } }) return ast.EnumDecl{ name: name is_pub: is_pub is_flag: is_flag + is_multi_allowed: is_multi_allowed fields: fields pos: start_pos.extend(end_pos) comments: enum_decl_comments diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index adbbe745a7..6b70dbca50 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -683,6 +683,7 @@ pub struct Enum { pub: vals []string is_flag bool + is_multi_allowed bool } pub struct Alias {