Browse Source

Fix map internal type generation

Ginger Bill 8 years ago
parent
commit
fbd27d7c45
5 changed files with 92 additions and 60 deletions
  1. 71 48
      src/check_expr.cpp
  2. 1 1
      src/checker.cpp
  3. 15 5
      src/exact_value.cpp
  4. 2 3
      src/parser.cpp
  5. 3 3
      src/types.cpp

+ 71 - 48
src/check_expr.cpp

@@ -364,7 +364,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
 }
 }
 
 
 bool check_polymorphic_procedure_assignment(Checker *c, Operand *operand, Type *type, PolyProcData *poly_proc_data) {
 bool check_polymorphic_procedure_assignment(Checker *c, Operand *operand, Type *type, PolyProcData *poly_proc_data) {
-	if (operand->expr == NULL) return false;
+	if (operand->expr == nullptr) return false;
 	Entity *base_entity = entity_of_ident(&c->info, operand->expr);
 	Entity *base_entity = entity_of_ident(&c->info, operand->expr);
 	if (base_entity == nullptr) return false;
 	if (base_entity == nullptr) return false;
 	return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_proc_data);
 	return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_proc_data);
@@ -1356,7 +1356,6 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 				}
 				}
 			}
 			}
 			if (ok) {
 			if (ok) {
-				add_type_info_type(c, t);
 				array_add(&variants, t);
 				array_add(&variants, t);
 			}
 			}
 		}
 		}
@@ -1401,6 +1400,7 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 		return;
 		return;
 	}
 	}
 
 
+
 }
 }
 
 
 // void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
 // void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
@@ -2790,9 +2790,50 @@ Type *make_optional_ok_type(gbAllocator a, Type *value) {
 	return t;
 	return t;
 }
 }
 
 
-void generate_map_struct_type(gbAllocator a, Type *type) {
+void generate_map_entry_type(gbAllocator a, Type *type) {
+	GB_ASSERT(type->kind == Type_Map);
+	if (type->Map.entry_type != nullptr) return;
+
+	// NOTE(bill): The preload types may have not been set yet
+	GB_ASSERT(t_map_key != nullptr);
+
+	Type *entry_type = make_type_struct(a);
+
+	/*
+	struct {
+		hash:  Map_Key,
+		next:  int,
+		key:   Key_Type,
+		value: Value_Type,
+	}
+	*/
+	AstNode *dummy_node = gb_alloc_item(a, AstNode);
+	dummy_node->kind = AstNode_Invalid;
+	Scope *s = make_scope(universal_scope, a);
+
+	isize field_count = 3;
+	Array<Entity *> fields = {};
+	array_init(&fields, a, 3);
+	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("key")),   t_map_key,       false, 0));
+	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("next")),  t_int,           false, 1));
+	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("value")), type->Map.value, false, 2));
+
+
+	entry_type->Struct.fields              = fields;
+	entry_type->Struct.fields_in_src_order = fields;
+
+	// type_set_offsets(a, entry_type);
+	type->Map.entry_type = entry_type;
+}
+
+void generate_map_internal_types(gbAllocator a, Type *type) {
 	GB_ASSERT(type->kind == Type_Map);
 	GB_ASSERT(type->kind == Type_Map);
-	if (type->Map.generated_struct_type != NULL) return;
+	if (type->Map.generated_struct_type != nullptr) return;
+	generate_map_entry_type(a, type);
+	Type *key   = type->Map.key;
+	Type *value = type->Map.value;
+	GB_ASSERT(key != nullptr);
+	GB_ASSERT(value != nullptr);
 
 
 	Type *generated_struct_type = make_type_struct(a);
 	Type *generated_struct_type = make_type_struct(a);
 
 
@@ -2809,6 +2850,7 @@ void generate_map_struct_type(gbAllocator a, Type *type) {
 	Type *hashes_type  = make_type_dynamic_array(a, t_int);
 	Type *hashes_type  = make_type_dynamic_array(a, t_int);
 	Type *entries_type = make_type_dynamic_array(a, type->Map.entry_type);
 	Type *entries_type = make_type_dynamic_array(a, type->Map.entry_type);
 
 
+
 	Array<Entity *> fields = {};
 	Array<Entity *> fields = {};
 	array_init(&fields, a, 2);
 	array_init(&fields, a, 2);
 	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0));
 	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0));
