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

all: add support for enum Xyz as u64 { + tests (#16246)

This commit is contained in:
Delyan Angelov 2022-10-29 06:32:20 +03:00 committed by GitHub
parent 4564a47fbc
commit 02c3af2432
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 567 additions and 54 deletions

View File

@ -3237,7 +3237,7 @@ You can see the complete
### Enums
```v
enum Color {
enum Color as u8 {
red
green
blue
@ -3254,6 +3254,8 @@ match color {
}
```
The enum type can be any integer type, but can be ommited, if it is `int`: `enum Color {`.
Enum match must be exhaustive or have an `else` branch.
This ensures that if a new enum field is added, it's handled everywhere in the code.

View File

@ -205,7 +205,7 @@ if exist "%InstallDir%\Common7\Tools\vsdevcmd.bat" (
set ObjFile=.v.c.obj
echo ^> Attempting to build v_win.c with MSVC
cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
cl.exe /volatile:ms /Fo%ObjFile% /W0 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
if %ERRORLEVEL% NEQ 0 (
echo In some cases, compile errors happen because of the MSVC compiler version
cl.exe

View File

@ -118,7 +118,7 @@ pub enum ImageType {
_num
}
pub enum CubeFace {
pub enum CubeFace as u32 {
pos_x
neg_x
pos_y

View File

@ -1164,6 +1164,7 @@ pub:
comments []Comment // comments before the first EnumField
fields []EnumField // all the enum fields
attrs []Attr // attributes of enum declaration
typ Type // the default is `int`; can be changed by `enum Big as u64 { a = 5 }`
pos token.Pos
}

View File

@ -1401,7 +1401,9 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
c.check_valid_pascal_case(node.name, 'enum name', node.pos)
mut seen := []i64{cap: node.fields.len}
mut useen := []u64{}
mut iseen := []i64{}
mut seen_enum_field_names := map[string]int{}
if node.fields.len == 0 {
c.error('enum cannot be empty', node.pos)
}
@ -1410,35 +1412,114 @@ pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
c.error('`builtin` module cannot have enums', node.pos)
}
*/
mut enum_imin := i64(0)
mut enum_imax := i64(0)
mut enum_umin := u64(0)
mut enum_umax := u64(0)
mut signed := true
senum_type := c.table.type_to_str(node.typ)
match node.typ {
ast.i8_type {
signed, enum_imin, enum_imax = true, -128, 0x7F
}
ast.i16_type {
signed, enum_imin, enum_imax = true, -32_768, 0x7FFF
}
ast.int_type {
signed, enum_imin, enum_imax = true, -2_147_483_648, 0x7FFF_FFFF
}
ast.i64_type {
signed, enum_imin, enum_imax = true, i64(-9223372036854775807 - 1), i64(0x7FFF_FFFF_FFFF_FFFF)
}
//
ast.u8_type {
signed, enum_umin, enum_umax = false, 0, 0xFF
}
ast.u16_type {
signed, enum_umin, enum_umax = false, 0, 0xFFFF
}
ast.u32_type {
signed, enum_umin, enum_umax = false, 0, 0xFFFF_FFFF
}
ast.u64_type {
signed, enum_umin, enum_umax = false, 0, 0xFFFF_FFFF_FFFF_FFFF
}
else {
c.error('`$senum_type` is not one of `i8`,`i16`,`int`,`i64`,`u8`,`u16`,`u32`,`u64`',
node.pos)
}
}
if enum_imin > 0 {
// ensure that the minimum value is negative, even with msvc, which has a bug that makes -2147483648 positive ...
enum_imin *= -1
}
for i, mut field in node.fields {
if !c.pref.experimental && util.contains_capital(field.name) {
// TODO C2V uses hundreds of enums with capitals, remove -experimental check once it's handled
c.error('field name `$field.name` cannot contain uppercase letters, use snake_case instead',
field.pos)
}
for j in 0 .. i {
if field.name == node.fields[j].name {
c.error('field name `$field.name` duplicate', field.pos)
}
if _ := seen_enum_field_names[field.name] {
c.error('duplicate enum field name `$field.name`', field.pos)
}
seen_enum_field_names[field.name] = i
if field.has_expr {
match mut field.expr {
ast.IntegerLiteral {
val := field.expr.val.i64()
if val < checker.int_min || val > checker.int_max {
c.error('enum value `$val` overflows int', field.expr.pos)
} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed
&& i64(val) in seen {
c.error('enum value `$val` already exists', field.expr.pos)
mut overflows := false
mut uval := u64(0)
mut ival := i64(0)
if signed {
val := field.expr.val.i64()
ival = val
if val < enum_imin || val >= enum_imax {
c.error('enum value `$field.expr.val` overflows the enum type `$senum_type`, values of which have to be in [$enum_imin, $enum_imax]',
field.expr.pos)
overflows = true
}
} else {
val := field.expr.val.u64()
uval = val
if val >= enum_umax {
c.error('enum value `$field.expr.val` overflows the enum type `$senum_type`, values of which have to be in [$enum_umin, $enum_umax]',
field.expr.pos)
overflows = true
}
}
if !overflows && !c.pref.translated && !c.file.is_translated
&& !node.is_multi_allowed {
if (signed && ival in iseen) || (!signed && uval in useen) {
c.error('enum value `$field.expr.val` already exists', field.expr.pos)
}
}
if signed {
iseen << ival
} else {
useen << uval
}
seen << i64(val)
}
ast.PrefixExpr {}
ast.PrefixExpr {
dump(field.expr)
}
ast.InfixExpr {
// Handle `enum Foo { x = 1 + 2 }`
c.infix_expr(mut field.expr)
}
// ast.ParExpr {} // TODO allow `.x = (1+2)`
ast.ParExpr {
c.expr(field.expr)
}
ast.CastExpr {
fe_type := c.cast_expr(mut field.expr)
if node.typ != fe_type {
sfe_type := c.table.type_to_str(fe_type)
c.error('the type of the enum value `$sfe_type` != the enum type itself `$senum_type`',
field.expr.pos)
}
if !fe_type.is_pure_int() {
c.error('the type of an enum value must be an integer type, like i8, u8, int, u64 etc.',
field.expr.pos)
}
}
else {
if mut field.expr is ast.Ident {
if field.expr.language == .c {
@ -1449,21 +1530,38 @@ pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
if pos.pos == 0 {
pos = field.pos
}
c.error('default value for enum has to be an integer', pos)
c.error('the default value for an enum has to be an integer', pos)
}
}
} else {
if seen.len > 0 {
last := seen[seen.len - 1]
if last == checker.int_max {
c.error('enum value overflows', field.pos)
} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed
&& last + 1 in seen {
c.error('enum value `${last + 1}` already exists', field.pos)
if signed {
if iseen.len > 0 {
ilast := iseen[iseen.len - 1]
if ilast == enum_imax {
c.error('enum value overflows type `$senum_type`, which has a maximum value of $enum_imax',
field.pos)
} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed
&& ilast + 1 in iseen {
c.error('enum value `${ilast + 1}` already exists', field.pos)
}
iseen << ilast + 1
} else {
iseen << 0
}
seen << last + 1
} else {
seen << 0
if useen.len > 0 {
ulast := useen[useen.len - 1]
if ulast == enum_umax {
c.error('enum value overflows type `$senum_type`, which has a maximum value of $enum_umax',
field.pos)
} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed
&& ulast + 1 in useen {
c.error('enum value `${ulast + 1}` already exists', field.pos)
}
useen << ulast + 1
} else {
useen << 0
}
}
}
}
@ -2637,21 +2735,25 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
if to_sym.kind == .enum_ {
if mut node.expr is ast.IntegerLiteral {
enum_typ_name := c.table.get_type_name(to_type)
node_val := node.expr.val.int()
node_val := node.expr.val.i64()
if enum_decl := c.table.enum_decls[to_sym.name] {
mut in_range := false
if enum_decl.is_flag {
// if a flag enum has 4 variants, the maximum possible value would have all 4 flags set (0b1111)
max_val := (1 << enum_decl.fields.len) - 1
in_range = node_val >= 0 && node_val <= max_val
max_val := (u64(1) << enum_decl.fields.len) - 1
in_range = node_val >= 0 && u64(node_val) <= max_val
} else {
mut enum_val := 0
mut enum_val := i64(0)
for enum_field in enum_decl.fields {
// check if the field of the enum value is an integer literal
if enum_field.expr is ast.IntegerLiteral {
enum_val = enum_field.expr.val.int()
enum_val = enum_field.expr.val.i64()
} else if comptime_value := c.eval_comptime_const_expr(enum_field.expr,
0)
{
enum_val = comptime_value.i64() or { -1 }
}
if node_val == enum_val {
in_range = true

View File

@ -1,5 +1,5 @@
vlib/v/checker/tests/enum_err.vv:4:13: error: default value for enum has to be an integer
2 |
vlib/v/checker/tests/enum_err.vv:4:13: error: the default value for an enum has to be an integer
2 |
3 | enum Color {
4 | green = 'green'
| ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/enum_field_name_duplicate_err.vv:5:2: error: field name `green` duplicate
vlib/v/checker/tests/enum_field_name_duplicate_err.vv:5:2: error: duplicate enum field name `green`
3 | yellow
4 | blue
5 | green

View File

@ -1,6 +1,13 @@
vlib/v/checker/tests/enum_field_overflow.vv:4:2: error: enum value overflows
vlib/v/checker/tests/enum_field_overflow.vv:3:10: error: enum value `2147483647` overflows the enum type `int`, values of which have to be in [-2147483648, 2147483647]
1 | enum Color {
2 | red
3 | green = 2147483647
| ~~~~~~~~~~
4 | blue
5 | }
vlib/v/checker/tests/enum_field_overflow.vv:4:2: error: enum value overflows type `int`, which has a maximum value of 2147483647
2 | red
3 | green = 2147483647
4 | blue
| ~~~~
5 | }
5 | }

View File

@ -1,7 +1,90 @@
vlib/v/checker/tests/enum_field_value_overflow.vv:3:10: error: enum value `2147483648` overflows int
vlib/v/checker/tests/enum_field_value_overflow.vv:3:10: error: enum value `2147483648` overflows the enum type `int`, values of which have to be in [-2147483648, 2147483647]
1 | enum Color {
2 | red
3 | green = 2147483648
| ~~~~~~~~~~
4 | blue
5 | }
5 | }
vlib/v/checker/tests/enum_field_value_overflow.vv:7:1: error: `string` is not one of `i8`,`i16`,`int`,`i64`,`u8`,`u16`,`u32`,`u64`
5 | }
6 |
7 | enum ColorString as string {
| ~~~~~~~~~~~~~~~~
8 | red
9 | green = 'abc'
vlib/v/checker/tests/enum_field_value_overflow.vv:9:10: error: the default value for an enum has to be an integer
7 | enum ColorString as string {
8 | red
9 | green = 'abc'
| ~~~~~
10 | blue
11 | }
vlib/v/checker/tests/enum_field_value_overflow.vv:10:2: error: enum value overflows type `string`, which has a maximum value of 0
8 | red
9 | green = 'abc'
10 | blue
| ~~~~
11 | }
12 |
vlib/v/checker/tests/enum_field_value_overflow.vv:15:10: error: enum value `128` overflows the enum type `i8`, values of which have to be in [-128, 127]
13 | enum ColorI8 as i8 {
14 | red
15 | green = 128
| ~~~
16 | blue
17 | }
vlib/v/checker/tests/enum_field_value_overflow.vv:21:10: error: enum value `32769` overflows the enum type `i16`, values of which have to be in [-32768, 32767]
19 | enum ColorI16 as i16 {
20 | red
21 | green = 32769
| ~~~~~
22 | blue
23 | }
vlib/v/checker/tests/enum_field_value_overflow.vv:27:10: error: enum value `2147483648` overflows the enum type `int`, values of which have to be in [-2147483648, 2147483647]
25 | enum ColorI32 {
26 | red
27 | green = 2147483648
| ~~~~~~~~~~
28 | blue
29 | }
vlib/v/checker/tests/enum_field_value_overflow.vv:33:10: error: enum value `9223372036854775808` overflows the enum type `i64`, values of which have to be in [-9223372036854775808, 9223372036854775807]
31 | enum ColorI64 as i64 {
32 | red
33 | green = 9223372036854775808
| ~~~~~~~~~~~~~~~~~~~
34 | blue
35 | }
vlib/v/checker/tests/enum_field_value_overflow.vv:34:2: error: enum value overflows type `i64`, which has a maximum value of 9223372036854775807
32 | red
33 | green = 9223372036854775808
34 | blue
| ~~~~
35 | }
36 |
vlib/v/checker/tests/enum_field_value_overflow.vv:56:10: error: enum value `256` overflows the enum type `u8`, values of which have to be in [0, 255]
54 | // These should work however, since the type is unsigned:
55 | enum ColorU8ShouldFail as u8 {
56 | green = 256
| ~~~
57 | }
58 |
vlib/v/checker/tests/enum_field_value_overflow.vv:60:10: error: enum value `65536` overflows the enum type `u16`, values of which have to be in [0, 65535]
58 |
59 | enum ColorU16ShouldFail as u16 {
60 | green = 65536
| ~~~~~
61 | }
62 |
vlib/v/checker/tests/enum_field_value_overflow.vv:64:10: error: enum value `4294967296` overflows the enum type `u32`, values of which have to be in [0, 4294967295]
62 |
63 | enum ColorU32ShouldFail as u32 {
64 | green = 4294967296
| ~~~~~~~~~~
65 | }
66 |
vlib/v/checker/tests/enum_field_value_overflow.vv:68:10: error: enum value `18446744073709551616` overflows the enum type `u64`, values of which have to be in [0, 18446744073709551615]
66 |
67 | enum ColorU64ShouldFail as u64 {
68 | green = 18446744073709551616
| ~~~~~~~~~~~~~~~~~~~~
69 | }

View File

@ -3,3 +3,67 @@ enum Color {
green = 2147483648
blue
}
enum ColorString as string {
red
green = 'abc'
blue
}
enum ColorI8 as i8 {
red
green = 128
blue
}
enum ColorI16 as i16 {
red
green = 32769
blue
}
enum ColorI32 {
red
green = 2147483648
blue
}
enum ColorI64 as i64 {
red
green = 9223372036854775808
blue
}
// These should work however, since the type is unsigned:
enum ColorU8ShouldWork as u8 {
green = 128
}
enum ColorU16ShouldWork as u16 {
green = 32769
}
enum ColorU32ShouldWork as u32 {
green = 2147483648
}
enum ColorU64ShouldWork as u64 {
green = 9223372036854775808
}
// These should work however, since the type is unsigned:
enum ColorU8ShouldFail as u8 {
green = 256
}
enum ColorU16ShouldFail as u16 {
green = 65536
}
enum ColorU32ShouldFail as u32 {
green = 4294967296
}
enum ColorU64ShouldFail as u64 {
green = 18446744073709551616
}

View File

@ -938,7 +938,11 @@ pub fn (mut f Fmt) enum_decl(node ast.EnumDecl) {
if node.is_pub {
f.write('pub ')
}
name := node.name.after('.')
mut name := node.name.after('.')
if node.typ != ast.int_type {
senum_type := f.table.type_to_str_using_aliases(node.typ, f.mod2alias)
name += ' as $senum_type'
}
if node.fields.len == 0 && node.pos.line_nr == node.pos.last_line {
f.writeln('enum $name {}\n')
return

View File

@ -306,8 +306,10 @@ fn (mut g Gen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string)
clean_name := util.strip_main_name(styp.replace('__', '.'))
g.auto_str_funcs.writeln('\tstring ret = _SLIT("$clean_name{");')
g.auto_str_funcs.writeln('\tint first = 1;')
g.auto_str_funcs.writeln('\tu64 zit = (u64)it;')
for i, val in info.vals {
g.auto_str_funcs.writeln('\tif (it & (1 << $i)) { if (!first) { ret = string__plus(ret, _SLIT(" | "));} ret = string__plus(ret, _SLIT(".$val")); first = 0;}')
mask := u64(1) << i
g.auto_str_funcs.writeln('\tif (zit & 0x${mask:016x}U) { if (!first) { ret = string__plus(ret, _SLIT(" | "));} ret = string__plus(ret, _SLIT(".$val")); first = 0;}')
}
g.auto_str_funcs.writeln('\tret = string__plus(ret, _SLIT("}"));')
g.auto_str_funcs.writeln('\treturn ret;')

View File

@ -3677,6 +3677,33 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
fn (mut g Gen) enum_decl(node ast.EnumDecl) {
enum_name := util.no_dots(node.name)
is_flag := node.is_flag
if g.pref.ccompiler == 'msvc' {
mut last_value := '0'
enum_typ_name := g.table.get_type_name(node.typ)
g.enum_typedefs.writeln('typedef $enum_typ_name $enum_name;')
for i, field in node.fields {
g.enum_typedefs.write_string('\t#define ${enum_name}__$field.name ')
g.enum_typedefs.write_string('(')
if is_flag {
g.enum_typedefs.write_string((u64(1) << i).str())
g.enum_typedefs.write_string('ULL')
} else if field.has_expr {
expr_str := g.expr_string(field.expr)
g.enum_typedefs.write_string(expr_str)
last_value = expr_str
} else {
if i != 0 {
last_value += '+1'
}
g.enum_typedefs.write_string(last_value)
}
g.enum_typedefs.writeln(')')
}
return
}
if node.typ != ast.int_type {
g.enum_typedefs.writeln('#pragma pack(push, 1)')
}
g.enum_typedefs.writeln('typedef enum {')
mut cur_enum_expr := ''
mut cur_enum_offset := 0
@ -3690,8 +3717,9 @@ fn (mut g Gen) enum_decl(node ast.EnumDecl) {
cur_enum_offset = 0
} else if is_flag {
g.enum_typedefs.write_string(' = ')
cur_enum_expr = '1 << $i'
g.enum_typedefs.write_string((1 << i).str())
cur_enum_expr = 'u64(1) << $i'
g.enum_typedefs.write_string((u64(1) << i).str())
g.enum_typedefs.write_string('U')
cur_enum_offset = 0
}
cur_value := if cur_enum_offset > 0 {
@ -3702,7 +3730,11 @@ fn (mut g Gen) enum_decl(node ast.EnumDecl) {
g.enum_typedefs.writeln(', // $cur_value')
cur_enum_offset++
}
g.enum_typedefs.writeln('} $enum_name;\n')
packed_attribute := if node.typ != ast.int_type { '__attribute__((packed))' } else { '' }
g.enum_typedefs.writeln('} $packed_attribute $enum_name;')
if node.typ != ast.int_type {
g.enum_typedefs.writeln('#pragma pack(pop)\n')
}
}
fn (mut g Gen) enum_expr(node ast.Expr) {

View File

@ -31,7 +31,7 @@ fn match_test() {
assert false
}
}
// println(color)
// println(color)
assert num == 3
}
@ -43,7 +43,7 @@ fn (_ Bar) baz() {}
fn test_enum_variant_and_method_name_clash() {
x := Bar.baz
// println(x)
// println(x)
x.baz()
}
@ -73,4 +73,5 @@ fn main() {
match_test()
test_enum_variant_and_method_name_clash()
value_test()
println('OK')
}

View File

@ -0,0 +1 @@
OK

View File

@ -3665,8 +3665,14 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
return ast.EnumDecl{}
}
name := p.prepend_mod(enum_name)
mut enum_type := ast.int_type
if p.tok.kind == .key_as {
p.next()
enum_type = p.parse_type()
}
p.check(.lcbr)
enum_decl_comments := p.eat_comments()
senum_type := p.table.get_type_name(enum_type)
mut vals := []string{}
// mut default_exprs := []ast.Expr{}
mut fields := []ast.EnumField{}
@ -3698,8 +3704,8 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
is_flag := p.attrs.contains('flag')
is_multi_allowed := p.attrs.contains('_allow_multiple_values')
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')
if fields.len > 64 {
p.error('when an enum is used as bit field, it must have a max of 64 fields')
return ast.EnumDecl{}
}
for f in fields {
@ -3712,12 +3718,12 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
pubfn := if p.mod == 'main' { 'fn' } else { 'pub fn' }
p.codegen('
//
[inline] $pubfn ( e &$enum_name) is_empty() bool { return int(*e) == 0 }
[inline] $pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (int(flag))) != 0 }
[inline] $pubfn ( e &$enum_name) all(flag $enum_name) bool { return (int(*e) & (int(flag))) == int(flag) }
[inline] $pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) | (int(flag))) } }
[inline] $pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) & ~(int(flag))) } }
[inline] $pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) ^ (int(flag))) } }
[inline] $pubfn ( e &$enum_name) is_empty() bool { return ${senum_type}(*e) == 0 }
[inline] $pubfn ( e &$enum_name) has(flag $enum_name) bool { return (${senum_type}(*e) & (${senum_type}(flag))) != 0 }
[inline] $pubfn ( e &$enum_name) all(flag $enum_name) bool { return (${senum_type}(*e) & (${senum_type}(flag))) == ${senum_type}(flag) }
[inline] $pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = ${enum_name}(${senum_type}(*e) | (${senum_type}(flag))) } }
[inline] $pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = ${enum_name}(${senum_type}(*e) & ~(${senum_type}(flag))) } }
[inline] $pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = ${enum_name}(${senum_type}(*e) ^ (${senum_type}(flag))) } }
//
')
}
@ -3741,6 +3747,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
enum_decl := ast.EnumDecl{
name: name
typ: enum_type
is_pub: is_pub
is_flag: is_flag
is_multi_allowed: is_multi_allowed

View File

@ -0,0 +1,124 @@
// TODO: fix the formatting here, when VFMT ON/OFF is working
[flag]
enum PawnsBoard as u64 {
a8
b8
c8
d8
e8
f8
g8
h8
a7
b7
c7
d7
e7
f7
g7
h7
a6
b6
c6
d6
e6
f6
g6
h6
a5
b5
c5
d5
e5
f5
g5
h5
a4
b4
c4
d4
e4
f4
g4
h4
a3
b3
c3
d3
e3
f3
g3
h3
a2
b2
c2
d2
e2
f2
g2
h2
a1
b1
c1
d1
e1
f1
g1
h1
}
fn test_flag_enum_with_64_value_bits() {
last_value := PawnsBoard.h1
dump(u64(last_value))
assert u64(last_value) == 0x8000_0000_0000_0000
wb := PawnsBoard.a2 | .b2 | .c2 | .d2 | .e2 | .f2 | .g2 | .h2
dump(wb)
dump(u64(wb))
assert u64(wb) == 71776119061217280
assert '${u64(wb):064b}' == '0000000011111111000000000000000000000000000000000000000000000000'
assert '$wb' == 'PawnsBoard{.a2 | .b2 | .c2 | .d2 | .e2 | .f2 | .g2 | .h2}'
bb := PawnsBoard.a7 | .b7 | .c7 | .d7 | .e7 | .f7 | .g7 | .h7
dump(bb)
dump(u64(bb))
assert u64(bb) == 65280
assert '${u64(bb):064b}' == '0000000000000000000000000000000000000000000000001111111100000000'
assert '$bb' == 'PawnsBoard{.a7 | .b7 | .c7 | .d7 | .e7 | .f7 | .g7 | .h7}'
if false {
eprintln('----------------------------------------------')
for x in [PawnsBoard.a1, .a2, .a3, .a4, .a5, .a6, .a7, .a8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.b1, .b2, .b3, .b4, .b5, .b6, .b7, .b8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.c1, .c2, .c3, .c4, .c5, .c6, .c7, .c8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.d1, .d2, .d3, .d4, .d5, .d6, .d7, .d8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.e1, .e2, .e3, .e4, .e5, .e6, .e7, .e8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.f1, .f2, .f3, .f4, .f5, .f6, .f7, .f8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.g1, .g2, .g3, .g4, .g5, .g6, .g7, .g8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
eprintln('----------------------------------------------')
for x in [PawnsBoard.h1, .h2, .h3, .h4, .h5, .h6, .h7, .h8] {
eprintln('>> x: $x | hex value: ${u64(x).hex()}')
}
}
}

View File

@ -0,0 +1,83 @@
enum SmallEnum as i8 {
a = -1
b = -4
c
d = 5
e
}
enum BigEnum as u64 {
a = 0xABCD_EF09_1234_5678
b = 0xFFFF_FFFF_FFFF_FFF0
c
d = 5
e
}
enum BigIEnum as i64 {
a = -999_999_999_999
b = -900_000_000_000
c
d = 900_000_000_000
e
}
fn test_small_enum() {
dump(sizeof(SmallEnum))
$if tinyc {
// TODO: TCC currently ignores `__attribute__((packed))` for enums, and uses an int instead, even with -fshort-enums :-|
assert sizeof(SmallEnum) == 4
} $else {
assert sizeof(SmallEnum) == 1
}
dump(i8(SmallEnum.a))
dump(i8(SmallEnum.b))
dump(i8(SmallEnum.c))
dump(i8(SmallEnum.d))
dump(i8(SmallEnum.e))
assert i8(SmallEnum.a) == -1
assert i8(SmallEnum.b) == -4
assert i8(SmallEnum.c) == -3
assert i8(SmallEnum.d) == 5
assert i8(SmallEnum.e) == 6
}
fn test_big_enum() {
assert sizeof(BigIEnum) == 8
assert BigEnum.a.str() == 'a'
assert BigEnum.b.str() == 'b'
assert BigEnum.c.str() == 'c'
assert BigEnum.d.str() == 'd'
assert BigEnum.e.str() == 'e'
dump(u64(BigEnum.a))
dump(u64(BigEnum.b))
dump(u64(BigEnum.c))
dump(u64(BigEnum.d))
dump(u64(BigEnum.e))
assert sizeof(BigEnum) == 8
assert u64(BigEnum.a) == 0xABCD_EF09_1234_5678
assert u64(BigEnum.b) == 0xFFFF_FFFF_FFFF_FFF0
assert u64(BigEnum.c) == 0xFFFF_FFFF_FFFF_FFF1
assert u64(BigEnum.d) == 5
assert u64(BigEnum.e) == 6
}
fn test_big_ienum() {
assert sizeof(BigIEnum) == 8
assert BigIEnum.a.str() == 'a'
assert BigIEnum.b.str() == 'b'
assert BigIEnum.c.str() == 'c'
assert BigIEnum.d.str() == 'd'
assert BigIEnum.e.str() == 'e'
dump(i64(BigIEnum.a))
dump(i64(BigIEnum.b))
dump(i64(BigIEnum.c))
dump(i64(BigIEnum.d))
dump(i64(BigIEnum.e))
assert sizeof(BigIEnum) == 8
assert i64(BigIEnum.a) == -999999999999
assert i64(BigIEnum.b) == -900000000000
assert i64(BigIEnum.c) == -899999999999
assert i64(BigIEnum.d) == 900000000000
assert i64(BigIEnum.e) == 900000000001
}