Pārlūkot izejas kodu

Begin changing `union` syntax

Ginger Bill 8 gadi atpakaļ
vecāks
revīzija
a94dfdf21d
6 mainītis faili ar 192 papildinājumiem un 45 dzēšanām
  1. 1 1
      code/demo.odin
  2. 43 0
      core/_preload.odin
  3. 67 13
      src/check_expr.c
  4. 1 1
      src/gb/gb.h
  5. 47 21
      src/ir.c
  6. 33 9
      src/parser.c

+ 1 - 1
code/demo.odin

@@ -5,7 +5,7 @@
 #import "mem.odin";
 #import "opengl.odin";
 #import "os.odin";
-#import "halloc.odin";
+// #import "halloc.odin";
 
 main :: proc() {
 	m: map[int]int;

+ 43 - 0
core/_preload.odin

@@ -37,6 +37,7 @@ Calling_Convention :: enum {
 	FAST = 3,
 }
 
+/*
 Type_Info :: union {
 	Named: struct #ordered {
 		name: string,
@@ -96,6 +97,48 @@ Type_Info :: union {
 		count:            int, // == 0 if dynamic
 	},
 }
+*/
+Type_Info :: union {
+	Named{name: string, base: ^Type_Info},
+	Integer{size: int, signed: bool},
+	Float{size: int},
+	String{},
+	Boolean{},
+	Any{},
+	Pointer{
+		elem: ^Type_Info, // nil -> rawptr
+	},
+	Procedure{
+		params:     ^Type_Info, // Type_Info.Tuple
+		results:    ^Type_Info, // Type_Info.Tuple
+		variadic:   bool,
+		convention: Calling_Convention,
+	},
+	Array{
+		elem:      ^Type_Info,
+		elem_size: int,
+		count:     int,
+	},
+	Dynamic_Array{elem: ^Type_Info, elem_size: int},
+	Slice        {elem: ^Type_Info, elem_size: int},
+	Vector       {elem: ^Type_Info, elem_size, count, align: int},
+	Tuple        {using record: Type_Info_Record}, // Only really used for procedures
+	Struct       {using record: Type_Info_Record},
+	Union        {using record: Type_Info_Record},
+	Raw_Union    {using record: Type_Info_Record},
+	Enum{
+		base:   ^Type_Info,
+		names:  []string,
+		values: []Type_Info_Enum_Value,
+	},
+	Map{
+		key:              ^Type_Info,
+		value:            ^Type_Info,
+		generated_struct: ^Type_Info,
+		count:            int, // == 0 if dynamic
+	},
+}
+
 
 // // NOTE(bill): only the ones that are needed (not all types)
 // // This will be set by the compiler

+ 67 - 13
src/check_expr.c

@@ -355,7 +355,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 
 				Token name_token = name->Ident;
 
-				if (str_eq(name_token.string, str_lit(""))) {
+				if (str_eq(name_token.string, str_lit("names"))) {
 					error(name_token, "`names` is a reserved identifier for unions");
 					continue;
 				}
@@ -596,22 +596,76 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
 	GB_ASSERT(is_type_union(union_type));
 	ast_node(ut, UnionType, node);
 
-	isize field_count = 1;
-	for_array(field_index, ut->fields) {
-		AstNode *field = ut->fields.e[field_index];
-		switch (field->kind) {
-		case_ast_node(f, Field, field);
-			field_count += f->names.count;
-		case_end;
-		}
-	}
+	isize field_count = ut->fields.count+1;
+
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+
+	MapEntity entity_map = {0};
+	map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count);
 
 	Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
 
-	check_fields(c, node, ut->fields, fields, field_count, str_lit("union"));
+	isize field_index = 0;
+	fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL);
+
+	for_array(i, ut->fields) {
+		AstNode *field = ut->fields.e[i];
+		if (field->kind != AstNode_UnionField) {
+			continue;
+		}
+		ast_node(f, UnionField, ut->fields.e[i]);
+		Token name_token = f->name->Ident;
+
+		if (str_eq(name_token.string, str_lit("names"))) {
+			error(name_token, "`names` is a reserved identifier for unions");
+			continue;
+		}
+
+		Type *base_type = make_type_struct(c->allocator);
+		{
+			ast_node(fl, FieldList, f->list);
+			isize field_count = 0;
+			for_array(j, fl->list) {
+				ast_node(f, Field, fl->list.e[j]);
+				field_count += f->names.count;
+			}
+
+			Token token = name_token;
+			token.kind = Token_struct;
+			AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, fl->list, field_count,
+			                                        false, true, NULL);
+
+			check_open_scope(c, dummy_struct);
+			check_struct_type(c, base_type, dummy_struct);
+			check_close_scope(c);
+			base_type->Record.node = dummy_struct;
+		}
+
+		Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
+		Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type);
+		type->Named.type_name = e;
+		add_entity(c, c->context.scope, f->name, e);
+
+		if (str_eq(name_token.string, str_lit("_"))) {
+			error(name_token, "`_` cannot be used a union subtype");
+			continue;
+		}
+
+		HashKey key = hash_string(name_token.string);
+		if (map_entity_get(&entity_map, key) != NULL) {
+			// TODO(bill): Scope checking already checks the declaration
+			error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
+		} else {
+			map_entity_set(&entity_map, key, e);
+			fields[field_index++] = e;
+		}
+		add_entity_use(c, f->name, e);
+	}
+
+	gb_temp_arena_memory_end(tmp);
 
