mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Enumerated arrays [Enum_Type]Elem_Type
This commit is contained in:
@@ -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 {
|
enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 {
|
||||||
switch i in ev {
|
switch i in ev {
|
||||||
@@ -892,6 +935,24 @@ enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 {
|
|||||||
return 0;
|
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 = "") {
|
fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
||||||
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
|
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
|
||||||
if ti == nil {
|
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);
|
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..<info.count {
|
||||||
|
if i > 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:
|
case runtime.Type_Info_Dynamic_Array:
|
||||||
if verb == 'p' {
|
if verb == 'p' {
|
||||||
slice := cast(^mem.Raw_Dynamic_Array)v.data;
|
slice := cast(^mem.Raw_Dynamic_Array)v.data;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Type_Kind :: enum {
|
|||||||
Pointer,
|
Pointer,
|
||||||
Procedure,
|
Procedure,
|
||||||
Array,
|
Array,
|
||||||
|
Enumerated_Array,
|
||||||
Dynamic_Array,
|
Dynamic_Array,
|
||||||
Slice,
|
Slice,
|
||||||
Tuple,
|
Tuple,
|
||||||
@@ -51,6 +52,7 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
|||||||
case runtime.Type_Info_Pointer: return .Pointer;
|
case runtime.Type_Info_Pointer: return .Pointer;
|
||||||
case runtime.Type_Info_Procedure: return .Procedure;
|
case runtime.Type_Info_Procedure: return .Procedure;
|
||||||
case runtime.Type_Info_Array: return .Array;
|
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_Dynamic_Array: return .Dynamic_Array;
|
||||||
case runtime.Type_Info_Slice: return .Slice;
|
case runtime.Type_Info_Slice: return .Slice;
|
||||||
case runtime.Type_Info_Tuple: return .Tuple;
|
case runtime.Type_Info_Tuple: return .Tuple;
|
||||||
|
|||||||
@@ -82,6 +82,13 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
|||||||
if x.count != y.count do return false;
|
if x.count != y.count do return false;
|
||||||
return are_types_identical(x.elem, y.elem);
|
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:
|
case rt.Type_Info_Dynamic_Array:
|
||||||
y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
|
y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
|
||||||
if !ok do return false;
|
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_i64(buf, i64(info.count), 10);
|
||||||
write_string(buf, "]");
|
write_string(buf, "]");
|
||||||
write_type(buf, info.elem);
|
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:
|
case rt.Type_Info_Dynamic_Array:
|
||||||
write_string(buf, "[dynamic]");
|
write_string(buf, "[dynamic]");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ Type_Info_Array :: struct {
|
|||||||
elem_size: int,
|
elem_size: int,
|
||||||
count: 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_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int};
|
||||||
Type_Info_Slice :: 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
|
Type_Info_Tuple :: struct { // Only really used for procedures
|
||||||
@@ -156,6 +164,7 @@ Type_Info :: struct {
|
|||||||
Type_Info_Pointer,
|
Type_Info_Pointer,
|
||||||
Type_Info_Procedure,
|
Type_Info_Procedure,
|
||||||
Type_Info_Array,
|
Type_Info_Array,
|
||||||
|
Type_Info_Enumerated_Array,
|
||||||
Type_Info_Dynamic_Array,
|
Type_Info_Dynamic_Array,
|
||||||
Type_Info_Slice,
|
Type_Info_Slice,
|
||||||
Type_Info_Tuple,
|
Type_Info_Tuple,
|
||||||
|
|||||||
@@ -172,6 +172,14 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
|||||||
print_u64(fd, u64(info.count));
|
print_u64(fd, u64(info.count));
|
||||||
os.write_byte(fd, ']');
|
os.write_byte(fd, ']');
|
||||||
print_type(fd, info.elem);
|
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:
|
case Type_Info_Dynamic_Array:
|
||||||
os.write_string(fd, "[dynamic]");
|
os.write_string(fd, "[dynamic]");
|
||||||
print_type(fd, info.elem);
|
print_type(fd, info.elem);
|
||||||
|
|||||||
+336
-33
@@ -3029,21 +3029,35 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
|||||||
update_expr_type(c, operand->expr, target_type, true);
|
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};
|
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 (operand.mode == Addressing_Invalid) {
|
||||||
if (value) *value = 0;
|
if (value) *value = 0;
|
||||||
return false;
|
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 (operand.mode == Addressing_Invalid) {
|
||||||
if (value) *value = 0;
|
if (value) *value = 0;
|
||||||
return false;
|
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);
|
gbString expr_str = expr_to_string(operand.expr);
|
||||||
error(operand.expr, "Index '%s' must be an integer", expr_str);
|
error(operand.expr, "Index '%s' must be an integer", expr_str);
|
||||||
gb_string_free(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 &&
|
if (operand.mode == Addressing_Constant &&
|
||||||
(c->state_flags & StateFlag_no_bounds_check) == 0) {
|
(c->state_flags & StateFlag_no_bounds_check) == 0) {
|
||||||
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
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);
|
gbString expr_str = expr_to_string(operand.expr);
|
||||||
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
||||||
gb_string_free(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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_count >= 0) { // NOTE(bill): Do array bound checking
|
if (max_count >= 0) {
|
||||||
i64 v = -1;
|
if (is_type_enum(index_type)) {
|
||||||
if (i.len <= 1) {
|
Type *bt = base_type(index_type);
|
||||||
v = big_int_to_i64(&i);
|
GB_ASSERT(bt->kind == Type_Enum);
|
||||||
}
|
ExactValue lo = bt->Enum.min_value;
|
||||||
if (value) *value = v;
|
ExactValue hi = bt->Enum.max_value;
|
||||||
bool out_of_bounds = false;
|
String lo_str = {};
|
||||||
if (open_range) {
|
String hi_str = {};
|
||||||
out_of_bounds = v >= max_count;
|
if (bt->Enum.fields.count > 0) {
|
||||||
} else {
|
lo_str = bt->Enum.fields[bt->Enum.min_value_index]->token.string;
|
||||||
out_of_bounds = v >= max_count+1;
|
hi_str = bt->Enum.fields[bt->Enum.max_value_index]->token.string;
|
||||||
}
|
}
|
||||||
if (v < 0) {
|
|
||||||
out_of_bounds = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_of_bounds) {
|
bool out_of_bounds = false;
|
||||||
gbString expr_str = expr_to_string(operand.expr);
|
|
||||||
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
|
if (compare_exact_values(Token_Lt, operand.value, lo) || compare_exact_values(Token_Gt, operand.value, hi)) {
|
||||||
gb_string_free(expr_str);
|
out_of_bounds = true;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
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;
|
mode = Addressing_Constant;
|
||||||
value = exact_value_i64(at->Array.count);
|
value = exact_value_i64(at->Array.count);
|
||||||
type = t_untyped_integer;
|
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) {
|
} else if (is_type_slice(op_type) && id == BuiltinProc_len) {
|
||||||
mode = Addressing_Value;
|
mode = Addressing_Value;
|
||||||
} else if (is_type_dynamic_array(op_type)) {
|
} 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 *original_type = operand->type;
|
||||||
Type *type = base_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);
|
gbString type_str = type_to_string(original_type);
|
||||||
error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str);
|
error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str);
|
||||||
gb_string_free(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->type = original_type;
|
||||||
operand->value = type->Enum.min_value;
|
operand->value = type->Enum.min_value;
|
||||||
return true;
|
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);
|
gbString type_str = type_to_string(original_type);
|
||||||
error(call, "Invalid type for 'min', got %s", type_str);
|
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 *original_type = operand->type;
|
||||||
Type *type = base_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);
|
gbString type_str = type_to_string(original_type);
|
||||||
error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str);
|
error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str);
|
||||||
gb_string_free(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->type = original_type;
|
||||||
operand->value = type->Enum.max_value;
|
operand->value = type->Enum.max_value;
|
||||||
return true;
|
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);
|
gbString type_str = type_to_string(original_type);
|
||||||
error(call, "Invalid type for 'max', got %s", type_str);
|
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;
|
o->type = t->Array.elem;
|
||||||
return true;
|
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:
|
case Type_Slice:
|
||||||
o->type = t->Slice.elem;
|
o->type = t->Slice.elem;
|
||||||
if (o->mode != Addressing_Constant) {
|
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)) {
|
if (!is_ast_range(node)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_node(ie, BinaryExpr, node);
|
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) {
|
if (x->mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
check_expr(c, y, ie->right);
|
check_expr_with_type_hint(c, y, ie->right, type_hint);
|
||||||
if (y->mode == Addressing_Invalid) {
|
if (y->mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -7630,6 +7714,218 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
break;
|
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: {
|
case Type_Basic: {
|
||||||
if (!is_type_any(t)) {
|
if (!is_type_any(t)) {
|
||||||
if (cl->elems.count != 0) {
|
if (cl->elems.count != 0) {
|
||||||
@@ -8135,8 +8431,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
return kind;
|
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;
|
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;
|
node->viral_state_flags |= ie->index->viral_state_flags;
|
||||||
case_end;
|
case_end;
|
||||||
|
|||||||
+35
-1
@@ -803,6 +803,8 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
|
|||||||
ExactValue iota = exact_value_i64(-1);
|
ExactValue iota = exact_value_i64(-1);
|
||||||
ExactValue min_value = exact_value_i64(0);
|
ExactValue min_value = exact_value_i64(0);
|
||||||
ExactValue max_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 min_value_set = false;
|
||||||
bool max_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 (min_value_set) {
|
||||||
if (compare_exact_values(Token_Gt, min_value, iota)) {
|
if (compare_exact_values(Token_Gt, min_value, iota)) {
|
||||||
|
min_value_index = i;
|
||||||
min_value = iota;
|
min_value = iota;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
min_value_index = i;
|
||||||
min_value = iota;
|
min_value = iota;
|
||||||
min_value_set = true;
|
min_value_set = true;
|
||||||
}
|
}
|
||||||
if (max_value_set) {
|
if (max_value_set) {
|
||||||
if (compare_exact_values(Token_Lt, max_value, iota)) {
|
if (compare_exact_values(Token_Lt, max_value, iota)) {
|
||||||
|
max_value_index = i;
|
||||||
max_value = iota;
|
max_value = iota;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
max_value_index = i;
|
||||||
max_value = iota;
|
max_value = iota;
|
||||||
max_value_set = true;
|
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.names = make_names_field_for_struct(ctx, ctx->scope);
|
||||||
enum_type->Enum.min_value = min_value;
|
enum_type->Enum.min_value = min_value;
|
||||||
enum_type->Enum.max_value = max_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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (o->mode == Addressing_Type) {
|
||||||
|
if (is_type_enum(o->type)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (o->mode != Addressing_Constant) {
|
if (o->mode != Addressing_Constant) {
|
||||||
if (o->mode != Addressing_Invalid) {
|
if (o->mode != Addressing_Invalid) {
|
||||||
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 = {};
|
Operand o = {};
|
||||||
i64 count = check_array_count(ctx, &o, at->count);
|
i64 count = check_array_count(ctx, &o, at->count);
|
||||||
Type *generic_type = nullptr;
|
Type *generic_type = nullptr;
|
||||||
|
|
||||||
|
Type *elem = check_type_expr(ctx, at->elem, nullptr);
|
||||||
|
|
||||||
if (o.mode == Addressing_Type && o.type->kind == Type_Generic) {
|
if (o.mode == Addressing_Type && o.type->kind == Type_Generic) {
|
||||||
generic_type = o.type;
|
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) {
|
if (count < 0) {
|
||||||
error(at->count, "? can only be used in conjuction with compound literals");
|
error(at->count, "? can only be used in conjuction with compound literals");
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
Type *elem = check_type_expr(ctx, at->elem, nullptr);
|
|
||||||
|
|
||||||
if (at->tag != nullptr) {
|
if (at->tag != nullptr) {
|
||||||
GB_ASSERT(at->tag->kind == Ast_BasicDirective);
|
GB_ASSERT(at->tag->kind == Ast_BasicDirective);
|
||||||
|
|||||||
+65
-48
@@ -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, alloc_type_pointer(bt->Array.elem));
|
||||||
add_type_info_type(c, t_int);
|
add_type_info_type(c, t_int);
|
||||||
break;
|
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:
|
case Type_DynamicArray:
|
||||||
add_type_info_type(c, bt->DynamicArray.elem);
|
add_type_info_type(c, bt->DynamicArray.elem);
|
||||||
add_type_info_type(c, alloc_type_pointer(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, alloc_type_pointer(bt->Array.elem));
|
||||||
add_min_dep_type_info(c, t_int);
|
add_min_dep_type_info(c, t_int);
|
||||||
break;
|
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:
|
case Type_DynamicArray:
|
||||||
add_min_dep_type_info(c, bt->DynamicArray.elem);
|
add_min_dep_type_info(c, bt->DynamicArray.elem);
|
||||||
add_min_dep_type_info(c, alloc_type_pointer(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;
|
Type *tiv_type = type_info_variant->type;
|
||||||
GB_ASSERT(is_type_union(tiv_type));
|
GB_ASSERT(is_type_union(tiv_type));
|
||||||
|
|
||||||
t_type_info_named = find_core_type(c, str_lit("Type_Info_Named"));
|
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_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_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_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_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_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_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_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_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_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_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_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_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_enumerated_array = find_core_type(c, str_lit("Type_Info_Enumerated_Array"));
|
||||||
t_type_info_slice = find_core_type(c, str_lit("Type_Info_Slice"));
|
t_type_info_dynamic_array = find_core_type(c, str_lit("Type_Info_Dynamic_Array"));
|
||||||
t_type_info_tuple = find_core_type(c, str_lit("Type_Info_Tuple"));
|
t_type_info_slice = find_core_type(c, str_lit("Type_Info_Slice"));
|
||||||
t_type_info_struct = find_core_type(c, str_lit("Type_Info_Struct"));
|
t_type_info_tuple = find_core_type(c, str_lit("Type_Info_Tuple"));
|
||||||
t_type_info_union = find_core_type(c, str_lit("Type_Info_Union"));
|
t_type_info_struct = find_core_type(c, str_lit("Type_Info_Struct"));
|
||||||
t_type_info_enum = find_core_type(c, str_lit("Type_Info_Enum"));
|
t_type_info_union = find_core_type(c, str_lit("Type_Info_Union"));
|
||||||
t_type_info_map = find_core_type(c, str_lit("Type_Info_Map"));
|
t_type_info_enum = find_core_type(c, str_lit("Type_Info_Enum"));
|
||||||
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
|
t_type_info_map = find_core_type(c, str_lit("Type_Info_Map"));
|
||||||
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
|
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
|
||||||
t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque"));
|
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
|
||||||
t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
|
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_named_ptr = alloc_type_pointer(t_type_info_named);
|
||||||
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
|
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_rune_ptr = alloc_type_pointer(t_type_info_rune);
|
||||||
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
|
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_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion);
|
||||||
t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex);
|
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_string_ptr = alloc_type_pointer(t_type_info_string);
|
||||||
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
|
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_any_ptr = alloc_type_pointer(t_type_info_any);
|
||||||
t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid);
|
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_pointer_ptr = alloc_type_pointer(t_type_info_pointer);
|
||||||
t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure);
|
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_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_enumerated_array_ptr = alloc_type_pointer(t_type_info_enumerated_array);
|
||||||
t_type_info_slice_ptr = alloc_type_pointer(t_type_info_slice);
|
t_type_info_dynamic_array_ptr = alloc_type_pointer(t_type_info_dynamic_array);
|
||||||
t_type_info_tuple_ptr = alloc_type_pointer(t_type_info_tuple);
|
t_type_info_slice_ptr = alloc_type_pointer(t_type_info_slice);
|
||||||
t_type_info_struct_ptr = alloc_type_pointer(t_type_info_struct);
|
t_type_info_tuple_ptr = alloc_type_pointer(t_type_info_tuple);
|
||||||
t_type_info_union_ptr = alloc_type_pointer(t_type_info_union);
|
t_type_info_struct_ptr = alloc_type_pointer(t_type_info_struct);
|
||||||
t_type_info_enum_ptr = alloc_type_pointer(t_type_info_enum);
|
t_type_info_union_ptr = alloc_type_pointer(t_type_info_union);
|
||||||
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
|
t_type_info_enum_ptr = alloc_type_pointer(t_type_info_enum);
|
||||||
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
|
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
|
||||||
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
|
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
|
||||||
t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque);
|
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
|
||||||
t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector);
|
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) {
|
void init_mem_allocator(Checker *c) {
|
||||||
|
|||||||
+71
-3
@@ -1148,9 +1148,14 @@ irValue *ir_instr_array_element_ptr(irProcedure *p, irValue *address, irValue *e
|
|||||||
Type *t = ir_type(address);
|
Type *t = ir_type(address);
|
||||||
GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
|
GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
|
||||||
t = base_type(type_deref(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.address = address;
|
||||||
i->ArrayElementPtr.elem_index = elem_index;
|
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);
|
Type *t = ir_type(s);
|
||||||
GB_ASSERT(is_type_pointer(t));
|
GB_ASSERT(is_type_pointer(t));
|
||||||
Type *st = base_type(type_deref(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
|
// 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);
|
index = ir_emit_conv(proc, index, t_i32);
|
||||||
@@ -7956,6 +7961,43 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
return ir_addr(elem);
|
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: {
|
case Type_Slice: {
|
||||||
irValue *slice = nullptr;
|
irValue *slice = nullptr;
|
||||||
if (using_addr != nullptr) {
|
if (using_addr != nullptr) {
|
||||||
@@ -11055,6 +11097,32 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
|
|
||||||
break;
|
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: {
|
case Type_DynamicArray: {
|
||||||
ir_emit_comment(proc, str_lit("Type_Info_Dynamic_Array"));
|
ir_emit_comment(proc, str_lit("Type_Info_Dynamic_Array"));
|
||||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_dynamic_array_ptr);
|
tag = ir_emit_conv(proc, variant_ptr, t_type_info_dynamic_array_ptr);
|
||||||
|
|||||||
@@ -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_print_type(f, m, t->Array.elem);
|
||||||
ir_write_byte(f, ']');
|
ir_write_byte(f, ']');
|
||||||
return;
|
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:
|
case Type_Slice:
|
||||||
ir_write_byte(f, '{');
|
ir_write_byte(f, '{');
|
||||||
ir_print_type(f, m, t->Slice.elem); ir_write_str_lit(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_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, ']');
|
ir_write_byte(f, ']');
|
||||||
}
|
}
|
||||||
} else if (is_type_simd_vector(type)) {
|
} else if (is_type_simd_vector(type)) {
|
||||||
|
|||||||
+142
-61
@@ -177,6 +177,14 @@ struct TypeUnion {
|
|||||||
i64 count; \
|
i64 count; \
|
||||||
Type *generic_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(Slice, struct { Type *elem; }) \
|
||||||
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
||||||
TYPE_KIND(Map, struct { \
|
TYPE_KIND(Map, struct { \
|
||||||
@@ -197,6 +205,8 @@ struct TypeUnion {
|
|||||||
Type * base_type; \
|
Type * base_type; \
|
||||||
ExactValue min_value; \
|
ExactValue min_value; \
|
||||||
ExactValue max_value; \
|
ExactValue max_value; \
|
||||||
|
isize min_value_index; \
|
||||||
|
isize max_value_index; \
|
||||||
}) \
|
}) \
|
||||||
TYPE_KIND(Tuple, struct { \
|
TYPE_KIND(Tuple, struct { \
|
||||||
Array<Entity *> variables; /* Entity_Variable */ \
|
Array<Entity *> variables; /* Entity_Variable */ \
|
||||||
@@ -489,73 +499,75 @@ gb_global Type *t_string_slice = nullptr;
|
|||||||
|
|
||||||
|
|
||||||
// Type generated for the "preload" file
|
// Type generated for the "preload" file
|
||||||
gb_global Type *t_type_info = nullptr;
|
gb_global Type *t_type_info = nullptr;
|
||||||
gb_global Type *t_type_info_enum_value = nullptr;
|
gb_global Type *t_type_info_enum_value = nullptr;
|
||||||
gb_global Type *t_type_info_ptr = 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_enum_value_ptr = nullptr;
|
||||||
|
|
||||||
gb_global Type *t_type_info_named = nullptr;
|
gb_global Type *t_type_info_named = nullptr;
|
||||||
gb_global Type *t_type_info_integer = nullptr;
|
gb_global Type *t_type_info_integer = nullptr;
|
||||||
gb_global Type *t_type_info_rune = nullptr;
|
gb_global Type *t_type_info_rune = nullptr;
|
||||||
gb_global Type *t_type_info_float = nullptr;
|
gb_global Type *t_type_info_float = nullptr;
|
||||||
gb_global Type *t_type_info_complex = nullptr;
|
gb_global Type *t_type_info_complex = nullptr;
|
||||||
gb_global Type *t_type_info_quaternion = nullptr;
|
gb_global Type *t_type_info_quaternion = nullptr;
|
||||||
gb_global Type *t_type_info_any = nullptr;
|
gb_global Type *t_type_info_any = nullptr;
|
||||||
gb_global Type *t_type_info_typeid = nullptr;
|
gb_global Type *t_type_info_typeid = nullptr;
|
||||||
gb_global Type *t_type_info_string = nullptr;
|
gb_global Type *t_type_info_string = nullptr;
|
||||||
gb_global Type *t_type_info_boolean = nullptr;
|
gb_global Type *t_type_info_boolean = nullptr;
|
||||||
gb_global Type *t_type_info_pointer = nullptr;
|
gb_global Type *t_type_info_pointer = nullptr;
|
||||||
gb_global Type *t_type_info_procedure = nullptr;
|
gb_global Type *t_type_info_procedure = nullptr;
|
||||||
gb_global Type *t_type_info_array = nullptr;
|
gb_global Type *t_type_info_array = nullptr;
|
||||||
gb_global Type *t_type_info_dynamic_array = nullptr;
|
gb_global Type *t_type_info_enumerated_array = nullptr;
|
||||||
gb_global Type *t_type_info_slice = nullptr;
|
gb_global Type *t_type_info_dynamic_array = nullptr;
|
||||||
gb_global Type *t_type_info_tuple = nullptr;
|
gb_global Type *t_type_info_slice = nullptr;
|
||||||
gb_global Type *t_type_info_struct = nullptr;
|
gb_global Type *t_type_info_tuple = nullptr;
|
||||||
gb_global Type *t_type_info_union = nullptr;
|
gb_global Type *t_type_info_struct = nullptr;
|
||||||
gb_global Type *t_type_info_enum = nullptr;
|
gb_global Type *t_type_info_union = nullptr;
|
||||||
gb_global Type *t_type_info_map = nullptr;
|
gb_global Type *t_type_info_enum = nullptr;
|
||||||
gb_global Type *t_type_info_bit_field = nullptr;
|
gb_global Type *t_type_info_map = nullptr;
|
||||||
gb_global Type *t_type_info_bit_set = nullptr;
|
gb_global Type *t_type_info_bit_field = nullptr;
|
||||||
gb_global Type *t_type_info_opaque = nullptr;
|
gb_global Type *t_type_info_bit_set = nullptr;
|
||||||
gb_global Type *t_type_info_simd_vector = 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_named_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_integer_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_rune_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_float_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_complex_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_quaternion_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_any_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_typeid_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_string_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_boolean_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_pointer_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_procedure_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_array_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_dynamic_array_ptr = nullptr;
|
gb_global Type *t_type_info_enumerated_array_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_slice_ptr = nullptr;
|
gb_global Type *t_type_info_dynamic_array_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_tuple_ptr = nullptr;
|
gb_global Type *t_type_info_slice_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_struct_ptr = nullptr;
|
gb_global Type *t_type_info_tuple_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_union_ptr = nullptr;
|
gb_global Type *t_type_info_struct_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_enum_ptr = nullptr;
|
gb_global Type *t_type_info_union_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_map_ptr = nullptr;
|
gb_global Type *t_type_info_enum_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
gb_global Type *t_type_info_map_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_opaque_ptr = nullptr;
|
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_simd_vector_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 = nullptr;
|
||||||
gb_global Type *t_allocator_ptr = nullptr;
|
gb_global Type *t_allocator_ptr = nullptr;
|
||||||
gb_global Type *t_context = nullptr;
|
gb_global Type *t_context = nullptr;
|
||||||
gb_global Type *t_context_ptr = nullptr;
|
gb_global Type *t_context_ptr = nullptr;
|
||||||
|
|
||||||
gb_global Type *t_source_code_location = 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_ptr = nullptr;
|
||||||
|
|
||||||
gb_global Type *t_map_key = nullptr;
|
gb_global Type *t_map_key = nullptr;
|
||||||
gb_global Type *t_map_header = 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;
|
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 *alloc_type_slice(Type *elem) {
|
||||||
Type *t = alloc_type(Type_Slice);
|
Type *t = alloc_type(Type_Slice);
|
||||||
t->Array.elem = elem;
|
t->Array.elem = elem;
|
||||||
@@ -1031,6 +1056,10 @@ bool is_type_array(Type *t) {
|
|||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return t->kind == Type_Array;
|
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) {
|
bool is_type_dynamic_array(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return t->kind == Type_DynamicArray;
|
return t->kind == Type_DynamicArray;
|
||||||
@@ -1381,6 +1410,8 @@ bool is_type_indexable(Type *t) {
|
|||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
case Type_Map:
|
case Type_Map:
|
||||||
return true;
|
return true;
|
||||||
|
case Type_EnumeratedArray:
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1394,6 +1425,8 @@ bool is_type_sliceable(Type *t) {
|
|||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
return true;
|
return true;
|
||||||
|
case Type_EnumeratedArray:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
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);
|
return is_type_polymorphic(t->Opaque.elem, or_specialized);
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
return is_type_polymorphic(t->Pointer.elem, or_specialized);
|
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:
|
case Type_Array:
|
||||||
if (t->Array.generic_count != nullptr) {
|
if (t->Array.generic_count != nullptr) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1633,6 +1672,8 @@ bool is_type_comparable(Type *t) {
|
|||||||
return true;
|
return true;
|
||||||
case Type_Enum:
|
case Type_Enum:
|
||||||
return is_type_comparable(core_type(t));
|
return is_type_comparable(core_type(t));
|
||||||
|
case Type_EnumeratedArray:
|
||||||
|
return is_type_comparable(t->EnumeratedArray.elem);
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
return is_type_comparable(t->Array.elem);
|
return is_type_comparable(t->Array.elem);
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
@@ -1695,6 +1736,13 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case Type_Array:
|
||||||
if (y->kind == Type_Array) {
|
if (y->kind == Type_Array) {
|
||||||
return (x->Array.count == y->Array.count) && are_types_identical(x->Array.elem, y->Array.elem);
|
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;
|
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:
|
case Type_Opaque:
|
||||||
return type_align_of_internal(t->Opaque.elem, path);
|
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;
|
return alignment*(count-1) + size;
|
||||||
} break;
|
} 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
|
case Type_Slice: // ptr + len
|
||||||
return 2 * build_context.word_size;
|
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);
|
str = write_type_to_string(str, type->Opaque.elem);
|
||||||
break;
|
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:
|
case Type_Array:
|
||||||
str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count));
|
str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count));
|
||||||
str = write_type_to_string(str, type->Array.elem);
|
str = write_type_to_string(str, type->Array.elem);
|
||||||
|
|||||||
Reference in New Issue
Block a user