@@ -2820,6 +2862,7 @@ void generate_map_struct_type(gbAllocator a, Type *type) {
 
 
 	type_set_offsets(a, generated_struct_type);
 	type_set_offsets(a, generated_struct_type);
 	type->Map.generated_struct_type = generated_struct_type;
 	type->Map.generated_struct_type = generated_struct_type;
+	type->Map.lookup_result_type = make_optional_ok_type(a, value);
 }
 }
 
 
 void check_map_type(Checker *c, Type *type, AstNode *node) {
 void check_map_type(Checker *c, Type *type, AstNode *node) {
@@ -2832,7 +2875,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 
 
 	if (!is_type_valid_for_keys(key)) {
 	if (!is_type_valid_for_keys(key)) {
 		if (is_type_boolean(key)) {
 		if (is_type_boolean(key)) {
-			error(node, "A boolean cannot be used as a key for a map");
+			error(node, "A boolean cannot be used as a key for a map, use an array instead for this case");
 		} else {
 		} else {
 			gbString str = type_to_string(key);
 			gbString str = type_to_string(key);
 			error(node, "Invalid type of a key for a map, got `%s`", str);
 			error(node, "Invalid type of a key for a map, got `%s`", str);
@@ -2849,46 +2892,9 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 	type->Map.key   = key;
 	type->Map.key   = key;
 	type->Map.value = value;
 	type->Map.value = value;
 
 
-	gbAllocator a = c->allocator;
-
-	{
-		// NOTE(bill): The preload types may have not been set yet
-		init_preload(c);
-		GB_ASSERT(t_map_key != nullptr);
-
-		Type *entry_type = make_type_struct(a);
 
 
-		/*
-		struct {
-			hash:  Map_Key,
-			next:  int,
-			key:   Key_Type,
-			value: Value_Type,
-		}
-		*/
-		AstNode *dummy_node = gb_alloc_item(a, AstNode);
-		dummy_node->kind = AstNode_Invalid;
-		check_open_scope(c, dummy_node);
-
-		isize field_count = 3;
-		Array<Entity *> fields = {};
-		array_init(&fields, a, 3);
-		array_add(&fields, make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")),   t_map_key, false, 0));
-		array_add(&fields, make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")),  t_int,     false, 1));
-		array_add(&fields, make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value,     false, 2));
-
-		check_close_scope(c);
-
-		entry_type->Struct.fields              = fields;
-		entry_type->Struct.fields_in_src_order = fields;
-
-		type_set_offsets(a, entry_type);
-		type->Map.entry_type = entry_type;
-	}
-
-	generate_map_struct_type(a, type);
-
-	type->Map.lookup_result_type = make_optional_ok_type(a, value);
+	init_preload(c);
+	generate_map_internal_types(c->allocator, type);
 
 
 	// error(node, "`map` types are not yet implemented");
 	// error(node, "`map` types are not yet implemented");
 }
 }
@@ -3244,7 +3250,6 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 		}
 		}
 		break;
 		break;
 
 
-	case Token_Add:
 	case Token_Mul:
 	case Token_Mul:
 	case Token_Quo:
 	case Token_Quo:
 	case Token_AddEq:
 	case Token_AddEq:
@@ -3256,6 +3261,19 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 		}
 		}
 		break;
 		break;
 
 
+	case Token_Add:
+		if (is_type_string(type)) {
+			if (o->mode == Addressing_Constant) {
+				return true;
+			}
+			error(op, "String concatenation is only allowed with constant strings");
+			return false;
+		} else if (!is_type_numeric(type)) {
+			error(op, "Operator `%.*s` is only allowed with numeric expressions", LIT(op.string));
+			return false;
+		}
+		break;
+
 	case Token_And:
 	case Token_And:
 	case Token_Or:
 	case Token_Or:
 	case Token_AndEq:
 	case Token_AndEq:
@@ -4140,7 +4158,9 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 		if (op.kind == Token_Quo && is_type_integer(type)) {
 		if (op.kind == Token_Quo && is_type_integer(type)) {
 			op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers
 			op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers
 		}
 		}
+
 		x->value = exact_binary_operator_value(op.kind, a, b);
 		x->value = exact_binary_operator_value(op.kind, a, b);
+
 		if (is_type_typed(type)) {
 		if (is_type_typed(type)) {
 			if (node != nullptr) {
 			if (node != nullptr) {
 				x->expr = node;
 				x->expr = node;
@@ -4148,6 +4168,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 			check_is_expressible(c, x, type);
 			check_is_expressible(c, x, type);
 		}
 		}
 		return;
 		return;
+	} else if (is_type_string(x->type)) {
+		error(node, "String concatenation is only allowed with constant strings");
+		x->mode = Addressing_Invalid;
+		return;
 	}
 	}
 
 
 	x->mode = Addressing_Value;
 	x->mode = Addressing_Value;
@@ -6478,7 +6502,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 				if (t == t_invalid) continue;
 				if (t == t_invalid) continue;
 				GB_ASSERT(t->kind == Type_Proc);
 				GB_ASSERT(t->kind == Type_Proc);
 				gbString pt;
 				gbString pt;
-				if (t->Proc.node != NULL) {
+				if (t->Proc.node != nullptr) {
 					pt = expr_to_string(t->Proc.node);
 					pt = expr_to_string(t->Proc.node);
 				} else {
 				} else {
 					pt = type_to_string(t);
 					pt = type_to_string(t);
@@ -6508,7 +6532,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 				TokenPos pos = proc->token.pos;
 				TokenPos pos = proc->token.pos;
 				Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc);
 				Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc);
 				gbString pt;
 				gbString pt;
-				if (t->Proc.node != NULL) {
+				if (t->Proc.node != nullptr) {
 					pt = expr_to_string(t->Proc.node);
 					pt = expr_to_string(t->Proc.node);
 				} else {
 				} else {
 					pt = type_to_string(t);
 					pt = type_to_string(t);
@@ -7749,7 +7773,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 			return kind;
 			return kind;
 		}
 		}
 
 
-
 		bool src_is_ptr = is_type_pointer(o->type);
 		bool src_is_ptr = is_type_pointer(o->type);
 		Type *src = type_deref(o->type);
 		Type *src = type_deref(o->type);
 		Type *dst = t;
 		Type *dst = t;

+ 1 - 1
src/checker.cpp

@@ -1182,7 +1182,7 @@ void add_type_info_type(Checker *c, Type *t) {
 	} break;
 	} break;
 
 
 	case Type_Map: {
 	case Type_Map: {
-		generate_map_struct_type(c->allocator, bt);
+		generate_map_internal_types(c->allocator, bt);
 		add_type_info_type(c, bt->Map.key);
 		add_type_info_type(c, bt->Map.key);
 		add_type_info_type(c, bt->Map.value);
 		add_type_info_type(c, bt->Map.value);
 		add_type_info_type(c, bt->Map.generated_struct_type);
 		add_type_info_type(c, bt->Map.generated_struct_type);

+ 15 - 5
src/exact_value.cpp

@@ -565,13 +565,23 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
 		}
 		}
 		return exact_value_complex(real, imag);
 		return exact_value_complex(real, imag);
 	} break;
 	} break;