-	union_type->Record.fields            = fields;
-	union_type->Record.field_count       = field_count;
+	union_type->Record.fields      = fields;
+	union_type->Record.field_count = field_index;
 	union_type->Record.names = make_names_field_for_record(c, c->context.scope);
 }
 

+ 1 - 1
src/gb/gb.h

@@ -705,7 +705,7 @@ extern "C++" {
 #endif
 
 #ifndef gb_is_between
-#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
+#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
 #endif
 
 #ifndef gb_abs

+ 47 - 21
src/ir.c

@@ -6467,10 +6467,11 @@ void ir_gen_tree(irGen *s) {
 				case Type_Tuple: {
 					ir_emit_comment(proc, str_lit("Type_Info_Tuple"));
 					tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr);
+					irValue *record = ir_emit_struct_ep(proc, tag, 0);
 
 					{
 						irValue *align = ir_make_const_int(a, type_align_of(a, t));
-						ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
 					}
 
 					irValue *memory_types   = ir_type_info_member_offset(proc, type_info_member_types,   t->Record.field_count, &type_info_member_types_index);
@@ -6490,14 +6491,15 @@ void ir_gen_tree(irGen *s) {
 						}
 					}
 
-					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
-					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
 				} break;
 				case Type_Record: {
 					switch (t->Record.kind) {
 					case TypeRecord_Struct: {
 						ir_emit_comment(proc, str_lit("Type_Info_Struct"));
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
+						irValue *record = ir_emit_struct_ep(proc, tag, 0);
 
 						{
 							irValue *size         = ir_make_const_int(a,  type_size_of(a, t));
@@ -6505,11 +6507,11 @@ void ir_gen_tree(irGen *s) {
 							irValue *packed       = ir_make_const_bool(a, t->Record.struct_is_packed);
 							irValue *ordered      = ir_make_const_bool(a, t->Record.struct_is_ordered);
 							irValue *custom_align = ir_make_const_bool(a, t->Record.custom_align);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), packed);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), ordered);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), custom_align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), packed);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 6), ordered);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 7), custom_align);
 						}
 
 						irValue *memory_types   = ir_type_info_member_offset(proc, type_info_member_types,   t->Record.field_count, &type_info_member_types_index);
@@ -6536,28 +6538,52 @@ void ir_gen_tree(irGen *s) {
 							ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
 						}
 
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
 					} break;
-					case TypeRecord_Union:
+					case TypeRecord_Union: {
 						ir_emit_comment(proc, str_lit("Type_Info_Union"));
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr);
+						irValue *record = ir_emit_struct_ep(proc, tag, 0);
 						{
 							irValue *size    = ir_make_const_int(a, type_size_of(a, t));
 							irValue *align   = ir_make_const_int(a, type_align_of(a, t));
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3),  size);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4),  align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3),  size);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4),  align);
 						}
