checker: allow infix expressions in enum declarations

pull/12660/head
Alexander Medvednikov 2021-12-03 07:45:37 +03:00
parent c4363bc78b
commit eca78a2906
5 changed files with 35 additions and 9 deletions

View File

@ -1039,8 +1039,9 @@ pub:
pos token.Position
comments []Comment // comment after Enumfield in the same line
next_comments []Comment // comments between current EnumField and next EnumField
expr Expr // the value of current EnumField; 123 in `ename = 123`
has_expr bool // true, when .expr has a value
pub mut:
expr Expr // the value of current EnumField; 123 in `ename = 123`
}
// enum declaration

View File

@ -485,6 +485,8 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField {
if field := ts.info.find_field(name) {
return field
}
// mut info := ts.info as SumType
// TODO a more detailed error so that it's easier to fix?
return error('field `$name` does not exist or have the same type in all sumtype variants')
}
else {}

View File

@ -3711,9 +3711,9 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
}
}
pub fn (mut c Checker) enum_decl(node ast.EnumDecl) {
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{}
mut seen := []i64{cap: node.fields.len}
if node.fields.len == 0 {
c.error('enum cannot be empty', node.pos)
}
@ -3722,7 +3722,7 @@ pub fn (mut c Checker) enum_decl(node ast.EnumDecl) {
c.error('`builtin` module cannot have enums', node.pos)
}
*/
for i, field in node.fields {
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',
@ -3734,20 +3734,28 @@ pub fn (mut c Checker) enum_decl(node ast.EnumDecl) {
}
}
if field.has_expr {
match field.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 !node.is_multi_allowed && i64(val) in seen {
} else if !c.pref.translated && !node.is_multi_allowed && i64(val) in seen {
c.error('enum value `$val` already exists', field.expr.pos)
}
seen << i64(val)
}
ast.PrefixExpr {}
ast.InfixExpr {
// Handle `enum Foo { x = 1 + 2 }`
c.infix_expr(mut field.expr)
}
// ast.ParExpr {} // TODO allow `.x = (1+2)`
else {
if field.expr is ast.Ident {
if field.expr.language == .c {
x := field.expr as ast.Ident
// TODO sum type bug, remove temp var
// if field.expr.language == .c {
if x.language == .c {
continue
}
}
@ -3763,7 +3771,7 @@ pub fn (mut c Checker) enum_decl(node ast.EnumDecl) {
last := seen[seen.len - 1]
if last == checker.int_max {
c.error('enum value overflows', field.pos)
} else if !node.is_multi_allowed && last + 1 in seen {
} else if !c.pref.translated && !node.is_multi_allowed && last + 1 in seen {
c.error('enum value `${last + 1}` already exists', field.pos)
}
seen << last + 1
@ -4657,7 +4665,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.inside_defer = false
}
ast.EnumDecl {
c.enum_decl(node)
c.enum_decl(mut node)
}
ast.ExprStmt {
node.typ = c.expr(node.expr)

View File

@ -542,6 +542,7 @@ typedef struct sync__Channel* chan;
#ifndef __cplusplus
#ifndef bool
//typedef int bool;
typedef byte bool;
#define true 1
#define false 0

View File

@ -32,6 +32,20 @@ fn test_enum() {
assert color == .green
}
enum PowerDuration {
invulntics = 30 * 35
invistics = 60 * 35
infratics = 120 * 35
}
fn test_custom_values() {
mut p := PowerDuration.invulntics
assert int(p) == 30 * 35
p = .invistics
assert int(p) == 60 * 35
assert int(PowerDuration.infratics) == 120 * 35
}
fn test_in() {
color := Color.red
num := 3 // used to be an expr bug before `in`