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 pos token.Position
comments []Comment // comment after Enumfield in the same line comments []Comment // comment after Enumfield in the same line
next_comments []Comment // comments between current EnumField and next EnumField 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 has_expr bool // true, when .expr has a value
pub mut:
expr Expr // the value of current EnumField; 123 in `ename = 123`
} }
// enum declaration // 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) { if field := ts.info.find_field(name) {
return field 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') return error('field `$name` does not exist or have the same type in all sumtype variants')
} }
else {} 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) 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 { if node.fields.len == 0 {
c.error('enum cannot be empty', node.pos) 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) 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) { if !c.pref.experimental && util.contains_capital(field.name) {
// TODO C2V uses hundreds of enums with capitals, remove -experimental check once it's handled // 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', 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 { if field.has_expr {
match field.expr { match mut field.expr {
ast.IntegerLiteral { ast.IntegerLiteral {
val := field.expr.val.i64() val := field.expr.val.i64()
if val < checker.int_min || val > checker.int_max { if val < checker.int_min || val > checker.int_max {
c.error('enum value `$val` overflows int', field.expr.pos) 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) c.error('enum value `$val` already exists', field.expr.pos)
} }
seen << i64(val) seen << i64(val)
} }
ast.PrefixExpr {} ast.PrefixExpr {}
ast.InfixExpr {
// Handle `enum Foo { x = 1 + 2 }`
c.infix_expr(mut field.expr)
}
// ast.ParExpr {} // TODO allow `.x = (1+2)`
else { else {
if field.expr is ast.Ident { 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 continue
} }
} }
@ -3763,7 +3771,7 @@ pub fn (mut c Checker) enum_decl(node ast.EnumDecl) {
last := seen[seen.len - 1] last := seen[seen.len - 1]
if last == checker.int_max { if last == checker.int_max {
c.error('enum value overflows', field.pos) 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) c.error('enum value `${last + 1}` already exists', field.pos)
} }
seen << last + 1 seen << last + 1
@ -4657,7 +4665,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.inside_defer = false c.inside_defer = false
} }
ast.EnumDecl { ast.EnumDecl {
c.enum_decl(node) c.enum_decl(mut node)
} }
ast.ExprStmt { ast.ExprStmt {
node.typ = c.expr(node.expr) node.typ = c.expr(node.expr)

View File

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

View File

@ -32,6 +32,20 @@ fn test_enum() {
assert color == .green 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() { fn test_in() {
color := Color.red color := Color.red
num := 3 // used to be an expr bug before `in` num := 3 // used to be an expr bug before `in`