+
+	case ExactValue_String: {
+		if (op != Token_Add) goto error;
+
+		// NOTE(bill): How do you minimize this over allocation?
+		String sx = x.value_string;
+		String sy = y.value_string;
+		isize len = sx.len+sy.len;
+		u8 *data = gb_alloc_array(heap_allocator(), u8, len);
+		gb_memmove(data,        sx.text, sx.len);
+		gb_memmove(data+sx.len, sy.text, sy.len);
+		return exact_value_string(make_string(data, len));
+	} break;
 	}
 	}
 
 
-error:
-	;		// MSVC accepts this??? apparently you cannot declare variables immediately after labels...
-	ExactValue error_value = {};
-	// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
-	return error_value;
+error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
+	return empty_exact_value;
 }
 }
 
 
 gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }
 gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }

+ 2 - 3
src/parser.cpp

@@ -2231,10 +2231,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 			// NOTE(bill): Allow neighbouring string literals to be merge together to
 			// NOTE(bill): Allow neighbouring string literals to be merge together to
 			// become one big string
 			// become one big string
 			String s = f->curr_token.string;
 			String s = f->curr_token.string;
-			Array<u8> data;
-			array_init(&data, heap_allocator(), token.string.len+s.len);
+			Array<u8> data = {};
+			array_init_count(&data, heap_allocator(), token.string.len+s.len);
 			gb_memmove(data.data, token.string.text, token.string.len);
 			gb_memmove(data.data, token.string.text, token.string.len);
-			data.count += token.string.len;
 
 
 			while (f->curr_token.kind == Token_String) {
 			while (f->curr_token.kind == Token_String) {
 				String s = f->curr_token.string;
 				String s = f->curr_token.string;

+ 3 - 3
src/types.cpp

@@ -390,7 +390,7 @@ i64      type_size_of            (gbAllocator allocator, Type *t);
 i64      type_align_of           (gbAllocator allocator, Type *t);
 i64      type_align_of           (gbAllocator allocator, Type *t);
 i64      type_offset_of          (gbAllocator allocator, Type *t, i32 index);
 i64      type_offset_of          (gbAllocator allocator, Type *t, i32 index);
 gbString type_to_string          (Type *type);
 gbString type_to_string          (Type *type);
-void     generate_map_struct_type(gbAllocator a, Type *type);
+void     generate_map_internal_types(gbAllocator a, Type *type);
 
 
 
 
 
 
@@ -1827,7 +1827,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 	case Type_Map: {
 	case Type_Map: {
 		if (t->Map.count == 0) { // Dynamic
 		if (t->Map.count == 0) { // Dynamic
 			// return build_context.word_size;
 			// return build_context.word_size;
-			generate_map_struct_type(allocator, t);
+			generate_map_internal_types(allocator, t);
 			return type_align_of_internal(allocator, t->Map.generated_struct_type, path);
 			return type_align_of_internal(allocator, t->Map.generated_struct_type, path);
 		}
 		}
 		GB_PANIC("TODO(bill): Fixed map alignment");
 		GB_PANIC("TODO(bill): Fixed map alignment");
@@ -2057,7 +2057,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 		if (t->Map.count == 0) { // Dynamic
 		if (t->Map.count == 0) { // Dynamic
 			// i64 da = 3*build_context.word_size + 2*build_context.word_size;
 			// i64 da = 3*build_context.word_size + 2*build_context.word_size;
 			// return 2 * da;
 			// return 2 * da;
-			generate_map_struct_type(allocator, t);
+			generate_map_internal_types(allocator, t);
 			return type_size_of_internal(allocator, t->Map.generated_struct_type, path);
 			return type_size_of_internal(allocator, t->Map.generated_struct_type, path);
 		}
 		}
 		GB_PANIC("TODO(bill): Fixed map size");
 		GB_PANIC("TODO(bill): Fixed map size");