diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 4dfc4013b0..3f419c5ac5 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -829,10 +829,11 @@ fn (mut g Gen) stmt(node ast.Stmt) { } ast.EnumDecl { enum_name := util.no_dots(node.name) + is_flag := node.is_flag g.enum_typedefs.writeln('typedef enum {') mut cur_enum_expr := '' mut cur_enum_offset := 0 - for field in node.fields { + for i, field in node.fields { g.enum_typedefs.write('\t${enum_name}_$field.name') if field.has_expr { g.enum_typedefs.write(' = ') @@ -843,6 +844,11 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.enum_typedefs.write(expr_str) cur_enum_expr = expr_str cur_enum_offset = 0 + } else if is_flag { + g.enum_typedefs.write(' = ') + cur_enum_expr = '1 << $i' + g.enum_typedefs.write((1 << i).str()) + cur_enum_offset = 0 } cur_value := if cur_enum_offset > 0 { '$cur_enum_expr+$cur_enum_offset' } else { cur_enum_expr } g.enum_typedefs.writeln(', // $cur_value') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 67ddfaa4f0..c05f8a7ba9 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1869,13 +1869,19 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { if fields.len > 32 { p.error('when an enum is used as bit field, it must have a max of 32 fields') } + for f in fields { + if f.has_expr { + p.error_with_pos('when an enum is used as a bit field, you can not assign custom values', + f.pos) + } + } pubfn := if p.mod == 'main' { 'fn' } else { 'pub fn' } p.scanner.codegen(' // -$pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (1 << int(flag))) != 0 } -$pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = int(*e) | (1 << int(flag)) } } -$pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = int(*e) & ~(1 << int(flag)) } } -$pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = int(*e) ^ (1 << int(flag)) } } +$pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (int(flag))) != 0 } +$pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = int(*e) | (int(flag)) } } +$pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = int(*e) & ~(int(flag)) } } +$pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = int(*e) ^ (int(flag)) } } // ') } diff --git a/vlib/v/tests/enum_bitfield_test.v b/vlib/v/tests/enum_bitfield_test.v index cf07b9a306..34af9c5298 100644 --- a/vlib/v/tests/enum_bitfield_test.v +++ b/vlib/v/tests/enum_bitfield_test.v @@ -13,6 +13,10 @@ mut: fn test_enum_bitfield() { mut a := BfFile{} + assert 1 == int(BfPermission.read) + assert 2 == int(BfPermission.write) + assert 4 == int(BfPermission.execute) + assert 8 == int(BfPermission.other) a.perm.set(.read) a.perm.set(.write) a.perm.toggle(.execute) @@ -22,11 +26,20 @@ fn test_enum_bitfield() { assert a.perm.has(.execute) assert !a.perm.has(.write) assert !a.perm.has(.other) - mut b := BfPermission.read // TODO: this does nothing currenty just sets the type + mut b := BfPermission.read | BfPermission.execute + assert int(b) == 1 + 0 + 4 + 0 + assert b.has(.read) + assert b.has(.execute) b.set(.write) + assert int(b) == 1 + 2 + 4 + 0 b.set(.other) + assert int(b) == 1 + 2 + 4 + 8 assert b.has(.write) assert b.has(.other) + b.toggle(.read) + assert int(b) == 0 + 2 + 4 + 8 + b.toggle(.execute) + assert int(b) == 0 + 2 + 0 + 8 assert !b.has(.read) assert !b.has(.execute) }