diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 20dce4a47..106f1e9c7 100644 --- a/src/check_expr.cpp +++ b/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) { - if (operand->expr == NULL) return false; + if (operand->expr == nullptr) return false; Entity *base_entity = entity_of_ident(&c->info, operand->expr); if (base_entity == nullptr) return false; 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) { - add_type_info_type(c, t); array_add(&variants, t); } } @@ -1401,6 +1400,7 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n return; } + } // 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; } -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.generated_struct_type != NULL) return; + 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 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); + 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); @@ -2809,6 +2850,7 @@ void generate_map_struct_type(gbAllocator a, Type *type) { Type *hashes_type = make_type_dynamic_array(a, t_int); Type *entries_type = make_type_dynamic_array(a, type->Map.entry_type); + Array fields = {}; array_init(&fields, a, 2); 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->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) { @@ -2832,7 +2875,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { if (!is_type_valid_for_keys(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 { gbString str = type_to_string(key); 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.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 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"); } @@ -3244,7 +3250,6 @@ bool check_binary_op(Checker *c, Operand *o, Token op) { } break; - case Token_Add: case Token_Mul: case Token_Quo: case Token_AddEq: @@ -3256,6 +3261,19 @@ bool check_binary_op(Checker *c, Operand *o, Token op) { } 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_Or: 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)) { op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers } + x->value = exact_binary_operator_value(op.kind, a, b); + if (is_type_typed(type)) { if (node != nullptr) { x->expr = node; @@ -4148,6 +4168,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { check_is_expressible(c, x, type); } 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; @@ -6478,7 +6502,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t if (t == t_invalid) continue; GB_ASSERT(t->kind == Type_Proc); gbString pt; - if (t->Proc.node != NULL) { + if (t->Proc.node != nullptr) { pt = expr_to_string(t->Proc.node); } else { 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; Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc); gbString pt; - if (t->Proc.node != NULL) { + if (t->Proc.node != nullptr) { pt = expr_to_string(t->Proc.node); } else { pt = type_to_string(t); @@ -7749,7 +7773,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return kind; } - bool src_is_ptr = is_type_pointer(o->type); Type *src = type_deref(o->type); Type *dst = t; diff --git a/src/checker.cpp b/src/checker.cpp index d8da08dc9..ec907cc1d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1182,7 +1182,7 @@ void add_type_info_type(Checker *c, Type *t) { } break; 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.value); add_type_info_type(c, bt->Map.generated_struct_type); diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 3bee3cdb2..6966dbf73 100644 --- a/src/exact_value.cpp +++ b/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); } 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); } diff --git a/src/parser.cpp b/src/parser.cpp index 3612efe64..3b4155fb9 100644 --- a/src/parser.cpp +++ b/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 // become one big string String s = f->curr_token.string; - Array data; - array_init(&data, heap_allocator(), token.string.len+s.len); + Array data = {}; + array_init_count(&data, heap_allocator(), token.string.len+s.len); gb_memmove(data.data, token.string.text, token.string.len); - data.count += token.string.len; while (f->curr_token.kind == Token_String) { String s = f->curr_token.string; diff --git a/src/types.cpp b/src/types.cpp index abe66c7f7..4d0c368fa 100644 --- a/src/types.cpp +++ b/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_offset_of (gbAllocator allocator, Type *t, i32 index); 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: { if (t->Map.count == 0) { // Dynamic // 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); } 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 // i64 da = 3*build_context.word_size + 2*build_context.word_size; // 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); } GB_PANIC("TODO(bill): Fixed map size");