浏览代码

using Foo :: enum {A, B, C}; len(Foo)

gingerBill 7 年之前
父节点
当前提交
6512a3e5f2
共有 11 个文件被更改,包括 60 次插入73 次删除
  1. 0 1
      core/fmt/fmt.odin
  2. 1 1
      core/runtime/core.odin
  3. 6 5
      examples/demo/demo.odin
  4. 0 1
      src/big_int.cpp
  5. 15 1
      src/check_expr.cpp
  6. 4 19
      src/check_type.cpp
  7. 8 0
      src/checker.cpp
  8. 2 2
      src/ir.cpp
  9. 21 22
      src/parser.cpp
  10. 1 1
      src/parser.hpp
  11. 2 20
      src/types.cpp

+ 0 - 1
core/fmt/fmt.odin

@@ -290,7 +290,6 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
 	case runtime.Type_Info_Enum:
 	case runtime.Type_Info_Enum:
 		write_string(buf, "enum ");
 		write_string(buf, "enum ");
 		write_type(buf, info.base);
 		write_type(buf, info.base);
-		if info.is_export do write_string(buf, " #export");
 		write_string(buf, " {");
 		write_string(buf, " {");
 		for name, i in info.names {
 		for name, i in info.names {
 			if i > 0 do write_string(buf, ", ");
 			if i > 0 do write_string(buf, ", ");

+ 1 - 1
core/runtime/core.odin

@@ -88,7 +88,7 @@ Type_Info_Enum :: struct {
 	base:      ^Type_Info,
 	base:      ^Type_Info,
 	names:     []string,
 	names:     []string,
 	values:    []Type_Info_Enum_Value,
 	values:    []Type_Info_Enum_Value,
-	is_export: bool,
+	is_using:  bool, // TODO(bill): Should this be in the `Type_Info`?
 };
 };
 Type_Info_Map :: struct {
 Type_Info_Map :: struct {
 	key:              ^Type_Info,
 	key:              ^Type_Info,

+ 6 - 5
examples/demo/demo.odin

@@ -608,15 +608,16 @@ named_proc_return_parameters :: proc() {
 }
 }
 
 
 
 
-enum_export :: proc() {
-	fmt.println("# enum #export");
+using_enum :: proc() {
+	fmt.println("# using enum");
 
 
-	Foo :: enum #export {A, B, C};
+	using Foo :: enum {A, B, C};
 
 
 	f0 := A;
 	f0 := A;
 	f1 := B;
 	f1 := B;
 	f2 := C;
 	f2 := C;
 	fmt.println(f0, f1, f2);
 	fmt.println(f0, f1, f2);
+	fmt.println(len(Foo));
 }
 }
 
 
 explicit_procedure_overloading :: proc() {
 explicit_procedure_overloading :: proc() {
@@ -656,7 +657,7 @@ explicit_procedure_overloading :: proc() {
 complete_switch :: proc() {
 complete_switch :: proc() {
 	fmt.println("# complete_switch");
 	fmt.println("# complete_switch");
 	{ // enum
 	{ // enum
-		Foo :: enum #export {
+		using Foo :: enum {
 			A,
 			A,
 			B,
 			B,
 			C,
 			C,
@@ -723,7 +724,7 @@ main :: proc() {
 		threading_example();
 		threading_example();
 		array_programming();
 		array_programming();
 		named_proc_return_parameters();
 		named_proc_return_parameters();
-		enum_export();
+		using_enum();
 		explicit_procedure_overloading();
 		explicit_procedure_overloading();
 		complete_switch();
 		complete_switch();
 		cstring_example();
 		cstring_example();

+ 0 - 1
src/big_int.cpp

@@ -510,7 +510,6 @@ void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
 
 
 		u64 first_word = dst->d.word;
 		u64 first_word = dst->d.word;
 		big_int_alloc(dst, 0, bigger->len);
 		big_int_alloc(dst, 0, bigger->len);
-		GB_ASSERT(dst->len > 1);
 		dst->d.words[0] = first_word;
 		dst->d.words[0] = first_word;
 
 
 		i32 i = 0;
 		i32 i = 0;

+ 15 - 1
src/check_expr.cpp

@@ -2788,6 +2788,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 	case BuiltinProc_offset_of:
 	case BuiltinProc_offset_of:
 	case BuiltinProc_type_info_of:
 	case BuiltinProc_type_info_of:
 	case BuiltinProc_typeid_of:
 	case BuiltinProc_typeid_of:
+	case BuiltinProc_len:
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		break;
 		break;
 	default:
 	default:
@@ -2860,9 +2861,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 	}
 	}
 
 
 	case BuiltinProc_len:
 	case BuiltinProc_len:
-	case BuiltinProc_cap: {
+		check_expr_or_type(c, operand, ce->args[0]);
+		if (operand->mode == Addressing_Invalid) {
+			return false;
+		}
+		/* fallthrough */
+
+	case BuiltinProc_cap:
+	{
 		// len :: proc(Type) -> int
 		// len :: proc(Type) -> int
 		// cap :: proc(Type) -> int
 		// cap :: proc(Type) -> int
+
 		Type *op_type = type_deref(operand->type);
 		Type *op_type = type_deref(operand->type);
 		Type *type = t_int;
 		Type *type = t_int;
 		AddressingMode mode = Addressing_Invalid;
 		AddressingMode mode = Addressing_Invalid;
@@ -2890,6 +2899,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			mode = Addressing_Value;
 			mode = Addressing_Value;
 		} else if (is_type_map(op_type)) {
 		} else if (is_type_map(op_type)) {
 			mode = Addressing_Value;
 			mode = Addressing_Value;
+		} else if (operand->mode == Addressing_Type && is_type_enum(op_type) && id == BuiltinProc_len) {
+			Type *bt = base_type(op_type);
+			mode  = Addressing_Constant;
+			value = exact_value_i64(bt->Enum.fields.count);
+			type  = t_untyped_integer;
 		}
 		}
 
 
 		if (mode == Addressing_Invalid) {
 		if (mode == Addressing_Invalid) {

+ 4 - 19
src/check_type.cpp

@@ -571,22 +571,10 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
 		// NOTE(bill): Skip blank identifiers
 		// NOTE(bill): Skip blank identifiers
 		if (is_blank_ident(name)) {
 		if (is_blank_ident(name)) {
 			continue;
 			continue;
-		} else if (name == "count") {
-			error(field, "'count' is a reserved identifier for enumerations");
-			continue;
-		} else if (name == "min_value") {
-			error(field, "'min_value' is a reserved identifier for enumerations");
-			continue;
-		} else if (name == "max_value") {
-			error(field, "'max_value' is a reserved identifier for enumerations");
-			continue;
 		} else if (name == "names") {
 		} else if (name == "names") {
 			error(field, "'names' is a reserved identifier for enumerations");
 			error(field, "'names' is a reserved identifier for enumerations");
 			continue;
 			continue;
-		}/*  else if (name == "base_type") {
-			error(field, "'base_type' is a reserved identifier for enumerations");
-			continue;
-		} */
+		}
 
 
 		if (compare_exact_values(Token_Gt, min_value, iota)) {
 		if (compare_exact_values(Token_Gt, min_value, iota)) {
 			min_value = iota;
 			min_value = iota;
@@ -613,8 +601,9 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
 
 
 
 
 	enum_type->Enum.fields    = fields;
 	enum_type->Enum.fields    = fields;
-	enum_type->Enum.is_export = et->is_export;
-	if (et->is_export) {
+	enum_type->Enum.is_using = et->is_using;
+	// TODO(bill): Should this be done elsewhere? e.g. delayed
+	if (et->is_using) {
 		Scope *parent = ctx->scope->parent;
 		Scope *parent = ctx->scope->parent;
 		if (parent->flags&ScopeFlag_File) {
 		if (parent->flags&ScopeFlag_File) {
 			// NOTE(bill): Use package scope
 			// NOTE(bill): Use package scope
@@ -634,10 +623,6 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
 	}
 	}
 
 
 	Scope *s = ctx->scope;
 	Scope *s = ctx->scope;
-	enum_type->Enum.count     = alloc_entity_constant(s, make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
-	enum_type->Enum.min_value = alloc_entity_constant(s, make_token_ident(str_lit("min_value")), constant_type, min_value);
-	enum_type->Enum.max_value = alloc_entity_constant(s, make_token_ident(str_lit("max_value")), constant_type, max_value);
-
 	enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope);
 	enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope);
 }
 }
 
 

+ 8 - 0
src/checker.cpp

@@ -2121,6 +2121,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 			}
 			}
 			e->identifier = name;
 			e->identifier = name;
 
 
+			if (vd->is_using) {
+				if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) {
+					init->EnumType.is_using = true;
+				} else {
+					error(name, "'using' is not allowed on this constant value declaration");
+				}
+			}
+
 			if (e->kind != Entity_Procedure) {
 			if (e->kind != Entity_Procedure) {
 				if (fl != nullptr || c->foreign_context.in_export) {
 				if (fl != nullptr || c->foreign_context.in_export) {
 					AstKind kind = init->kind;
 					AstKind kind = init->kind;

+ 2 - 2
src/ir.cpp

@@ -8163,8 +8163,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
 				irValue *base = ir_type_info(proc, t->Enum.base_type);
 				irValue *base = ir_type_info(proc, t->Enum.base_type);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), base);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), base);
 
 
-				// is_export
-				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_bool(t->Enum.is_export));
+				// is_using
+				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_bool(t->Enum.is_using));
 
 
 				if (t->Enum.fields.count > 0) {
 				if (t->Enum.fields.count > 0) {
 					auto fields = t->Enum.fields;
 					auto fields = t->Enum.fields;

+ 21 - 22
src/parser.cpp

@@ -920,11 +920,10 @@ Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *align)
 }
 }
 
 
 
 
-Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, bool is_export, Array<Ast *> fields) {
+Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, Array<Ast *> fields) {
 	Ast *result = alloc_ast_node(f, Ast_EnumType);
 	Ast *result = alloc_ast_node(f, Ast_EnumType);
 	result->EnumType.token = token;
 	result->EnumType.token = token;
 	result->EnumType.base_type = base_type;
 	result->EnumType.base_type = base_type;
-	result->EnumType.is_export = is_export;
 	result->EnumType.fields = fields;
 	result->EnumType.fields = fields;
 	return result;
 	return result;
 }
 }
@@ -1903,34 +1902,34 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 	} break;
 	} break;
 
 
 	case Token_enum: {
 	case Token_enum: {
-		bool is_export = false;
+		// bool is_export = false;
 		Token token = expect_token(f, Token_enum);
 		Token token = expect_token(f, Token_enum);
 		Ast *base_type = nullptr;
 		Ast *base_type = nullptr;
 		if (f->curr_token.kind != Token_OpenBrace) {
 		if (f->curr_token.kind != Token_OpenBrace) {
 			if (f->curr_token.kind != Token_Hash) {
 			if (f->curr_token.kind != Token_Hash) {
 				base_type = parse_type(f);
 				base_type = parse_type(f);
 			}
 			}
-			while (allow_token(f, Token_Hash)) {
-				Token tag = f->curr_token;
-				if (!allow_token(f, Token_Ident) && !allow_token(f, Token_export)) {
-					expect_token_after(f, Token_Ident, "#");
-				}
-				if (tag.string == "export") {
-					if (is_export) {
-						syntax_error(tag, "Duplicate enum tag '#%.*s'", LIT(tag.string));
-					}
-					is_export = true;
-				} else {
-					syntax_error(tag, "Invalid enum tag '#%.*s'", LIT(tag.string));
-				}
-			}
+			// while (allow_token(f, Token_Hash)) {
+			// 	Token tag = f->curr_token;
+			// 	if (!allow_token(f, Token_Ident) && !allow_token(f, Token_export)) {
+			// 		expect_token_after(f, Token_Ident, "#");
+			// 	}
+			// 	if (tag.string == "export") {
+			// 		if (is_export) {
+			// 			syntax_error(tag, "Duplicate enum tag '#%.*s'", LIT(tag.string));
+			// 		}
+			// 		is_export = true;
+			// 	} else {
+			// 		syntax_error(tag, "Invalid enum tag '#%.*s'", LIT(tag.string));
+			// 	}
+			// }
 		}
 		}
 		Token open = expect_token(f, Token_OpenBrace);
 		Token open = expect_token(f, Token_OpenBrace);
 
 
 		Array<Ast *> values = parse_element_list(f);
 		Array<Ast *> values = parse_element_list(f);
 		Token close = expect_token(f, Token_CloseBrace);
 		Token close = expect_token(f, Token_CloseBrace);
 
 
-		return ast_enum_type(f, token, base_type, is_export, values);
+		return ast_enum_type(f, token, base_type, values);
 	} break;
 	} break;
 
 
 	case Token_bit_field: {
 	case Token_bit_field: {
@@ -3591,10 +3590,10 @@ Ast *parse_stmt(AstFile *f) {
 		decl = parse_value_decl(f, list, docs);
 		decl = parse_value_decl(f, list, docs);
 
 
 		if (decl != nullptr && decl->kind == Ast_ValueDecl) {
 		if (decl != nullptr && decl->kind == Ast_ValueDecl) {
-			if (!decl->ValueDecl.is_mutable) {
-				syntax_error(token, "'using' may only be applied to variable declarations");
-				return decl;
-			}
+			// if (!decl->ValueDecl.is_mutable) {
+			// 	syntax_error(token, "'using' may only be applied to variable declarations");
+			// 	return decl;
+			// }
 			decl->ValueDecl.is_using = true;
 			decl->ValueDecl.is_using = true;
 			return decl;
 			return decl;
 		}
 		}

+ 1 - 1
src/parser.hpp

@@ -478,7 +478,7 @@ AST_KIND(_TypeBegin, "", bool) \
 		Token        token; \
 		Token        token; \
 		Ast *        base_type; \
 		Ast *        base_type; \
 		Array<Ast *> fields; /* FieldValue */ \
 		Array<Ast *> fields; /* FieldValue */ \
-		bool         is_export; \
+		bool         is_using; \
 	}) \
 	}) \
 	AST_KIND(BitFieldType, "bit field type", struct { \
 	AST_KIND(BitFieldType, "bit field type", struct { \
 		Token        token; \
 		Token        token; \

+ 2 - 20
src/types.cpp

@@ -131,14 +131,11 @@ struct TypeStruct {
 	TYPE_KIND(Struct,  TypeStruct)                        \
 	TYPE_KIND(Struct,  TypeStruct)                        \
 	TYPE_KIND(Enum, struct {                              \
 	TYPE_KIND(Enum, struct {                              \
 		Array<Entity *> fields;                           \
 		Array<Entity *> fields;                           \
-		Ast *node;                                    \
+		Ast *node;                                        \
 		Scope *  scope;                                   \
 		Scope *  scope;                                   \
 		Entity * names;                                   \
 		Entity * names;                                   \
 		Type *   base_type;                               \
 		Type *   base_type;                               \
-		bool     is_export;                               \
-		Entity * count;                                   \
-		Entity * min_value;                               \
-		Entity * max_value;                               \
+		bool     is_using;                                \
 	})                                                    \
 	})                                                    \
 	TYPE_KIND(Union, struct {                             \
 	TYPE_KIND(Union, struct {                             \
 		Array<Type *> variants;                           \
 		Array<Type *> variants;                           \
@@ -1657,21 +1654,6 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 
 
 		if (is_type_enum(type)) {
 		if (is_type_enum(type)) {
 			// NOTE(bill): These may not have been added yet, so check in case
 			// NOTE(bill): These may not have been added yet, so check in case
-			if (type->Enum.count != nullptr) {
-				if (field_name == "count") {
-					sel.entity = type->Enum.count;
-					return sel;
-				}
-				if (field_name == "min_value") {
-					sel.entity = type->Enum.min_value;
-					return sel;
-				}
-				if (field_name == "max_value") {
-					sel.entity = type->Enum.max_value;
-					return sel;
-				}
-			}
-
 			for_array(i, type->Enum.fields) {
 			for_array(i, type->Enum.fields) {
 				Entity *f = type->Enum.fields[i];
 				Entity *f = type->Enum.fields[i];
 				GB_ASSERT(f->kind == Entity_Constant);
 				GB_ASSERT(f->kind == Entity_Constant);