mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
Add underlying type for bit_set
This commit is contained in:
+5
-1
@@ -355,7 +355,11 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
|
|||||||
write_string(buf, "..");
|
write_string(buf, "..");
|
||||||
write_i64(buf, info.upper, 10);
|
write_i64(buf, info.upper, 10);
|
||||||
}
|
}
|
||||||
write_string(buf, "]");
|
if info.underlying != nil {
|
||||||
|
write_string(buf, "; ");
|
||||||
|
write_type(buf, info.underlying);
|
||||||
|
}
|
||||||
|
write_byte(buf, ']');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-3
@@ -100,9 +100,10 @@ Type_Info_Bit_Field :: struct {
|
|||||||
offsets: []i32,
|
offsets: []i32,
|
||||||
};
|
};
|
||||||
Type_Info_Bit_Set :: struct {
|
Type_Info_Bit_Set :: struct {
|
||||||
elem: ^Type_Info,
|
elem: ^Type_Info,
|
||||||
lower: i64,
|
underlying: ^Type_Info, // Possibly nil
|
||||||
upper: i64,
|
lower: i64,
|
||||||
|
upper: i64,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type_Info :: struct {
|
Type_Info :: struct {
|
||||||
@@ -427,6 +428,14 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(builtin)
|
||||||
|
incl :: proc(s: ^$B/bit_set[$T], elem: T) {
|
||||||
|
s^ |= {elem};
|
||||||
|
}
|
||||||
|
@(builtin)
|
||||||
|
excl :: proc(s: ^$B/bit_set[$T], elem: T) {
|
||||||
|
s^ &~= {elem};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -744,12 +744,15 @@ bit_set_type :: proc() {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
x: bit_set['A'..'Z'];
|
x: bit_set['A'..'Z'];
|
||||||
y: bit_set[0..8];
|
assert(size_of(x) == size_of(u32));
|
||||||
|
y: bit_set[0..8; u16];
|
||||||
fmt.println(typeid_of(type_of(x))); // bit_set[A..Z]
|
fmt.println(typeid_of(type_of(x))); // bit_set[A..Z]
|
||||||
fmt.println(typeid_of(type_of(y))); // bit_set[0..8]
|
fmt.println(typeid_of(type_of(y))); // bit_set[0..8]
|
||||||
|
|
||||||
x |= {'F'};
|
incl(&x, 'F');
|
||||||
assert('F' in x);
|
assert('F' in x);
|
||||||
|
excl(&x, 'F');
|
||||||
|
assert(!('F' in x));
|
||||||
|
|
||||||
y |= {1, 4, 2};
|
y |= {1, 4, 2};
|
||||||
assert(2 in y);
|
assert(2 in y);
|
||||||
@@ -757,7 +760,7 @@ bit_set_type :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when false {
|
||||||
general_stuff();
|
general_stuff();
|
||||||
union_type();
|
union_type();
|
||||||
parametric_polymorphism();
|
parametric_polymorphism();
|
||||||
@@ -769,6 +772,6 @@ main :: proc() {
|
|||||||
complete_switch();
|
complete_switch();
|
||||||
cstring_example();
|
cstring_example();
|
||||||
deprecated_attribute();
|
deprecated_attribute();
|
||||||
bit_set_type();
|
|
||||||
}
|
}
|
||||||
|
bit_set_type();
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-4
@@ -836,6 +836,9 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case Type_BitSet:
|
case Type_BitSet:
|
||||||
|
if (source->kind == Type_BitSet) {
|
||||||
|
return is_polymorphic_type_assignable(c, poly->BitSet.elem, source->BitSet.elem, true, modify_type);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
@@ -2040,7 +2043,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as
|
|||||||
add_package_dependency(c, "runtime", "__dynamic_map_get");
|
add_package_dependency(c, "runtime", "__dynamic_map_get");
|
||||||
} else if (is_type_bit_set(y->type)) {
|
} else if (is_type_bit_set(y->type)) {
|
||||||
Type *yt = base_type(y->type);
|
Type *yt = base_type(y->type);
|
||||||
check_assignment(c, x, yt->BitSet.base, str_lit("bit_set 'in'"));
|
check_assignment(c, x, yt->BitSet.elem, str_lit("bit_set 'in'"));
|
||||||
|
|
||||||
if (x->mode == Addressing_Constant && y->mode == Addressing_Constant) {
|
if (x->mode == Addressing_Constant && y->mode == Addressing_Constant) {
|
||||||
ExactValue k = exact_value_to_integer(x->value);
|
ExactValue k = exact_value_to_integer(x->value);
|
||||||
@@ -5552,7 +5555,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
if (cl->elems.count == 0) {
|
if (cl->elems.count == 0) {
|
||||||
break; // NOTE(bill): No need to init
|
break; // NOTE(bill): No need to init
|
||||||
}
|
}
|
||||||
Type *et = base_type(t->BitSet.base);
|
Type *et = base_type(t->BitSet.elem);
|
||||||
isize field_count = 0;
|
isize field_count = 0;
|
||||||
if (et->kind == Type_Enum) {
|
if (et->kind == Type_Enum) {
|
||||||
field_count = et->Enum.fields.count;
|
field_count = et->Enum.fields.count;
|
||||||
@@ -5576,7 +5579,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
is_constant = o->mode == Addressing_Constant;
|
is_constant = o->mode == Addressing_Constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_assignment(c, o, t->BitSet.base, str_lit("bit_set literal"));
|
check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -6318,7 +6321,7 @@ gbString write_expr_to_string(gbString str, Ast *node) {
|
|||||||
|
|
||||||
case_ast_node(bs, BitSetType, node);
|
case_ast_node(bs, BitSetType, node);
|
||||||
str = gb_string_appendc(str, "bit_set[");
|
str = gb_string_appendc(str, "bit_set[");
|
||||||
str = write_expr_to_string(str, bs->base);
|
str = write_expr_to_string(str, bs->elem);
|
||||||
str = gb_string_appendc(str, "]");
|
str = gb_string_appendc(str, "]");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|||||||
+72
-44
@@ -696,7 +696,7 @@ void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) {
|
|||||||
|
|
||||||
i64 const MAX_BITS = 64;
|
i64 const MAX_BITS = 64;
|
||||||
|
|
||||||
Ast *base = unparen_expr(bs->base);
|
Ast *base = unparen_expr(bs->elem);
|
||||||
if (is_ast_range(base)) {
|
if (is_ast_range(base)) {
|
||||||
ast_node(be, BinaryExpr, base);
|
ast_node(be, BinaryExpr, base);
|
||||||
Operand lhs = {};
|
Operand lhs = {};
|
||||||
@@ -719,8 +719,8 @@ void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) {
|
|||||||
rhs.type != t_invalid) {
|
rhs.type != t_invalid) {
|
||||||
gbString xt = type_to_string(lhs.type);
|
gbString xt = type_to_string(lhs.type);
|
||||||
gbString yt = type_to_string(rhs.type);
|
gbString yt = type_to_string(rhs.type);
|
||||||
gbString expr_str = expr_to_string(bs->base);
|
gbString expr_str = expr_to_string(bs->elem);
|
||||||
error(bs->base, "Mismatched types in range '%s' : '%s' vs '%s'", expr_str, xt, yt);
|
error(bs->elem, "Mismatched types in range '%s' : '%s' vs '%s'", expr_str, xt, yt);
|
||||||
gb_string_free(expr_str);
|
gb_string_free(expr_str);
|
||||||
gb_string_free(yt);
|
gb_string_free(yt);
|
||||||
gb_string_free(xt);
|
gb_string_free(xt);
|
||||||
@@ -730,13 +730,13 @@ void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) {
|
|||||||
|
|
||||||
if (!is_type_valid_bit_set_range(lhs.type)) {
|
if (!is_type_valid_bit_set_range(lhs.type)) {
|
||||||
gbString str = type_to_string(lhs.type);
|
gbString str = type_to_string(lhs.type);
|
||||||
error(bs->base, "'%s' is invalid for an interval expression, expected an integer or rune", str);
|
error(bs->elem, "'%s' is invalid for an interval expression, expected an integer or rune", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lhs.mode != Addressing_Constant || rhs.mode != Addressing_Constant) {
|
if (lhs.mode != Addressing_Constant || rhs.mode != Addressing_Constant) {
|
||||||
error(bs->base, "Intervals must be constant values");
|
error(bs->elem, "Intervals must be constant values");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,19 +751,29 @@ void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) {
|
|||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
String si = big_int_to_string(a, &i);
|
String si = big_int_to_string(a, &i);
|
||||||
String sj = big_int_to_string(a, &j);
|
String sj = big_int_to_string(a, &j);
|
||||||
error(bs->base, "Lower interval bound larger than upper bound, %.*s .. %.*s", LIT(si), LIT(sj));
|
error(bs->elem, "Lower interval bound larger than upper bound, %.*s .. %.*s", LIT(si), LIT(sj));
|
||||||
gb_free(a, si.text);
|
gb_free(a, si.text);
|
||||||
gb_free(a, sj.text);
|
gb_free(a, sj.text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *t = default_type(lhs.type);
|
Type *t = default_type(lhs.type);
|
||||||
|
if (bs->underlying != nullptr) {
|
||||||
|
Type *u = check_type(c, bs->underlying);
|
||||||
|
if (!is_type_integer(u)) {
|
||||||
|
gbString ts = type_to_string(u);
|
||||||
|
error(bs->underlying, "Expected an underlying integer for the bit set, got %s", ts);
|
||||||
|
gb_string_free(ts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
type->BitSet.underlying = u;
|
||||||
|
}
|
||||||
|
|
||||||
if (!check_representable_as_constant(c, iv, t, nullptr)) {
|
if (!check_representable_as_constant(c, iv, t, nullptr)) {
|
||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
String s = big_int_to_string(a, &i);
|
String s = big_int_to_string(a, &i);
|
||||||
gbString ts = type_to_string(t);
|
gbString ts = type_to_string(t);
|
||||||
error(bs->base, "%.*s is not representable by %s", LIT(s), ts);
|
error(bs->elem, "%.*s is not representable by %s", LIT(s), ts);
|
||||||
gb_string_free(ts);
|
gb_string_free(ts);
|
||||||
gb_free(a, s.text);
|
gb_free(a, s.text);
|
||||||
return;
|
return;
|
||||||
@@ -772,7 +782,7 @@ void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) {
|
|||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
String s = big_int_to_string(a, &j);
|
String s = big_int_to_string(a, &j);
|
||||||
gbString ts = type_to_string(t);
|
gbString ts = type_to_string(t);
|
||||||
error(bs->base, "%.*s is not representable by %s", LIT(s), ts);
|
error(bs->elem, "%.*s is not representable by %s", LIT(s), ts);
|
||||||
gb_string_free(ts);
|
gb_string_free(ts);
|
||||||
gb_free(a, s.text);
|
gb_free(a, s.text);
|
||||||
return;
|
return;
|
||||||
@@ -780,50 +790,68 @@ void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) {
|
|||||||
i64 lower = big_int_to_i64(&i);
|
i64 lower = big_int_to_i64(&i);
|
||||||
i64 upper = big_int_to_i64(&j);
|
i64 upper = big_int_to_i64(&j);
|
||||||
|
|
||||||
if (upper - lower > MAX_BITS) {
|
i64 bits = MAX_BITS;
|
||||||
error(bs->base, "bit_set range is greater than %lld bits, %lld bits are required", MAX_BITS, (upper-lower+1));
|
if (type->BitSet.underlying != nullptr) {
|
||||||
|
bits = 8*type_size_of(type->BitSet.underlying);
|
||||||
}
|
}
|
||||||
type->BitSet.base = t;
|
|
||||||
|
if (upper - lower >= bits) {
|
||||||
|
error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower+1));
|
||||||
|
}
|
||||||
|
type->BitSet.elem = t;
|
||||||
type->BitSet.lower = lower;
|
type->BitSet.lower = lower;
|
||||||
type->BitSet.upper = upper;
|
type->BitSet.upper = upper;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Type *bt = check_type_expr(c, bs->base, nullptr);
|
Type *elem = check_type_expr(c, bs->elem, nullptr);
|
||||||
|
|
||||||
type->BitSet.base = bt;
|
type->BitSet.elem = elem;
|
||||||
if (!is_type_enum(bt)) {
|
if (!is_type_valid_bit_set_elem(elem)) {
|
||||||
error(bs->base, "Expected an enum type for a bit_set");
|
error(bs->elem, "Expected an enum type for a bit_set");
|
||||||
} else {
|
} else {
|
||||||
Type *et = base_type(bt);
|
Type *et = base_type(elem);
|
||||||
GB_ASSERT(et->kind == Type_Enum);
|
if (et->kind == Type_Enum) {
|
||||||
if (!is_type_integer(et->Enum.base_type)) {
|
if (!is_type_integer(et->Enum.base_type)) {
|
||||||
error(bs->base, "Enum type for bit_set must be an integer");
|
error(bs->elem, "Enum type for bit_set must be an integer");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
i64 lower = 0;
|
|
||||||
i64 upper = 0;
|
|
||||||
|
|
||||||
for_array(i, et->Enum.fields) {
|
|
||||||
Entity *e = et->Enum.fields[i];
|
|
||||||
if (e->kind != Entity_Constant) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
ExactValue value = exact_value_to_integer(e->Constant.value);
|
i64 lower = 0;
|
||||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
i64 upper = 0;
|
||||||
// NOTE(bill): enum types should be able to store i64 values
|
|
||||||
i64 x = big_int_to_i64(&value.value_integer);
|
for_array(i, et->Enum.fields) {
|
||||||
lower = gb_min(lower, x);
|
Entity *e = et->Enum.fields[i];
|
||||||
upper = gb_max(upper, x);
|
if (e->kind != Entity_Constant) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ExactValue value = exact_value_to_integer(e->Constant.value);
|
||||||
|
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||||
|
// NOTE(bill): enum types should be able to store i64 values
|
||||||
|
i64 x = big_int_to_i64(&value.value_integer);
|
||||||
|
lower = gb_min(lower, x);
|
||||||
|
upper = gb_max(upper, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(lower <= upper);
|
||||||
|
|
||||||
|
i64 bits = MAX_BITS;
|
||||||
|
if (bs->underlying != nullptr) {
|
||||||
|
Type *u = check_type(c, bs->underlying);
|
||||||
|
if (!is_type_integer(u)) {
|
||||||
|
gbString ts = type_to_string(u);
|
||||||
|
error(bs->underlying, "Expected an underlying integer for the bit set, got %s", ts);
|
||||||
|
gb_string_free(ts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
type->BitSet.underlying = u;
|
||||||
|
bits = 8*type_size_of(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upper - lower >= MAX_BITS) {
|
||||||
|
error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", MAX_BITS, (upper-lower+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
type->BitSet.lower = lower;
|
||||||
|
type->BitSet.upper = upper;
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_ASSERT(lower <= upper);
|
|
||||||
|
|
||||||
if (upper - lower > MAX_BITS) {
|
|
||||||
error(bs->base, "bit_set range is greater than %lld bits, %lld bits are required", MAX_BITS, (upper-lower+1));
|
|
||||||
}
|
|
||||||
|
|
||||||
type->BitSet.lower = lower;
|
|
||||||
type->BitSet.upper = upper;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1044,7 +1044,7 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_BitSet:
|
case Type_BitSet:
|
||||||
add_type_info_type(c, bt->BitSet.base);
|
add_type_info_type(c, bt->BitSet.elem);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
|
|||||||
+9
-6
@@ -4909,7 +4909,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
|||||||
{
|
{
|
||||||
ir_emit_comment(proc, str_lit("bit_set in"));
|
ir_emit_comment(proc, str_lit("bit_set in"));
|
||||||
|
|
||||||
Type *key_type = rt->BitSet.base;
|
Type *key_type = rt->BitSet.elem;
|
||||||
GB_ASSERT(are_types_identical(ir_type(left), key_type));
|
GB_ASSERT(are_types_identical(ir_type(left), key_type));
|
||||||
|
|
||||||
Type *it = bit_set_to_int(rt);
|
Type *it = bit_set_to_int(rt);
|
||||||
@@ -5663,7 +5663,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
switch (bt->kind) {
|
switch (bt->kind) {
|
||||||
case Type_Array: et = bt->Array.elem; break;
|
case Type_Array: et = bt->Array.elem; break;
|
||||||
case Type_Slice: et = bt->Slice.elem; break;
|
case Type_Slice: et = bt->Slice.elem; break;
|
||||||
case Type_BitSet: et = bt->BitSet.base; break;
|
case Type_BitSet: et = bt->BitSet.elem; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
String proc_name = {};
|
String proc_name = {};
|
||||||
@@ -8118,10 +8118,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
ir_emit_comment(proc, str_lit("Type_Info_Bit_Set"));
|
ir_emit_comment(proc, str_lit("Type_Info_Bit_Set"));
|
||||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_bit_set_ptr);
|
tag = ir_emit_conv(proc, variant_ptr, t_type_info_bit_set_ptr);
|
||||||
|
|
||||||
GB_ASSERT(is_type_typed(t->BitSet.base));
|
GB_ASSERT(is_type_typed(t->BitSet.elem));
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->BitSet.base));
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->BitSet.elem));
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_i64(t->BitSet.lower));
|
if (t->BitSet.underlying != nullptr) {
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_i64(t->BitSet.upper));
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_get_type_info_ptr(proc, t->BitSet.underlying));
|
||||||
|
}
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_i64(t->BitSet.lower));
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_i64(t->BitSet.upper));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+6
-9
@@ -508,16 +508,13 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Type_BitSet: {
|
case Type_BitSet: {
|
||||||
i64 align = type_align_of(t);
|
i64 size = type_size_of(t);
|
||||||
i64 size = type_size_of(t);
|
if (size == 0) {
|
||||||
switch (size) {
|
ir_write_str_lit(f, "{}");
|
||||||
case 0: ir_write_str_lit(f, "{}"); return;
|
return;
|
||||||
case 1: ir_write_str_lit(f, "i8"); return;
|
|
||||||
case 2: ir_write_str_lit(f, "i16"); return;
|
|
||||||
case 4: ir_write_str_lit(f, "i32"); return;
|
|
||||||
case 8: ir_write_str_lit(f, "i64"); return;
|
|
||||||
default: GB_PANIC("Unknown bit_set size"); break;
|
|
||||||
}
|
}
|
||||||
|
ir_print_type(f, m, bit_set_to_int(t));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-5
@@ -347,7 +347,8 @@ Ast *clone_ast(Ast *node) {
|
|||||||
n->BitFieldType.align = clone_ast(n->BitFieldType.align);
|
n->BitFieldType.align = clone_ast(n->BitFieldType.align);
|
||||||
break;
|
break;
|
||||||
case Ast_BitSetType:
|
case Ast_BitSetType:
|
||||||
n->BitSetType.base = clone_ast(n->BitSetType.base);
|
n->BitSetType.elem = clone_ast(n->BitSetType.elem);
|
||||||
|
n->BitSetType.underlying = clone_ast(n->BitSetType.underlying);
|
||||||
break;
|
break;
|
||||||
case Ast_MapType:
|
case Ast_MapType:
|
||||||
n->MapType.count = clone_ast(n->MapType.count);
|
n->MapType.count = clone_ast(n->MapType.count);
|
||||||
@@ -927,10 +928,11 @@ Ast *ast_bit_field_type(AstFile *f, Token token, Array<Ast *> fields, Ast *align
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *ast_bit_set_type(AstFile *f, Token token, Ast *base) {
|
Ast *ast_bit_set_type(AstFile *f, Token token, Ast *elem, Ast *underlying) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_BitSetType);
|
Ast *result = alloc_ast_node(f, Ast_BitSetType);
|
||||||
result->BitSetType.token = token;
|
result->BitSetType.token = token;
|
||||||
result->BitSetType.base = base;
|
result->BitSetType.elem = elem;
|
||||||
|
result->BitSetType.underlying = underlying;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1963,14 +1965,20 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
Token token = expect_token(f, Token_bit_set);
|
Token token = expect_token(f, Token_bit_set);
|
||||||
Token open = expect_token(f, Token_OpenBracket);
|
Token open = expect_token(f, Token_OpenBracket);
|
||||||
|
|
||||||
|
Ast *elem = nullptr;
|
||||||
|
Ast *underlying = nullptr;
|
||||||
|
|
||||||
bool prev_allow_range = f->allow_range;
|
bool prev_allow_range = f->allow_range;
|
||||||
f->allow_range = true;
|
f->allow_range = true;
|
||||||
Ast *base = parse_expr(f, false);
|
elem = parse_expr(f, false);
|
||||||
f->allow_range = prev_allow_range;
|
f->allow_range = prev_allow_range;
|
||||||
|
if (allow_token(f, Token_Semicolon)) {
|
||||||
|
underlying = parse_type(f);
|
||||||
|
}
|
||||||
|
|
||||||
Token close = expect_token(f, Token_CloseBracket);
|
Token close = expect_token(f, Token_CloseBracket);
|
||||||
|
|
||||||
return ast_bit_set_type(f, token, base);
|
return ast_bit_set_type(f, token, elem, underlying);
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
+2
-1
@@ -483,7 +483,8 @@ AST_KIND(_TypeBegin, "", bool) \
|
|||||||
}) \
|
}) \
|
||||||
AST_KIND(BitSetType, "bit set type", struct { \
|
AST_KIND(BitSetType, "bit set type", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
Ast * base; \
|
Ast * elem; \
|
||||||
|
Ast * underlying; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(MapType, "map type", struct { \
|
AST_KIND(MapType, "map type", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
|
|||||||
+28
-5
@@ -179,7 +179,8 @@ struct TypeStruct {
|
|||||||
i64 custom_align; \
|
i64 custom_align; \
|
||||||
}) \
|
}) \
|
||||||
TYPE_KIND(BitSet, struct { \
|
TYPE_KIND(BitSet, struct { \
|
||||||
Type *base; \
|
Type *elem; \
|
||||||
|
Type *underlying; \
|
||||||
i64 lower; \
|
i64 lower; \
|
||||||
i64 upper; \
|
i64 upper; \
|
||||||
}) \
|
}) \
|
||||||
@@ -981,10 +982,28 @@ bool is_type_valid_for_keys(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_type_valid_bit_set_elem(Type *t) {
|
||||||
|
if (is_type_enum(t)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
t = core_type(t);
|
||||||
|
if (t->kind == Type_Generic) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *bit_set_to_int(Type *t) {
|
Type *bit_set_to_int(Type *t) {
|
||||||
GB_ASSERT(is_type_bit_set(t));
|
GB_ASSERT(is_type_bit_set(t));
|
||||||
|
Type *bt = base_type(t);
|
||||||
|
Type *underlying = bt->BitSet.underlying;
|
||||||
|
if (underlying != nullptr && is_type_integer(underlying)) {
|
||||||
|
return underlying;
|
||||||
|
}
|
||||||
|
|
||||||
i64 sz = type_size_of(t);
|
i64 sz = type_size_of(t);
|
||||||
switch (sz) {
|
switch (sz) {
|
||||||
|
case 0: return t_u8;
|
||||||
case 1: return t_u8;
|
case 1: return t_u8;
|
||||||
case 2: return t_u16;
|
case 2: return t_u16;
|
||||||
case 4: return t_u32;
|
case 4: return t_u32;
|
||||||
@@ -1277,7 +1296,7 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
|
|
||||||
case Type_BitSet:
|
case Type_BitSet:
|
||||||
if (y->kind == Type_BitSet) {
|
if (y->kind == Type_BitSet) {
|
||||||
return are_types_identical(x->BitSet.base, y->BitSet.base);
|
return are_types_identical(x->BitSet.elem, y->BitSet.elem);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2069,8 +2088,10 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_BitSet: {
|
case Type_BitSet: {
|
||||||
|
if (t->BitSet.underlying != nullptr) {
|
||||||
|
return type_align_of(t->BitSet.underlying);
|
||||||
|
}
|
||||||
i64 bits = t->BitSet.upper - t->BitSet.lower + 1;
|
i64 bits = t->BitSet.upper - t->BitSet.lower + 1;
|
||||||
if (bits == 0) return 0;
|
|
||||||
if (bits <= 8) return 1;
|
if (bits <= 8) return 1;
|
||||||
if (bits <= 16) return 2;
|
if (bits <= 16) return 2;
|
||||||
if (bits <= 32) return 4;
|
if (bits <= 32) return 4;
|
||||||
@@ -2296,8 +2317,10 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_BitSet: {
|
case Type_BitSet: {
|
||||||
|
if (t->BitSet.underlying != nullptr) {
|
||||||
|
return type_size_of(t->BitSet.underlying);
|
||||||
|
}
|
||||||
i64 bits = t->BitSet.upper - t->BitSet.lower + 1;
|
i64 bits = t->BitSet.upper - t->BitSet.lower + 1;
|
||||||
if (bits == 0) return 0;
|
|
||||||
if (bits <= 8) return 1;
|
if (bits <= 8) return 1;
|
||||||
if (bits <= 16) return 2;
|
if (bits <= 16) return 2;
|
||||||
if (bits <= 32) return 4;
|
if (bits <= 32) return 4;
|
||||||
@@ -2617,7 +2640,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
|
|
||||||
case Type_BitSet:
|
case Type_BitSet:
|
||||||
str = gb_string_appendc(str, "bit_set[");
|
str = gb_string_appendc(str, "bit_set[");
|
||||||
str = write_type_to_string(str, type->BitSet.base);
|
str = write_type_to_string(str, type->BitSet.elem);
|
||||||
str = gb_string_appendc(str, "]");
|
str = gb_string_appendc(str, "]");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user