diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index c03fbacdb..48efc7e50 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -873,6 +873,49 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { } +stored_enum_value_to_string :: proc(enum_type: ^runtime.Type_Info, ev: runtime.Type_Info_Enum_Value, offset: int = 0) -> (string, bool) { + et := runtime.type_info_base(enum_type); + #partial switch e in et.variant { + case: return "", false; + case runtime.Type_Info_Enum: + get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) { + if reflect.is_string(e.base) { + for val, idx in e.values { + if v, ok := val.(T); ok && v == i { + return e.names[idx], true; + } + } + } else if len(e.values) == 0 { + return "", true; + } else { + for val, idx in e.values { + if v, ok := val.(T); ok && v == i { + return e.names[idx], true; + } + } + } + return "", false; + } + + switch v in ev { + case rune: return get_str(v + auto_cast offset, e); + case i8: return get_str(v + auto_cast offset, e); + case i16: return get_str(v + auto_cast offset, e); + case i32: return get_str(v + auto_cast offset, e); + case i64: return get_str(v + auto_cast offset, e); + case int: return get_str(v + auto_cast offset, e); + case u8: return get_str(v + auto_cast offset, e); + case u16: return get_str(v + auto_cast offset, e); + case u32: return get_str(v + auto_cast offset, e); + case u64: return get_str(v + auto_cast offset, e); + case uint: return get_str(v + auto_cast offset, e); + case uintptr: return get_str(v + auto_cast offset, e); + } + } + + return "", false; +} + enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 { switch i in ev { @@ -892,6 +935,24 @@ enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 { return 0; } +enum_value_to_i64 :: proc(ev: runtime.Type_Info_Enum_Value) -> i64 { + switch i in ev { + case rune: return i64(i); + case i8: return i64(i); + case i16: return i64(i); + case i32: return i64(i); + case i64: return i64(i); + case int: return i64(i); + case u8: return i64(i); + case u16: return i64(i); + case u32: return i64(i); + case u64: return i64(i); + case uint: return i64(i); + case uintptr: return i64(i); + } + return 0; +} + fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { if ti == nil { @@ -1241,6 +1302,25 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); } + case runtime.Type_Info_Enumerated_Array: + strings.write_byte(fi.buf, '['); + defer strings.write_byte(fi.buf, ']'); + for i in 0.. 0 do strings.write_string(fi.buf, ", "); + + idx, ok := stored_enum_value_to_string(info.index, info.min_value, i); + if ok { + strings.write_byte(fi.buf, '.'); + strings.write_string(fi.buf, idx); + } else { + strings.write_i64(fi.buf, enum_value_to_i64(info.min_value)+i64(i)); + } + strings.write_string(fi.buf, " = "); + + data := uintptr(v.data) + uintptr(i*info.elem_size); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + } + case runtime.Type_Info_Dynamic_Array: if verb == 'p' { slice := cast(^mem.Raw_Dynamic_Array)v.data; diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 05d959115..0c1b13e8f 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -20,6 +20,7 @@ Type_Kind :: enum { Pointer, Procedure, Array, + Enumerated_Array, Dynamic_Array, Slice, Tuple, @@ -51,6 +52,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case runtime.Type_Info_Pointer: return .Pointer; case runtime.Type_Info_Procedure: return .Procedure; case runtime.Type_Info_Array: return .Array; + case runtime.Type_Info_Enumerated_Array: return .Enumerated_Array; case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array; case runtime.Type_Info_Slice: return .Slice; case runtime.Type_Info_Tuple: return .Tuple; diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 9c382a8e3..42ab9828a 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -82,6 +82,13 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool { if x.count != y.count do return false; return are_types_identical(x.elem, y.elem); + case rt.Type_Info_Enumerated_Array: + y, ok := b.variant.(rt.Type_Info_Enumerated_Array); + if !ok do return false; + if x.count != y.count do return false; + return are_types_identical(x.index, y.index) && + are_types_identical(x.elem, y.elem); + case rt.Type_Info_Dynamic_Array: y, ok := b.variant.(rt.Type_Info_Dynamic_Array); if !ok do return false; @@ -397,6 +404,13 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { write_i64(buf, i64(info.count), 10); write_string(buf, "]"); write_type(buf, info.elem); + + case rt.Type_Info_Enumerated_Array: + write_string(buf, "["); + write_type(buf, info.index); + write_string(buf, "]"); + write_type(buf, info.elem); + case rt.Type_Info_Dynamic_Array: write_string(buf, "[dynamic]"); write_type(buf, info.elem); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index f9ffbdd62..e70f2a52f 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -79,6 +79,14 @@ Type_Info_Array :: struct { elem_size: int, count: int, }; +Type_Info_Enumerated_Array :: struct { + elem: ^Type_Info, + index: ^Type_Info, + elem_size: int, + count: int, + min_value: Type_Info_Enum_Value, + max_value: Type_Info_Enum_Value, +}; Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int}; Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int}; Type_Info_Tuple :: struct { // Only really used for procedures @@ -156,6 +164,7 @@ Type_Info :: struct { Type_Info_Pointer, Type_Info_Procedure, Type_Info_Array, + Type_Info_Enumerated_Array, Type_Info_Dynamic_Array, Type_Info_Slice, Type_Info_Tuple, diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 3f69580b8..dd86fb55e 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -172,6 +172,14 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { print_u64(fd, u64(info.count)); os.write_byte(fd, ']'); print_type(fd, info.elem); + + case Type_Info_Enumerated_Array: + os.write_byte(fd, '['); + print_type(fd, info.index); + os.write_byte(fd, ']'); + print_type(fd, info.elem); + + case Type_Info_Dynamic_Array: os.write_string(fd, "[dynamic]"); print_type(fd, info.elem); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bfee3d56a..2776b8d6d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3029,21 +3029,35 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { update_expr_type(c, operand->expr, target_type, true); } -bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 max_count, i64 *value) { +bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) { Operand operand = {Addressing_Invalid}; - check_expr(c, &operand, index_value); + check_expr_with_type_hint(c, &operand, index_value, type_hint); if (operand.mode == Addressing_Invalid) { if (value) *value = 0; return false; } - convert_to_typed(c, &operand, t_int); + Type *index_type = t_int; + if (type_hint != nullptr) { + index_type = type_hint; + } + convert_to_typed(c, &operand, index_type); if (operand.mode == Addressing_Invalid) { if (value) *value = 0; return false; } - if (!is_type_integer(operand.type) && !is_type_enum(operand.type)) { + if (type_hint != nullptr) { + if (!check_is_assignable_to(c, &operand, type_hint)) { + gbString expr_str = expr_to_string(operand.expr); + gbString index_type_str = type_to_string(type_hint); + error(operand.expr, "Index '%s' must be an enum of type '%s'", expr_str, index_type_str); + gb_string_free(index_type_str); + gb_string_free(expr_str); + if (value) *value = 0; + return false; + } + } else if (!is_type_integer(operand.type) && !is_type_enum(operand.type)) { gbString expr_str = expr_to_string(operand.expr); error(operand.expr, "Index '%s' must be an integer", expr_str); gb_string_free(expr_str); @@ -3054,7 +3068,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 if (operand.mode == Addressing_Constant && (c->state_flags & StateFlag_no_bounds_check) == 0) { BigInt i = exact_value_to_integer(operand.value).value_integer; - if (i.neg) { + if (i.neg && !is_type_enum(index_type)) { gbString expr_str = expr_to_string(operand.expr); error(operand.expr, "Index '%s' cannot be a negative value", expr_str); gb_string_free(expr_str); @@ -3062,31 +3076,66 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 return false; } - if (max_count >= 0) { // NOTE(bill): Do array bound checking - i64 v = -1; - if (i.len <= 1) { - v = big_int_to_i64(&i); - } - if (value) *value = v; - bool out_of_bounds = false; - if (open_range) { - out_of_bounds = v >= max_count; - } else { - out_of_bounds = v >= max_count+1; - } - if (v < 0) { - out_of_bounds = true; - } + if (max_count >= 0) { + if (is_type_enum(index_type)) { + Type *bt = base_type(index_type); + GB_ASSERT(bt->kind == Type_Enum); + ExactValue lo = bt->Enum.min_value; + ExactValue hi = bt->Enum.max_value; + String lo_str = {}; + String hi_str = {}; + if (bt->Enum.fields.count > 0) { + lo_str = bt->Enum.fields[bt->Enum.min_value_index]->token.string; + hi_str = bt->Enum.fields[bt->Enum.max_value_index]->token.string; + } - if (out_of_bounds) { - gbString expr_str = expr_to_string(operand.expr); - error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count); - gb_string_free(expr_str); - return false; - } + bool out_of_bounds = false; + + if (compare_exact_values(Token_Lt, operand.value, lo) || compare_exact_values(Token_Gt, operand.value, hi)) { + out_of_bounds = true; + } + + if (out_of_bounds) { + gbString expr_str = expr_to_string(operand.expr); + if (lo_str.len > 0) { + error(operand.expr, "Index '%s' is out of bounds range %.*s .. %.*s", expr_str, LIT(lo_str), LIT(hi_str)); + } else { + gbString index_type_str = type_to_string(index_type); + error(operand.expr, "Index '%s' is out of bounds range of enum type %s", expr_str, index_type_str); + gb_string_free(index_type_str); + } + gb_string_free(expr_str); + return false; + } + + return true; + + } else { // NOTE(bill): Do array bound checking + i64 v = -1; + if (i.len <= 1) { + v = big_int_to_i64(&i); + } + if (value) *value = v; + bool out_of_bounds = false; + if (open_range) { + out_of_bounds = v >= max_count; + } else { + out_of_bounds = v >= max_count+1; + } + if (v < 0) { + out_of_bounds = true; + } + + if (out_of_bounds) { + gbString expr_str = expr_to_string(operand.expr); + error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count); + gb_string_free(expr_str); + return false; + } - return true; + return true; + } } } @@ -3674,6 +3723,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 mode = Addressing_Constant; value = exact_value_i64(at->Array.count); type = t_untyped_integer; + } else if (is_type_enumerated_array(op_type) && id == BuiltinProc_len) { + Type *at = core_type(op_type); + mode = Addressing_Constant; + value = exact_value_i64(at->EnumeratedArray.count); + type = t_untyped_integer; } else if (is_type_slice(op_type) && id == BuiltinProc_len) { mode = Addressing_Value; } else if (is_type_dynamic_array(op_type)) { @@ -4313,7 +4367,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *original_type = operand->type; Type *type = base_type(operand->type); - if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + // Okay + } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str); gb_string_free(type_str); @@ -4361,6 +4417,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = original_type; operand->value = type->Enum.min_value; return true; + } else if (is_type_enumerated_array(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_EnumeratedArray); + operand->mode = Addressing_Constant; + operand->type = bt->EnumeratedArray.index; + operand->value = bt->EnumeratedArray.min_value; + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -4471,7 +4534,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *original_type = operand->type; Type *type = base_type(operand->type); - if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { + + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + // Okay + } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str); gb_string_free(type_str); @@ -4524,6 +4590,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = original_type; operand->value = type->Enum.max_value; return true; + } else if (is_type_enumerated_array(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_EnumeratedArray); + operand->mode = Addressing_Constant; + operand->type = bt->EnumeratedArray.index; + operand->value = bt->EnumeratedArray.max_value; + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -6841,6 +6914,17 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count, o->type = t->Array.elem; return true; + case Type_EnumeratedArray: + *max_count = t->EnumeratedArray.count; + if (indirection) { + o->mode = Addressing_Variable; + } else if (o->mode != Addressing_Variable && + o->mode != Addressing_Constant) { + o->mode = Addressing_Value; + } + o->type = t->EnumeratedArray.elem; + return true; + case Type_Slice: o->type = t->Slice.elem; if (o->mode != Addressing_Constant) { @@ -6896,18 +6980,18 @@ bool ternary_compare_types(Type *x, Type *y) { } -bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_) { +bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { if (!is_ast_range(node)) { return false; } ast_node(ie, BinaryExpr, node); - check_expr(c, x, ie->left); + check_expr_with_type_hint(c, x, ie->left, type_hint); if (x->mode == Addressing_Invalid) { return false; } - check_expr(c, y, ie->right); + check_expr_with_type_hint(c, y, ie->right, type_hint); if (y->mode == Addressing_Invalid) { return false; } @@ -7630,6 +7714,218 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type break; } + case Type_EnumeratedArray: + { + Type *elem_type = t->EnumeratedArray.elem; + Type *index_type = t->EnumeratedArray.index; + String context_name = str_lit("enumerated array literal"); + i64 max_type_count = t->EnumeratedArray.count; + + gbString index_type_str = type_to_string(index_type); + defer (gb_string_free(index_type_str)); + + i64 total_lo = exact_value_to_i64(t->EnumeratedArray.min_value); + i64 total_hi = exact_value_to_i64(t->EnumeratedArray.max_value); + + String total_lo_string = {}; + String total_hi_string = {}; + GB_ASSERT(is_type_enum(index_type)); + { + Type *bt = base_type(index_type); + GB_ASSERT(bt->kind == Type_Enum); + for_array(i, bt->Enum.fields) { + Entity *f = bt->Enum.fields[i]; + if (f->kind != Entity_Constant) { + continue; + } + if (total_lo_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, t->EnumeratedArray.min_value)) { + total_lo_string = f->token.string; + } + if (total_hi_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, t->EnumeratedArray.max_value)) { + total_hi_string = f->token.string; + } + if (total_lo_string.len != 0 && total_hi_string.len != 0) { + break; + } + } + } + + i64 max = 0; + + Type *bet = base_type(elem_type); + if (!elem_type_can_be_constant(bet)) { + is_constant = false; + } + + if (bet == t_invalid) { + break; + } + + if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { + RangeCache rc = range_cache_make(heap_allocator()); + defer (range_cache_destroy(&rc)); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + + if (is_ast_range(fv->field)) { + Token op = fv->field->BinaryExpr.op; + + Operand x = {}; + Operand y = {}; + bool ok = check_range(c, fv->field, &x, &y, nullptr, index_type); + if (!ok) { + continue; + } + if (x.mode != Addressing_Constant || !are_types_identical(x.type, index_type)) { + error(x.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); + continue; + } + + if (y.mode != Addressing_Constant || !are_types_identical(x.type, index_type)) { + error(y.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); + continue; + } + + i64 lo = exact_value_to_i64(x.value); + i64 hi = exact_value_to_i64(y.value); + i64 max_index = hi; + if (op.kind == Token_RangeHalf) { + hi -= 1; + } + + bool new_range = range_cache_add_range(&rc, lo, hi); + if (!new_range) { + gbString lo_str = expr_to_string(x.expr); + gbString hi_str = expr_to_string(y.expr); + error(elem, "Overlapping field range index %s %.*s %s for %.*s", lo_str, LIT(op.string), hi_str, LIT(context_name)); + gb_string_free(hi_str); + gb_string_free(lo_str); + continue; + } + + + // NOTE(bill): These are sanity checks for invalid enum values + if (max_type_count >= 0 && (lo < total_lo || lo >= total_hi)) { + gbString lo_str = expr_to_string(x.expr); + error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", lo_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); + gb_string_free(lo_str); + continue; + } + if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { + gbString hi_str = expr_to_string(y.expr); + error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", hi_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); + gb_string_free(hi_str); + continue; + } + + if (max < hi) { + max = max_index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } else { + Operand op_index = {}; + check_expr_with_type_hint(c, &op_index, fv->field, index_type); + + if (op_index.mode != Addressing_Constant || !are_types_identical(op_index.type, index_type)) { + error(op_index.expr, "Expected a constant enum of type '%s' as an array field", index_type_str); + continue; + } + + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < total_lo || index >= total_hi)) { + gbString idx_str = expr_to_string(op_index.expr); + error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", idx_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); + gb_string_free(idx_str); + continue; + } + + bool new_index = range_cache_add_index(&rc, index); + if (!new_index) { + gbString idx_str = expr_to_string(op_index.expr); + error(elem, "Duplicate field index %s for %.*s", idx_str, LIT(context_name)); + gb_string_free(idx_str); + continue; + } + + if (max < index+1) { + max = index+1; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + } + + cl->max_count = max; + + } else { + isize index = 0; + for (; index < cl->elems.count; index++) { + Ast *e = cl->elems[index]; + if (e == nullptr) { + error(node, "Invalid literal element"); + continue; + } + + if (e->kind == Ast_FieldValue) { + error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + + if (0 <= max_type_count && max_type_count <= index) { + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, e, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + + if (max < index) { + max = index; + } + } + + + if (t->kind == Type_Array) { + if (is_to_be_determined_array_count) { + t->Array.count = max; + } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->Array.count) { + error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); + } + } + } + + + if (t->kind == Type_SimdVector) { + if (!is_constant) { + error(node, "Expected all constant elements for a simd vector"); + } + if (t->SimdVector.is_x86_mmx) { + error(node, "Compound literals are not allowed with intrinsics.x86_mmx"); + } + } + break; + } + case Type_Basic: { if (!is_type_any(t)) { if (cl->elems.count != 0) { @@ -8135,8 +8431,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type return kind; } + Type *index_type_hint = nullptr; + if (is_type_enumerated_array(t)) { + Type *bt = base_type(t); + GB_ASSERT(bt->kind == Type_EnumeratedArray); + index_type_hint = bt->EnumeratedArray.index; + } + i64 index = 0; - bool ok = check_index_value(c, false, ie->index, max_count, &index); + bool ok = check_index_value(c, false, ie->index, max_count, &index, index_type_hint); node->viral_state_flags |= ie->index->viral_state_flags; case_end; diff --git a/src/check_type.cpp b/src/check_type.cpp index 9b86ff129..0b7843993 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -803,6 +803,8 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast ExactValue iota = exact_value_i64(-1); ExactValue min_value = exact_value_i64(0); ExactValue max_value = exact_value_i64(0); + isize min_value_index = 0; + isize max_value_index = 0; bool min_value_set = false; bool max_value_set = false; @@ -858,17 +860,21 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast if (min_value_set) { if (compare_exact_values(Token_Gt, min_value, iota)) { + min_value_index = i; min_value = iota; } } else { + min_value_index = i; min_value = iota; min_value_set = true; } if (max_value_set) { if (compare_exact_values(Token_Lt, max_value, iota)) { + max_value_index = i; max_value = iota; } } else { + max_value_index = i; max_value = iota; max_value_set = true; } @@ -894,6 +900,9 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope); enum_type->Enum.min_value = min_value; enum_type->Enum.max_value = max_value; + + enum_type->Enum.min_value_index = min_value_index; + enum_type->Enum.max_value_index = max_value_index; } @@ -2564,6 +2573,12 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) { return 0; } } + if (o->mode == Addressing_Type) { + if (is_type_enum(o->type)) { + return -1; + } + } + if (o->mode != Addressing_Constant) { if (o->mode != Addressing_Invalid) { o->mode = Addressing_Invalid; @@ -3214,14 +3229,33 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t Operand o = {}; i64 count = check_array_count(ctx, &o, at->count); Type *generic_type = nullptr; + + Type *elem = check_type_expr(ctx, at->elem, nullptr); + if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { generic_type = o.type; + } else if (is_type_enum(o.type)) { + Type *index = o.type; + Type *bt = base_type(index); + GB_ASSERT(bt->kind == Type_Enum); + + Type *t = alloc_type_enumerated_array(elem, index, bt->Enum.min_value, bt->Enum.max_value, Token_Invalid); + + 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)); + } + *type = t; + + goto array_end; } + if (count < 0) { error(at->count, "? can only be used in conjuction with compound literals"); count = 0; } - Type *elem = check_type_expr(ctx, at->elem, nullptr); + if (at->tag != nullptr) { GB_ASSERT(at->tag->kind == Ast_BasicDirective); diff --git a/src/checker.cpp b/src/checker.cpp index ec6e5d4d0..682588d42 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1299,6 +1299,14 @@ void add_type_info_type(CheckerContext *c, Type *t) { add_type_info_type(c, alloc_type_pointer(bt->Array.elem)); add_type_info_type(c, t_int); break; + + case Type_EnumeratedArray: + add_type_info_type(c, bt->EnumeratedArray.index); + add_type_info_type(c, t_int); + add_type_info_type(c, bt->EnumeratedArray.elem); + add_type_info_type(c, alloc_type_pointer(bt->EnumeratedArray.elem)); + break; + case Type_DynamicArray: add_type_info_type(c, bt->DynamicArray.elem); add_type_info_type(c, alloc_type_pointer(bt->DynamicArray.elem)); @@ -1508,6 +1516,13 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, alloc_type_pointer(bt->Array.elem)); add_min_dep_type_info(c, t_int); break; + case Type_EnumeratedArray: + add_min_dep_type_info(c, bt->EnumeratedArray.index); + add_min_dep_type_info(c, bt->EnumeratedArray.elem); + add_min_dep_type_info(c, alloc_type_pointer(bt->EnumeratedArray.elem)); + add_min_dep_type_info(c, t_int); + break; + case Type_DynamicArray: add_min_dep_type_info(c, bt->DynamicArray.elem); add_min_dep_type_info(c, alloc_type_pointer(bt->DynamicArray.elem)); @@ -1957,55 +1972,57 @@ void init_core_type_info(Checker *c) { Type *tiv_type = type_info_variant->type; GB_ASSERT(is_type_union(tiv_type)); - t_type_info_named = find_core_type(c, str_lit("Type_Info_Named")); - t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer")); - t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune")); - t_type_info_float = find_core_type(c, str_lit("Type_Info_Float")); - t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion")); - t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex")); - t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); - t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); - t_type_info_any = find_core_type(c, str_lit("Type_Info_Any")); - t_type_info_typeid = find_core_type(c, str_lit("Type_Info_Type_Id")); - t_type_info_pointer = find_core_type(c, str_lit("Type_Info_Pointer")); - t_type_info_procedure = find_core_type(c, str_lit("Type_Info_Procedure")); - t_type_info_array = find_core_type(c, str_lit("Type_Info_Array")); - t_type_info_dynamic_array = find_core_type(c, str_lit("Type_Info_Dynamic_Array")); - t_type_info_slice = find_core_type(c, str_lit("Type_Info_Slice")); - t_type_info_tuple = find_core_type(c, str_lit("Type_Info_Tuple")); - t_type_info_struct = find_core_type(c, str_lit("Type_Info_Struct")); - t_type_info_union = find_core_type(c, str_lit("Type_Info_Union")); - t_type_info_enum = find_core_type(c, str_lit("Type_Info_Enum")); - t_type_info_map = find_core_type(c, str_lit("Type_Info_Map")); - t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field")); - t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set")); - t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque")); - t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector")); + t_type_info_named = find_core_type(c, str_lit("Type_Info_Named")); + t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer")); + t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune")); + t_type_info_float = find_core_type(c, str_lit("Type_Info_Float")); + t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion")); + t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex")); + t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); + t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); + t_type_info_any = find_core_type(c, str_lit("Type_Info_Any")); + t_type_info_typeid = find_core_type(c, str_lit("Type_Info_Type_Id")); + t_type_info_pointer = find_core_type(c, str_lit("Type_Info_Pointer")); + t_type_info_procedure = find_core_type(c, str_lit("Type_Info_Procedure")); + t_type_info_array = find_core_type(c, str_lit("Type_Info_Array")); + t_type_info_enumerated_array = find_core_type(c, str_lit("Type_Info_Enumerated_Array")); + t_type_info_dynamic_array = find_core_type(c, str_lit("Type_Info_Dynamic_Array")); + t_type_info_slice = find_core_type(c, str_lit("Type_Info_Slice")); + t_type_info_tuple = find_core_type(c, str_lit("Type_Info_Tuple")); + t_type_info_struct = find_core_type(c, str_lit("Type_Info_Struct")); + t_type_info_union = find_core_type(c, str_lit("Type_Info_Union")); + t_type_info_enum = find_core_type(c, str_lit("Type_Info_Enum")); + t_type_info_map = find_core_type(c, str_lit("Type_Info_Map")); + t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field")); + t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set")); + t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque")); + t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector")); - t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); - t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); - t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune); - t_type_info_float_ptr = alloc_type_pointer(t_type_info_float); - t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion); - t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex); - t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); - t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); - t_type_info_any_ptr = alloc_type_pointer(t_type_info_any); - t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid); - t_type_info_pointer_ptr = alloc_type_pointer(t_type_info_pointer); - t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure); - t_type_info_array_ptr = alloc_type_pointer(t_type_info_array); - t_type_info_dynamic_array_ptr = alloc_type_pointer(t_type_info_dynamic_array); - t_type_info_slice_ptr = alloc_type_pointer(t_type_info_slice); - t_type_info_tuple_ptr = alloc_type_pointer(t_type_info_tuple); - t_type_info_struct_ptr = alloc_type_pointer(t_type_info_struct); - t_type_info_union_ptr = alloc_type_pointer(t_type_info_union); - t_type_info_enum_ptr = alloc_type_pointer(t_type_info_enum); - t_type_info_map_ptr = alloc_type_pointer(t_type_info_map); - t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field); - t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set); - t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque); - t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector); + t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); + t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); + t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune); + t_type_info_float_ptr = alloc_type_pointer(t_type_info_float); + t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion); + t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex); + t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); + t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); + t_type_info_any_ptr = alloc_type_pointer(t_type_info_any); + t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid); + t_type_info_pointer_ptr = alloc_type_pointer(t_type_info_pointer); + t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure); + t_type_info_array_ptr = alloc_type_pointer(t_type_info_array); + t_type_info_enumerated_array_ptr = alloc_type_pointer(t_type_info_enumerated_array); + t_type_info_dynamic_array_ptr = alloc_type_pointer(t_type_info_dynamic_array); + t_type_info_slice_ptr = alloc_type_pointer(t_type_info_slice); + t_type_info_tuple_ptr = alloc_type_pointer(t_type_info_tuple); + t_type_info_struct_ptr = alloc_type_pointer(t_type_info_struct); + t_type_info_union_ptr = alloc_type_pointer(t_type_info_union); + t_type_info_enum_ptr = alloc_type_pointer(t_type_info_enum); + t_type_info_map_ptr = alloc_type_pointer(t_type_info_map); + t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field); + t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set); + t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque); + t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector); } void init_mem_allocator(Checker *c) { diff --git a/src/ir.cpp b/src/ir.cpp index 4d29396a3..97ab4649f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1148,9 +1148,14 @@ irValue *ir_instr_array_element_ptr(irProcedure *p, irValue *address, irValue *e Type *t = ir_type(address); GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); t = base_type(type_deref(t)); - GB_ASSERT(is_type_array(t)); + GB_ASSERT(is_type_array(t) || is_type_enumerated_array(t)); - Type *result_type = alloc_type_pointer(t->Array.elem); + Type *result_type = nullptr; + if (t->kind == Type_Array) { + result_type = alloc_type_pointer(t->Array.elem); + } else if (t->kind == Type_EnumeratedArray) { + result_type = alloc_type_pointer(t->EnumeratedArray.elem); + } i->ArrayElementPtr.address = address; i->ArrayElementPtr.elem_index = elem_index; @@ -4680,7 +4685,7 @@ irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index) { Type *t = ir_type(s); GB_ASSERT(is_type_pointer(t)); Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st), "%s", type_to_string(st)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); // NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32 index = ir_emit_conv(proc, index, t_i32); @@ -7956,6 +7961,43 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { return ir_addr(elem); } + case Type_EnumeratedArray: { + irValue *array = nullptr; + if (using_addr != nullptr) { + array = using_addr; + } else { + array = ir_build_addr_ptr(proc, ie->expr); + if (deref) { + array = ir_emit_load(proc, array); + } + } + + Type *index_type = t->EnumeratedArray.index; + + auto index_tv = type_and_value_of_expr(ie->index); + + irValue *index = nullptr; + if (compare_exact_values(Token_NotEq, t->EnumeratedArray.min_value, exact_value_i64(0))) { + if (index_tv.mode == Addressing_Constant) { + ExactValue idx = exact_value_sub(index_tv.value, t->EnumeratedArray.min_value); + index = ir_value_constant(index_type, idx); + } else { + index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + index = ir_emit_arith(proc, Token_Sub, index, ir_value_constant(index_type, t->EnumeratedArray.min_value), index_type); + } + } else { + index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + } + + irValue *elem = ir_emit_array_ep(proc, array, index); + + if (index_tv.mode != Addressing_Constant) { + irValue *len = ir_const_int(t->EnumeratedArray.count); + ir_emit_bounds_check(proc, ast_token(ie->index), index, len); + } + return ir_addr(elem); + } + case Type_Slice: { irValue *slice = nullptr; if (using_addr != nullptr) { @@ -11055,6 +11097,32 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info break; } + case Type_EnumeratedArray: { + ir_emit_comment(proc, str_lit("Type_Info_Enumerated_Array")); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_enumerated_array_ptr); + irValue *elem = ir_get_type_info_ptr(proc, t->EnumeratedArray.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), elem); + + irValue *index = ir_get_type_info_ptr(proc, t->EnumeratedArray.index); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), index); + + i64 ez = type_size_of(t->EnumeratedArray.elem); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 2); + ir_emit_store(proc, elem_size, ir_const_int(ez)); + + irValue *count = ir_emit_struct_ep(proc, tag, 3); + ir_emit_store(proc, count, ir_const_int(t->EnumeratedArray.count)); + + irValue *min_value = ir_emit_struct_ep(proc, tag, 4); + irValue *max_value = ir_emit_struct_ep(proc, tag, 5); + + irValue *min_v = ir_value_constant(core_type(t->EnumeratedArray.index), t->EnumeratedArray.min_value); + irValue *max_v = ir_value_constant(core_type(t->EnumeratedArray.index), t->EnumeratedArray.max_value); + + ir_emit_store_union_variant(proc, min_value, min_v, ir_type(min_v)); + ir_emit_store_union_variant(proc, max_value, max_v, ir_type(max_v)); + break; + } case Type_DynamicArray: { ir_emit_comment(proc, str_lit("Type_Info_Dynamic_Array")); tag = ir_emit_conv(proc, variant_ptr, t_type_info_dynamic_array_ptr); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 35116fb69..f6eacf146 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -457,6 +457,14 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { ir_print_type(f, m, t->Array.elem); ir_write_byte(f, ']'); return; + case Type_EnumeratedArray: + ir_write_byte(f, '['); + ir_write_i64(f, t->EnumeratedArray.count); + ir_write_str_lit(f, " x "); + ir_print_type(f, m, t->EnumeratedArray.elem); + ir_write_byte(f, ']'); + return; + case Type_Slice: ir_write_byte(f, '{'); ir_print_type(f, m, t->Slice.elem); ir_write_str_lit(f, "*, "); @@ -972,6 +980,100 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_print_compound_element(f, m, empty_exact_value, elem_type); } + ir_write_byte(f, ']'); + } + } else if (is_type_enumerated_array(type)) { + ast_node(cl, CompoundLit, value.value_compound); + + Type *index_type = type->EnumeratedArray.elem; + Type *elem_type = type->Array.elem; + isize elem_count = cl->elems.count; + if (elem_count == 0) { + ir_write_str_lit(f, "zeroinitializer"); + break; + } + if (cl->elems[0]->kind == Ast_FieldValue) { + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + ir_write_byte(f, '['); + + i64 total_lo = exact_value_to_i64(type->EnumeratedArray.min_value); + i64 total_hi = exact_value_to_i64(type->EnumeratedArray.max_value); + + for (i64 i = total_lo; i <= total_hi; i++) { + if (i > total_lo) ir_write_str_lit(f, ", "); + + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + for (i64 k = lo; k < hi; k++) { + if (k > lo) ir_write_str_lit(f, ", "); + + ir_print_compound_element(f, m, tav.value, elem_type); + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + ir_print_compound_element(f, m, tav.value, elem_type); + found = true; + break; + } + } + } + + if (!found) { + ir_print_type(f, m, elem_type); + ir_write_byte(f, ' '); + ir_write_str_lit(f, "zeroinitializer"); + } + } + ir_write_byte(f, ']'); + } else { + GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); + + ir_write_byte(f, '['); + + for (isize i = 0; i < elem_count; i++) { + if (i > 0) ir_write_str_lit(f, ", "); + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + ir_print_compound_element(f, m, tav.value, elem_type); + } + for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { + if (i >= elem_count) ir_write_str_lit(f, ", "); + ir_print_compound_element(f, m, empty_exact_value, elem_type); + } + ir_write_byte(f, ']'); } } else if (is_type_simd_vector(type)) { diff --git a/src/types.cpp b/src/types.cpp index c02bf7dd2..f4423ba69 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -177,6 +177,14 @@ struct TypeUnion { i64 count; \ Type *generic_count; \ }) \ + TYPE_KIND(EnumeratedArray, struct { \ + Type *elem; \ + Type *index; \ + ExactValue min_value; \ + ExactValue max_value; \ + i64 count; \ + TokenKind op; \ + }) \ TYPE_KIND(Slice, struct { Type *elem; }) \ TYPE_KIND(DynamicArray, struct { Type *elem; }) \ TYPE_KIND(Map, struct { \ @@ -197,6 +205,8 @@ struct TypeUnion { Type * base_type; \ ExactValue min_value; \ ExactValue max_value; \ + isize min_value_index; \ + isize max_value_index; \ }) \ TYPE_KIND(Tuple, struct { \ Array variables; /* Entity_Variable */ \ @@ -489,73 +499,75 @@ gb_global Type *t_string_slice = nullptr; // Type generated for the "preload" file -gb_global Type *t_type_info = nullptr; -gb_global Type *t_type_info_enum_value = nullptr; -gb_global Type *t_type_info_ptr = nullptr; -gb_global Type *t_type_info_enum_value_ptr = nullptr; +gb_global Type *t_type_info = nullptr; +gb_global Type *t_type_info_enum_value = nullptr; +gb_global Type *t_type_info_ptr = nullptr; +gb_global Type *t_type_info_enum_value_ptr = nullptr; -gb_global Type *t_type_info_named = nullptr; -gb_global Type *t_type_info_integer = nullptr; -gb_global Type *t_type_info_rune = nullptr; -gb_global Type *t_type_info_float = nullptr; -gb_global Type *t_type_info_complex = nullptr; -gb_global Type *t_type_info_quaternion = nullptr; -gb_global Type *t_type_info_any = nullptr; -gb_global Type *t_type_info_typeid = nullptr; -gb_global Type *t_type_info_string = nullptr; -gb_global Type *t_type_info_boolean = nullptr; -gb_global Type *t_type_info_pointer = nullptr; -gb_global Type *t_type_info_procedure = nullptr; -gb_global Type *t_type_info_array = nullptr; -gb_global Type *t_type_info_dynamic_array = nullptr; -gb_global Type *t_type_info_slice = nullptr; -gb_global Type *t_type_info_tuple = nullptr; -gb_global Type *t_type_info_struct = nullptr; -gb_global Type *t_type_info_union = nullptr; -gb_global Type *t_type_info_enum = nullptr; -gb_global Type *t_type_info_map = nullptr; -gb_global Type *t_type_info_bit_field = nullptr; -gb_global Type *t_type_info_bit_set = nullptr; -gb_global Type *t_type_info_opaque = nullptr; -gb_global Type *t_type_info_simd_vector = nullptr; +gb_global Type *t_type_info_named = nullptr; +gb_global Type *t_type_info_integer = nullptr; +gb_global Type *t_type_info_rune = nullptr; +gb_global Type *t_type_info_float = nullptr; +gb_global Type *t_type_info_complex = nullptr; +gb_global Type *t_type_info_quaternion = nullptr; +gb_global Type *t_type_info_any = nullptr; +gb_global Type *t_type_info_typeid = nullptr; +gb_global Type *t_type_info_string = nullptr; +gb_global Type *t_type_info_boolean = nullptr; +gb_global Type *t_type_info_pointer = nullptr; +gb_global Type *t_type_info_procedure = nullptr; +gb_global Type *t_type_info_array = nullptr; +gb_global Type *t_type_info_enumerated_array = nullptr; +gb_global Type *t_type_info_dynamic_array = nullptr; +gb_global Type *t_type_info_slice = nullptr; +gb_global Type *t_type_info_tuple = nullptr; +gb_global Type *t_type_info_struct = nullptr; +gb_global Type *t_type_info_union = nullptr; +gb_global Type *t_type_info_enum = nullptr; +gb_global Type *t_type_info_map = nullptr; +gb_global Type *t_type_info_bit_field = nullptr; +gb_global Type *t_type_info_bit_set = nullptr; +gb_global Type *t_type_info_opaque = nullptr; +gb_global Type *t_type_info_simd_vector = nullptr; -gb_global Type *t_type_info_named_ptr = nullptr; -gb_global Type *t_type_info_integer_ptr = nullptr; -gb_global Type *t_type_info_rune_ptr = nullptr; -gb_global Type *t_type_info_float_ptr = nullptr; -gb_global Type *t_type_info_complex_ptr = nullptr; -gb_global Type *t_type_info_quaternion_ptr = nullptr; -gb_global Type *t_type_info_any_ptr = nullptr; -gb_global Type *t_type_info_typeid_ptr = nullptr; -gb_global Type *t_type_info_string_ptr = nullptr; -gb_global Type *t_type_info_boolean_ptr = nullptr; -gb_global Type *t_type_info_pointer_ptr = nullptr; -gb_global Type *t_type_info_procedure_ptr = nullptr; -gb_global Type *t_type_info_array_ptr = nullptr; -gb_global Type *t_type_info_dynamic_array_ptr = nullptr; -gb_global Type *t_type_info_slice_ptr = nullptr; -gb_global Type *t_type_info_tuple_ptr = nullptr; -gb_global Type *t_type_info_struct_ptr = nullptr; -gb_global Type *t_type_info_union_ptr = nullptr; -gb_global Type *t_type_info_enum_ptr = nullptr; -gb_global Type *t_type_info_map_ptr = nullptr; -gb_global Type *t_type_info_bit_field_ptr = nullptr; -gb_global Type *t_type_info_bit_set_ptr = nullptr; -gb_global Type *t_type_info_opaque_ptr = nullptr; -gb_global Type *t_type_info_simd_vector_ptr = nullptr; +gb_global Type *t_type_info_named_ptr = nullptr; +gb_global Type *t_type_info_integer_ptr = nullptr; +gb_global Type *t_type_info_rune_ptr = nullptr; +gb_global Type *t_type_info_float_ptr = nullptr; +gb_global Type *t_type_info_complex_ptr = nullptr; +gb_global Type *t_type_info_quaternion_ptr = nullptr; +gb_global Type *t_type_info_any_ptr = nullptr; +gb_global Type *t_type_info_typeid_ptr = nullptr; +gb_global Type *t_type_info_string_ptr = nullptr; +gb_global Type *t_type_info_boolean_ptr = nullptr; +gb_global Type *t_type_info_pointer_ptr = nullptr; +gb_global Type *t_type_info_procedure_ptr = nullptr; +gb_global Type *t_type_info_array_ptr = nullptr; +gb_global Type *t_type_info_enumerated_array_ptr = nullptr; +gb_global Type *t_type_info_dynamic_array_ptr = nullptr; +gb_global Type *t_type_info_slice_ptr = nullptr; +gb_global Type *t_type_info_tuple_ptr = nullptr; +gb_global Type *t_type_info_struct_ptr = nullptr; +gb_global Type *t_type_info_union_ptr = nullptr; +gb_global Type *t_type_info_enum_ptr = nullptr; +gb_global Type *t_type_info_map_ptr = nullptr; +gb_global Type *t_type_info_bit_field_ptr = nullptr; +gb_global Type *t_type_info_bit_set_ptr = nullptr; +gb_global Type *t_type_info_opaque_ptr = nullptr; +gb_global Type *t_type_info_simd_vector_ptr = nullptr; -gb_global Type *t_allocator = nullptr; -gb_global Type *t_allocator_ptr = nullptr; -gb_global Type *t_context = nullptr; -gb_global Type *t_context_ptr = nullptr; +gb_global Type *t_allocator = nullptr; +gb_global Type *t_allocator_ptr = nullptr; +gb_global Type *t_context = nullptr; +gb_global Type *t_context_ptr = nullptr; -gb_global Type *t_source_code_location = nullptr; -gb_global Type *t_source_code_location_ptr = nullptr; +gb_global Type *t_source_code_location = nullptr; +gb_global Type *t_source_code_location_ptr = nullptr; -gb_global Type *t_map_key = nullptr; -gb_global Type *t_map_header = nullptr; +gb_global Type *t_map_key = nullptr; +gb_global Type *t_map_header = nullptr; -gb_global Type *t_vector_x86_mmx = nullptr; +gb_global Type *t_vector_x86_mmx = nullptr; @@ -702,6 +714,19 @@ Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { return t; } +Type *alloc_type_enumerated_array(Type *elem, Type *index, ExactValue min_value, ExactValue max_value, TokenKind op) { + Type *t = alloc_type(Type_EnumeratedArray); + t->EnumeratedArray.elem = elem; + t->EnumeratedArray.index = index; + t->EnumeratedArray.min_value = min_value; + t->EnumeratedArray.max_value = max_value; + t->EnumeratedArray.op = op; + + t->EnumeratedArray.count = 1 + exact_value_to_i64(exact_value_sub(max_value, min_value)); + return t; +} + + Type *alloc_type_slice(Type *elem) { Type *t = alloc_type(Type_Slice); t->Array.elem = elem; @@ -1031,6 +1056,10 @@ bool is_type_array(Type *t) { t = base_type(t); return t->kind == Type_Array; } +bool is_type_enumerated_array(Type *t) { + t = base_type(t); + return t->kind == Type_EnumeratedArray; +} bool is_type_dynamic_array(Type *t) { t = base_type(t); return t->kind == Type_DynamicArray; @@ -1381,6 +1410,8 @@ bool is_type_indexable(Type *t) { case Type_DynamicArray: case Type_Map: return true; + case Type_EnumeratedArray: + return true; } return false; } @@ -1394,6 +1425,8 @@ bool is_type_sliceable(Type *t) { case Type_Slice: case Type_DynamicArray: return true; + case Type_EnumeratedArray: + return false; } return false; } @@ -1470,6 +1503,12 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) { return is_type_polymorphic(t->Opaque.elem, or_specialized); case Type_Pointer: return is_type_polymorphic(t->Pointer.elem, or_specialized); + + case Type_EnumeratedArray: + if (is_type_polymorphic(t->EnumeratedArray.index, or_specialized)) { + return true; + } + return is_type_polymorphic(t->EnumeratedArray.elem, or_specialized); case Type_Array: if (t->Array.generic_count != nullptr) { return true; @@ -1633,6 +1672,8 @@ bool is_type_comparable(Type *t) { return true; case Type_Enum: return is_type_comparable(core_type(t)); + case Type_EnumeratedArray: + return is_type_comparable(t->EnumeratedArray.elem); case Type_Array: return is_type_comparable(t->Array.elem); case Type_Proc: @@ -1695,6 +1736,13 @@ bool are_types_identical(Type *x, Type *y) { } break; + case Type_EnumeratedArray: + if (y->kind == Type_EnumeratedArray) { + return are_types_identical(x->EnumeratedArray.index, y->EnumeratedArray.index) && + are_types_identical(x->EnumeratedArray.elem, y->EnumeratedArray.elem); + } + break; + case Type_Array: if (y->kind == Type_Array) { return (x->Array.count == y->Array.count) && are_types_identical(x->Array.elem, y->Array.elem); @@ -2471,6 +2519,17 @@ i64 type_align_of_internal(Type *t, TypePath *path) { return align; } + case Type_EnumeratedArray: { + Type *elem = t->EnumeratedArray.elem; + bool pop = type_path_push(path, elem); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(t->EnumeratedArray.elem, path); + if (pop) type_path_pop(path); + return align; + } + case Type_Opaque: return type_align_of_internal(t->Opaque.elem, path); @@ -2709,6 +2768,21 @@ i64 type_size_of_internal(Type *t, TypePath *path) { return alignment*(count-1) + size; } break; + case Type_EnumeratedArray: { + i64 count, align, size, alignment; + count = t->EnumeratedArray.count; + if (count == 0) { + return 0; + } + align = type_align_of_internal(t->EnumeratedArray.elem, path); + if (path->failure) { + return FAILURE_SIZE; + } + size = type_size_of_internal( t->EnumeratedArray.elem, path); + alignment = align_formula(size, align); + return alignment*(count-1) + size; + } break; + case Type_Slice: // ptr + len return 2 * build_context.word_size; @@ -2984,6 +3058,13 @@ gbString write_type_to_string(gbString str, Type *type) { str = write_type_to_string(str, type->Opaque.elem); break; + case Type_EnumeratedArray: + str = gb_string_append_rune(str, '['); + str = write_type_to_string(str, type->EnumeratedArray.index); + str = gb_string_append_rune(str, ']'); + str = write_type_to_string(str, type->EnumeratedArray.elem); + break; + case Type_Array: str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count)); str = write_type_to_string(str, type->Array.elem);