Browse Source

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

gingerBill 5 years ago
parent
commit
5ec8dd166a
3 changed files with 46 additions and 4 deletions
  1. 13 3
      examples/demo/demo.odin
  2. 22 1
      src/check_type.cpp
  3. 11 0
      src/parser.cpp

+ 13 - 3
examples/demo/demo.odin

@@ -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]);

+ 22 - 1
src/check_type.cpp

@@ -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;

+ 11 - 0
src/parser.cpp

@@ -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;