-						break;
+
+						irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index);
+						irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index);
+
+						for (isize source_index = 1; source_index < t->Record.field_count; source_index++) {
+							// TODO(bill): Order fields in source order not layout order
+							Entity *f = t->Record.fields[source_index];
+							irValue *tip = ir_get_type_info_ptr(proc, type_info_data, f->type);
+							irValue *index     = ir_make_const_int(a, source_index);
+							irValue *type_info = ir_emit_ptr_offset(proc, memory_types,   index);
+
+							ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
+							if (f->token.string.len > 0) {
+								irValue *name = ir_emit_ptr_offset(proc, memory_names,   index);
+								ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+							}
+						}
+
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
+
+					} break;
 					case TypeRecord_RawUnion: {
 						ir_emit_comment(proc, str_lit("Type_Info_RawUnion"));
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr);
+						irValue *record = ir_emit_struct_ep(proc, tag, 0);
+
 						{
 							irValue *size    = ir_make_const_int(a, type_size_of(a, t));
 							irValue *align   = ir_make_const_int(a, type_align_of(a, t));
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3),  size);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4),  align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3),  size);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4),  align);
 						}
 
 						irValue *memory_types   = ir_type_info_member_offset(proc, type_info_member_types,   t->Record.field_count, &type_info_member_types_index);
@@ -6577,9 +6603,9 @@ void ir_gen_tree(irGen *s) {
 							}
 						}
 
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
 					} break;
 					case TypeRecord_Enum:
 						ir_emit_comment(proc, str_lit("Type_Info_Enum"));
@@ -6668,7 +6694,7 @@ void ir_gen_tree(irGen *s) {
 							break;
 						}
 					}
-					GB_ASSERT(found);
+					GB_ASSERT_MSG(found, "%s", type_to_string(tag_type));
 				}
 			}
 		}

+ 33 - 9
src/parser.c

@@ -306,6 +306,10 @@ AST_NODE_KIND(_DeclEnd,   "", i32) \
 		Token token; \
 		AstNodeArray list; \
 	}) \
+	AST_NODE_KIND(UnionField, "union field", struct { \
+		AstNode *name; \
+		AstNode *list; \
+	}) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
 	AST_NODE_KIND(HelperType, "type", struct { \
 		Token token; \
@@ -490,6 +494,8 @@ Token ast_node_token(AstNode *node) {
 		return ast_node_token(node->Field.type);
 	case AstNode_FieldList:
 		return node->FieldList.token;
+	case AstNode_UnionField:
+		return ast_node_token(node->UnionField.name);
 
 	case AstNode_HelperType:       return node->HelperType.token;
 	case AstNode_ProcType:         return node->ProcType.token;
@@ -965,6 +971,12 @@ AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) {
 	result->FieldList.list  = list;
 	return result;
 }
+AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
+	AstNode *result = make_ast_node(f, AstNode_UnionField);
+	result->UnionField.name = name;
+	result->UnionField.list = list;
+	return result;
+}
 
 
 AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
@@ -1016,7 +1028,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
 }
 
 AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count,
-                          bool is_packed, bool is_ordered, AstNode *align) {
+                         bool is_packed, bool is_ordered, AstNode *align) {
 	AstNode *result = make_ast_node(f, AstNode_StructType);
 	result->StructType.token       = token;
 	result->StructType.fields      = fields;
@@ -2670,17 +2682,29 @@ AstNode *parse_type_or_ident(AstFile *f) {
 	case Token_union: {
 		Token token = expect_token(f, Token_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "union");
-		isize decl_count = 0;
-		AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union"));
-		Token close = expect_token(f, Token_CloseBrace);
+		AstNodeArray variants = make_ast_node_array(f);
 
-		AstNodeArray decls = {0};
-		if (fields != NULL) {
-			GB_ASSERT(fields->kind == AstNode_FieldList);
-			decls = fields->FieldList.list;
+		while (f->curr_token.kind != Token_CloseBrace &&
+		       f->curr_token.kind != Token_EOF) {
+			AstNode *name  = parse_ident(f);
+			Token    open  = expect_token(f, Token_OpenBrace);
+			isize decl_count = 0;
+			AstNode *list  = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
+			Token    close = expect_token(f, Token_CloseBrace);
+
+			array_add(&variants, ast_union_field(f, name, list));
+
+			if (f->curr_token.kind != Token_Comma) {
+				break;
+			}
+			next_token(f);
 		}
 
-		return ast_union_type(f, token, decls, decl_count);
+		// AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union"));
+		Token close = expect_token(f, Token_CloseBrace);
+
+
+		return ast_union_type(f, token, variants, variants.count);
 	}
 
 	case Token_raw_union: {