Add #partial tag for enumerated arrays to prevent common errors using non-contiguous enumerations

This commit is contained in:
gingerBill
2019-12-27 16:55:32 +00:00
parent 80a32a8182
commit 5ec8dd166a
3 changed files with 46 additions and 4 deletions

View File

@@ -1845,11 +1845,9 @@ constant_literal_expressions :: proc() {
FOO_ARRAY_DEFAULTS :: [3]Foo{{}, {}, {}};
fmt.println(FOO_ARRAY_DEFAULTS[2].x);
fmt.println("-------");
Baz :: enum{A=5, B, C, D=9};
Baz :: enum{A=5, B, C, D};
ENUM_ARRAY_CONST :: [Baz]int{.A .. .C = 1, .D = 16};
fmt.println(ENUM_ARRAY_CONST[.A]);
@@ -1859,6 +1857,18 @@ constant_literal_expressions :: proc() {
fmt.println("-------");
Partial_Baz :: enum{A=5, B, C, D=16};
#assert(len(Partial_Baz) < len(#partial [Partial_Baz]int));
PARTIAL_ENUM_ARRAY_CONST :: #partial [Partial_Baz]int{.A .. .C = 1, .D = 16};
fmt.println(PARTIAL_ENUM_ARRAY_CONST[.A]);
fmt.println(PARTIAL_ENUM_ARRAY_CONST[.B]);
fmt.println(PARTIAL_ENUM_ARRAY_CONST[.C]);
fmt.println(PARTIAL_ENUM_ARRAY_CONST[.D]);
fmt.println("-------");
STRING_CONST :: "Hellope!";
fmt.println(STRING_CONST[0]);

View File

@@ -3241,11 +3241,32 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
Type *t = alloc_type_enumerated_array(elem, index, bt->Enum.min_value, bt->Enum.max_value, Token_Invalid);
bool is_partial = false;
if (at->tag != nullptr) {
GB_ASSERT(at->tag->kind == Ast_BasicDirective);
String name = at->tag->BasicDirective.name;
error(at->tag, "Invalid tag applied to an enumerated array, got #%.*s", LIT(name));
if (name == "partial") {
is_partial = true;
} else {
error(at->tag, "Invalid tag applied to an enumerated array, got #%.*s", LIT(name));
}
}
if (t->EnumeratedArray.count != bt->Enum.fields.count) {
if (!is_partial) {
error(e, "Non-contiguous enumeration used as an index in an enumerated array");
long long ea_count = cast(long long)t->EnumeratedArray.count;
long long enum_count = cast(long long)t->Enum.fields.count;
error_line("\tenumerated array length: %lld\n", ea_count);
error_line("\tenum field count: %lld\n", enum_count);
error_line("\tSuggestion: prepend #partial to the enumerated array to allow for non-named elements\n");
if (2*enum_count < ea_count) {
error_line("\tWarning: the number of named elements is much smaller than the length of the array, are you sure this is what you want?\n");
error_line("\t this warning will be removed if #partial is applied\n");
}
}
}
*type = t;
goto array_end;

View File

@@ -1759,6 +1759,17 @@ Ast *parse_operand(AstFile *f, bool lhs) {
break;
}
return original_type;
} else if (name.string == "partial") {
Ast *tag = ast_basic_directive(f, token, name.string);
Ast *original_type = parse_type(f);
Ast *type = unparen_expr(original_type);
switch (type->kind) {
case Ast_ArrayType: type->ArrayType.tag = tag; break;
default:
syntax_error(type, "Expected an enumerated array type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind]));
break;
}
return original_type;
} else if (name.string == "bounds_check") {
Ast *operand = parse_expr(f, lhs);
operand->state_flags |= StateFlag_bounds_check;