Skip to content

Commit ac27a3c

Browse files
committed
parser,cgen: improve [flag]enum Abc{ a b }, allow x := Abc.a | Abc.b
1 parent 18cf36a commit ac27a3c

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

vlib/v/gen/cgen.v

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,10 +829,11 @@ fn (mut g Gen) stmt(node ast.Stmt) {
829829
}
830830
ast.EnumDecl {
831831
enum_name := util.no_dots(node.name)
832+
is_flag := node.is_flag
832833
g.enum_typedefs.writeln('typedef enum {')
833834
mut cur_enum_expr := ''
834835
mut cur_enum_offset := 0
835-
for field in node.fields {
836+
for i, field in node.fields {
836837
g.enum_typedefs.write('\t${enum_name}_$field.name')
837838
if field.has_expr {
838839
g.enum_typedefs.write(' = ')
@@ -843,6 +844,11 @@ fn (mut g Gen) stmt(node ast.Stmt) {
843844
g.enum_typedefs.write(expr_str)
844845
cur_enum_expr = expr_str
845846
cur_enum_offset = 0
847+
} else if is_flag {
848+
g.enum_typedefs.write(' = ')
849+
cur_enum_expr = '1 << $i'
850+
g.enum_typedefs.write((1 << i).str())
851+
cur_enum_offset = 0
846852
}
847853
cur_value := if cur_enum_offset > 0 { '$cur_enum_expr+$cur_enum_offset' } else { cur_enum_expr }
848854
g.enum_typedefs.writeln(', // $cur_value')

vlib/v/parser/parser.v

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,13 +1869,19 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
18691869
if fields.len > 32 {
18701870
p.error('when an enum is used as bit field, it must have a max of 32 fields')
18711871
}
1872+
for f in fields {
1873+
if f.has_expr {
1874+
p.error_with_pos('when an enum is used as a bit field, you can not assign custom values',
1875+
f.pos)
1876+
}
1877+
}
18721878
pubfn := if p.mod == 'main' { 'fn' } else { 'pub fn' }
18731879
p.scanner.codegen('
18741880
//
1875-
$pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (1 << int(flag))) != 0 }
1876-
$pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = int(*e) | (1 << int(flag)) } }
1877-
$pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = int(*e) & ~(1 << int(flag)) } }
1878-
$pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = int(*e) ^ (1 << int(flag)) } }
1881+
$pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (int(flag))) != 0 }
1882+
$pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = int(*e) | (int(flag)) } }
1883+
$pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = int(*e) & ~(int(flag)) } }
1884+
$pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = int(*e) ^ (int(flag)) } }
18791885
//
18801886
')
18811887
}

vlib/v/tests/enum_bitfield_test.v

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ mut:
1313

1414
fn test_enum_bitfield() {
1515
mut a := BfFile{}
16+
assert 1 == int(BfPermission.read)
17+
assert 2 == int(BfPermission.write)
18+
assert 4 == int(BfPermission.execute)
19+
assert 8 == int(BfPermission.other)
1620
a.perm.set(.read)
1721
a.perm.set(.write)
1822
a.perm.toggle(.execute)
@@ -22,11 +26,20 @@ fn test_enum_bitfield() {
2226
assert a.perm.has(.execute)
2327
assert !a.perm.has(.write)
2428
assert !a.perm.has(.other)
25-
mut b := BfPermission.read // TODO: this does nothing currenty just sets the type
29+
mut b := BfPermission.read | BfPermission.execute
30+
assert int(b) == 1 + 0 + 4 + 0
31+
assert b.has(.read)
32+
assert b.has(.execute)
2633
b.set(.write)
34+
assert int(b) == 1 + 2 + 4 + 0
2735
b.set(.other)
36+
assert int(b) == 1 + 2 + 4 + 8
2837
assert b.has(.write)
2938
assert b.has(.other)
39+
b.toggle(.read)
40+
assert int(b) == 0 + 2 + 4 + 8
41+
b.toggle(.execute)
42+
assert int(b) == 0 + 2 + 0 + 8
3043
assert !b.has(.read)
3144
assert !b.has(.execute)
3245
}

0 commit comments

Comments
 (0)