mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-18 11:52:22 -07:00
Add bit_set type
This commit is contained in:
+87
-1
@@ -70,7 +70,7 @@ write_rune :: proc(buf: ^String_Buffer, r: rune) {
|
||||
|
||||
write_i64 :: proc(buf: ^String_Buffer, i: i64, base: int) {
|
||||
b: [129]byte;
|
||||
s := strconv.append_bits(b[:], u64(i), base, true, 64, strconv.digits, 0);
|
||||
s := strconv.append_bits(b[:], u64(i), base, true, 64, strconv.digits, nil);
|
||||
write_string(buf, s);
|
||||
}
|
||||
|
||||
@@ -312,6 +312,11 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_string(buf, "}");
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
write_string(buf, "bit_set[");
|
||||
write_type(buf, info.base);
|
||||
write_string(buf, "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,6 +719,82 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 {
|
||||
switch i in ev {
|
||||
case rune: return u64(i);
|
||||
case i8: return u64(i);
|
||||
case i16: return u64(i);
|
||||
case i32: return u64(i);
|
||||
case i64: return u64(i);
|
||||
case int: return u64(i);
|
||||
case u8: return u64(i);
|
||||
case u16: return u64(i);
|
||||
case u32: return u64(i);
|
||||
case u64: return u64(i);
|
||||
case uint: return u64(i);
|
||||
case uintptr: return u64(i);
|
||||
case f32: return u64(i);
|
||||
case f64: return u64(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
||||
type_info := type_info_of(v.typeid);
|
||||
switch info in type_info.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
val := v;
|
||||
val.typeid = info.base.id;
|
||||
fmt_bit_set(fi, val, info.name);
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
bits: u64;
|
||||
bit_size := u64(8*type_info.size);
|
||||
verb := 'b';
|
||||
|
||||
switch bit_size {
|
||||
case 0: bits = 0;
|
||||
case 8: bits = u64( (^u8)(v.data)^);
|
||||
case 16: bits = u64((^u16)(v.data)^);
|
||||
case 32: bits = u64((^u32)(v.data)^);
|
||||
case 64: bits = u64((^u64)(v.data)^);
|
||||
case: panic("unknown bit_size size");
|
||||
}
|
||||
|
||||
et := runtime.type_info_base(info.base);
|
||||
e := et.variant.(runtime.Type_Info_Enum);
|
||||
|
||||
if name != "" {
|
||||
write_string(fi.buf, name);
|
||||
} else {
|
||||
write_type(fi.buf, type_info);
|
||||
}
|
||||
write_byte(fi.buf, '{');
|
||||
defer write_byte(fi.buf, '}');
|
||||
|
||||
commas := 0;
|
||||
loop: for i in 0 .. bit_size-1 {
|
||||
if bits & (1<<i) == 0 {
|
||||
continue loop;
|
||||
}
|
||||
|
||||
if commas > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
defer commas += 1;
|
||||
|
||||
for ev, evi in e.values {
|
||||
v := enum_value_to_u64(ev);
|
||||
if v == i {
|
||||
write_string(fi.buf, e.names[evi]);
|
||||
continue loop;
|
||||
}
|
||||
}
|
||||
write_i64(fi.buf, i64(i), 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if v.data == nil || v.typeid == nil {
|
||||
write_string(fi.buf, "<nil>");
|
||||
@@ -765,6 +846,8 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if hash do for in 0..indent-1 do write_byte(fi.buf, '\t');
|
||||
write_byte(fi.buf, '}');
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
fmt_bit_set(fi, v);
|
||||
case:
|
||||
fmt_value(fi, any{v.data, typeid_of(info.base)}, verb);
|
||||
}
|
||||
@@ -929,6 +1012,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
case runtime.Type_Info_Type_Id:
|
||||
id := (^typeid)(v.data)^;
|
||||
write_typeid(fi.buf, id);
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
fmt_bit_set(fi, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,9 @@ Type_Info_Bit_Field :: struct {
|
||||
bits: []i32,
|
||||
offsets: []i32,
|
||||
};
|
||||
|
||||
Type_Info_Bit_Set :: struct {
|
||||
base: ^Type_Info,
|
||||
};
|
||||
|
||||
Type_Info :: struct {
|
||||
size: int,
|
||||
@@ -127,6 +129,7 @@ Type_Info :: struct {
|
||||
Type_Info_Enum,
|
||||
Type_Info_Map,
|
||||
Type_Info_Bit_Field,
|
||||
Type_Info_Bit_Set,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package runtime
|
||||
|
||||
foreign import kernel32 "system:Kernel32.lib"
|
||||
|
||||
@(link_name="memcpy")
|
||||
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
foreign kernel32 {
|
||||
RtlCopyMemory :: proc "c" (dst, src: rawptr, len: int) ---
|
||||
}
|
||||
RtlCopyMemory(dst, src, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@(link_name="memmove")
|
||||
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
foreign kernel32 {
|
||||
RtlMoveMemory :: proc "c" (dst, src: rawptr, len: int) ---
|
||||
}
|
||||
RtlMoveMemory(dst, src, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@(link_name="memset")
|
||||
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
|
||||
foreign kernel32 {
|
||||
RtlFillMemory :: proc "c" (dst: rawptr, len: int, fill: byte) ---
|
||||
}
|
||||
RtlFillMemory(ptr, len, byte(val));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// @(link_name="memcmp")
|
||||
// memcmp :: proc "c" (dst, src: rawptr, len: int) -> i32 {
|
||||
// if dst == nil || src == nil {
|
||||
// return 0;
|
||||
// }
|
||||
// if dst == src {
|
||||
// return 0;
|
||||
// }
|
||||
// d, s := uintptr(dst), uintptr(src);
|
||||
// n := uintptr(len);
|
||||
|
||||
// for i := uintptr(0); i < n; i += 1 {
|
||||
// x, y := (^byte)(d+i)^, (^byte)(s+i)^;
|
||||
// if x != y {
|
||||
// return x < y ? -1 : +1;
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
@@ -198,10 +198,10 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
}
|
||||
|
||||
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, 0);
|
||||
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, nil);
|
||||
}
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
|
||||
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil);
|
||||
}
|
||||
itoa :: proc(buf: []byte, i: int) -> string do return append_int(buf, i64(i), 10);
|
||||
|
||||
@@ -474,7 +474,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
||||
}
|
||||
i-=1; a[i] = digits[u % b];
|
||||
|
||||
if flags&Int_Flag.Prefix != 0 {
|
||||
if flags&Int_Flag.Prefix != nil {
|
||||
ok := true;
|
||||
switch base {
|
||||
case 2: i-=1; a[i] = 'b';
|
||||
@@ -492,9 +492,9 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
||||
switch {
|
||||
case neg:
|
||||
i-=1; a[i] = '-';
|
||||
case flags&Int_Flag.Plus != 0:
|
||||
case flags&Int_Flag.Plus != nil:
|
||||
i-=1; a[i] = '+';
|
||||
case flags&Int_Flag.Space != 0:
|
||||
case flags&Int_Flag.Space != nil:
|
||||
i-=1; a[i] = ' ';
|
||||
}
|
||||
|
||||
|
||||
@@ -712,6 +712,25 @@ deprecated_attribute :: proc() {
|
||||
// foo_v1(1);
|
||||
}
|
||||
|
||||
bit_set_type :: proc() {
|
||||
using Day :: enum {
|
||||
Sunday,
|
||||
Monday,
|
||||
Tuesday,
|
||||
Wednesday,
|
||||
Thursday,
|
||||
Friday,
|
||||
Saturday,
|
||||
}
|
||||
|
||||
Days :: distinct bit_set[Day];
|
||||
d: Days;
|
||||
d = Days{Sunday};
|
||||
x := Tuesday;
|
||||
d |= Days{Saturday, x};
|
||||
fmt.println(d);
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
general_stuff();
|
||||
@@ -725,5 +744,6 @@ main :: proc() {
|
||||
complete_switch();
|
||||
cstring_example();
|
||||
deprecated_attribute();
|
||||
bit_set_type();
|
||||
}
|
||||
}
|
||||
|
||||
+83
-31
@@ -841,6 +841,9 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
case Type_Enum:
|
||||
return false;
|
||||
|
||||
case Type_BitSet:
|
||||
return false;
|
||||
|
||||
case Type_Union:
|
||||
if (source->kind == Type_Union) {
|
||||
TypeUnion *x = &poly->Union;
|
||||
@@ -1115,8 +1118,8 @@ bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
break;
|
||||
|
||||
case Token_Xor:
|
||||
if (!is_type_integer(type) && !is_type_boolean(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with integers or booleans", LIT(op.string));
|
||||
if (!is_type_integer(type) && !is_type_boolean(type) && !is_type_bit_set(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with integers, booleans, or bit sets", LIT(op.string));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1142,33 +1145,17 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
switch (op.kind) {
|
||||
case Token_Sub:
|
||||
case Token_SubEq:
|
||||
if (!is_type_numeric(type) && !is_type_pointer(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with numeric or pointer expressions", LIT(op.string));
|
||||
return false;
|
||||
}
|
||||
#if defined(NO_POINTER_ARITHMETIC)
|
||||
if (is_type_pointer(type)) {
|
||||
error(o->expr, "Pointer arithmetic is not supported");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (is_type_pointer(type)) {
|
||||
o->type = t_int;
|
||||
}
|
||||
if (base_type(type) == t_rawptr) {
|
||||
gbString str = type_to_string(type);
|
||||
error(o->expr, "Invalid pointer type for pointer arithmetic: '%s'", str);
|
||||
gb_string_free(str);
|
||||
if (!is_type_numeric(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with numeric expressions", LIT(op.string));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case Token_Mul:
|
||||
case Token_Quo:
|
||||
case Token_AddEq:
|
||||
case Token_MulEq:
|
||||
case Token_QuoEq:
|
||||
case Token_AddEq:
|
||||
if (!is_type_numeric(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with numeric expressions", LIT(op.string));
|
||||
return false;
|
||||
@@ -1194,24 +1181,30 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
case Token_OrEq:
|
||||
case Token_Xor:
|
||||
case Token_XorEq:
|
||||
if (!is_type_integer(type) && !is_type_boolean(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with integers or booleans", LIT(op.string));
|
||||
if (!is_type_integer(type) && !is_type_boolean(type) && !is_type_bit_set(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with integers, booleans, or bit sets", LIT(op.string));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_Mod:
|
||||
case Token_ModMod:
|
||||
case Token_AndNot:
|
||||
case Token_ModEq:
|
||||
case Token_ModModEq:
|
||||
case Token_AndNotEq:
|
||||
if (!is_type_integer(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_AndNot:
|
||||
case Token_AndNotEq:
|
||||
if (!is_type_integer(type) && !is_type_bit_set(type)) {
|
||||
error(op, "Operator '%.*s' is only allowed with integers and bit sets", LIT(op.string));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_CmpAnd:
|
||||
case Token_CmpOr:
|
||||
case Token_CmpAndEq:
|
||||
@@ -2329,7 +2322,11 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
||||
return;
|
||||
}
|
||||
|
||||
Type *t = core_type(target_type);
|
||||
Type *t = base_type(target_type);
|
||||
if (c->in_enum_type) {
|
||||
t = core_type(target_type);
|
||||
}
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
@@ -4264,6 +4261,12 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
|
||||
} else {
|
||||
pt = type_to_string(t);
|
||||
}
|
||||
String prefix = {};
|
||||
String prefix_sep = {};
|
||||
if (proc->pkg) {
|
||||
prefix = proc->pkg->name;
|
||||
prefix_sep = str_lit(".");
|
||||
}
|
||||
String name = proc->token.string;
|
||||
|
||||
char const *sep = "::";
|
||||
@@ -4271,7 +4274,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
|
||||
sep = ":=";
|
||||
}
|
||||
// gb_printf_err("\t%.*s %s %s at %.*s(%td:%td) with score %lld\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
|
||||
gb_printf_err("\t%.*s %s %s at %.*s(%td:%td)\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column);
|
||||
gb_printf_err("\t%.*s%.*s%.*s %s %s at %.*s(%td:%td)\n", LIT(prefix), LIT(prefix_sep), LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
if (procs.count > 0) {
|
||||
gb_printf_err("\n");
|
||||
@@ -5096,9 +5099,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Struct: {
|
||||
if (is_type_union(t)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (cl->elems.count == 0) {
|
||||
break; // NOTE(bill): No need to init
|
||||
}
|
||||
@@ -5111,7 +5111,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
break;
|
||||
}
|
||||
|
||||
{ // Checker values
|
||||
if (is_type_struct(t)) { // Checker values
|
||||
isize field_count = t->Struct.fields.count;
|
||||
isize min_field_count = t->Struct.fields.count;
|
||||
for (isize i = min_field_count-1; i >= 0; i--) {
|
||||
@@ -5220,6 +5220,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5409,6 +5410,39 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
break;
|
||||
}
|
||||
|
||||
case Type_BitSet: {
|
||||
if (cl->elems.count == 0) {
|
||||
break; // NOTE(bill): No need to init
|
||||
}
|
||||
Type *et = base_type(t->BitSet.base_type);
|
||||
isize field_count = 0;
|
||||
if (et->kind == Type_Enum) {
|
||||
field_count = et->Enum.fields.count;
|
||||
}
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed");
|
||||
} else {
|
||||
for_array(index, cl->elems) {
|
||||
Entity *field = nullptr;
|
||||
Ast *elem = cl->elems[index];
|
||||
if (elem->kind == Ast_FieldValue) {
|
||||
error(elem, "'field = value' in a bit_set a literal is not allowed");
|
||||
continue;
|
||||
}
|
||||
|
||||
check_expr(c, o, elem);
|
||||
|
||||
if (is_constant) {
|
||||
is_constant = o->mode == Addressing_Constant;
|
||||
}
|
||||
|
||||
check_assignment(c, o, t->BitSet.base_type, str_lit("bit_set literal"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (cl->elems.count == 0) {
|
||||
break; // NOTE(bill): No need to init
|
||||
@@ -6108,6 +6142,24 @@ gbString write_expr_to_string(gbString str, Ast *node) {
|
||||
str = write_expr_to_string(str, at->elem);
|
||||
case_end;
|
||||
|
||||
case_ast_node(bf, BitFieldType, node);
|
||||
str = gb_string_appendc(str, "bit_field ");
|
||||
if (bf->align) {
|
||||
str = gb_string_appendc(str, "#align ");
|
||||
str = write_expr_to_string(str, bf->align);
|
||||
}
|
||||
str = gb_string_appendc(str, "{");
|
||||
str = write_struct_fields_to_string(str, bf->fields);
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(bs, BitSetType, node);
|
||||
str = gb_string_appendc(str, "bit_set[");
|
||||
str = write_expr_to_string(str, bs->base_type);
|
||||
str = gb_string_appendc(str, "]");
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(mt, MapType, node);
|
||||
str = gb_string_appendc(str, "map[");
|
||||
str = write_expr_to_string(str, mt->key);
|
||||
|
||||
+70
-1
@@ -681,6 +681,59 @@ void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Ast *node)
|
||||
}
|
||||
|
||||
|
||||
void check_bit_set_type(CheckerContext *ctx, Type *type, Ast *node) {
|
||||
ast_node(bs, BitSetType, node);
|
||||
GB_ASSERT(type->kind == Type_BitSet);
|
||||
|
||||
Type *bt = check_type_expr(ctx, bs->base_type, nullptr);
|
||||
|
||||
type->BitSet.base_type = bt;
|
||||
if (!is_type_enum(bt)) {
|
||||
error(bs->base_type, "Expected an enum type for a bit_set");
|
||||
} else {
|
||||
Type *et = base_type(bt);
|
||||
GB_ASSERT(et->kind == Type_Enum);
|
||||
if (!is_type_integer(et->Enum.base_type)) {
|
||||
error(bs->base_type, "Enum type for bit_set must be an integer");
|
||||
return;
|
||||
}
|
||||
i64 min_value = 0;
|
||||
i64 max_value = 0;
|
||||
BigInt v64 = {}; big_int_from_i64(&v64, 64);
|
||||
|
||||
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);
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
BigInt v = value.value_integer;
|
||||
|
||||
|
||||
if (big_int_cmp(&v, &BIG_INT_ZERO) < 0) {
|
||||
error(bs->base_type, "Negative enum values are not allowed in a bit_set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (big_int_cmp(&v, &v64) >= 0) {
|
||||
error(bs->base_type, "Enum values overe 64 are not allowed in a bit_set");
|
||||
return;
|
||||
}
|
||||
|
||||
i64 x = big_int_to_i64(&v);
|
||||
min_value = gb_min(min_value, x);
|
||||
max_value = gb_max(max_value, x);
|
||||
}
|
||||
|
||||
|
||||
type->BitSet.min = min_value;
|
||||
type->BitSet.max = max_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
|
||||
if (type == nullptr ||
|
||||
type == t_invalid) {
|
||||
@@ -1014,6 +1067,12 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_auto_cast) {
|
||||
error(name, "'auto_cast' can only be applied variable fields");
|
||||
p->flags &= ~FieldFlag_auto_cast;
|
||||
}
|
||||
|
||||
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
|
||||
param->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
@@ -1885,18 +1944,28 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
check_enum_type(ctx, *type, named_type, e);
|
||||
check_close_scope(ctx);
|
||||
(*type)->Enum.node = e;
|
||||
|
||||
ctx->in_enum_type = false;
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(et, BitFieldType, e);
|
||||
*type = alloc_type_bit_field();
|
||||
set_base_type(named_type, *type);
|
||||
check_open_scope(ctx, e);
|
||||
check_bit_field_type(ctx, *type, e);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(bs, BitSetType, e);
|
||||
*type = alloc_type_bit_set();
|
||||
set_base_type(named_type, *type);
|
||||
check_open_scope(ctx, e);
|
||||
check_bit_set_type(ctx, *type, e);
|
||||
check_close_scope(ctx);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(pt, ProcType, e);
|
||||
bool ips = ctx->in_polymorphic_specialization;
|
||||
defer (ctx->in_polymorphic_specialization = ips);
|
||||
|
||||
@@ -1043,6 +1043,10 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
add_type_info_type(c, bt->Enum.base_type);
|
||||
break;
|
||||
|
||||
case Type_BitSet:
|
||||
add_type_info_type(c, bt->BitSet.base_type);
|
||||
break;
|
||||
|
||||
case Type_Union:
|
||||
add_type_info_type(c, t_int);
|
||||
add_type_info_type(c, t_type_info_ptr);
|
||||
@@ -1600,6 +1604,7 @@ void init_core_type_info(Checker *c) {
|
||||
t_type_info_enum = find_core_type(c, str_lit("Type_Info_Enum"));
|
||||
t_type_info_map = find_core_type(c, str_lit("Type_Info_Map"));
|
||||
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
|
||||
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
|
||||
|
||||
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
|
||||
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
|
||||
@@ -1621,6 +1626,7 @@ void init_core_type_info(Checker *c) {
|
||||
t_type_info_enum_ptr = alloc_type_pointer(t_type_info_enum);
|
||||
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
|
||||
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
|
||||
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
|
||||
}
|
||||
|
||||
void init_mem_allocator(Checker *c) {
|
||||
|
||||
+46
-6
@@ -3275,8 +3275,6 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
||||
|
||||
// boolean -> boolean/integer
|
||||
if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) {
|
||||
GB_ASSERT(src != t_llvm_bool);
|
||||
|
||||
irValue *b = ir_emit(proc, ir_instr_binary_op(proc, Token_NotEq, value, v_zero, t_llvm_bool));
|
||||
return ir_emit(proc, ir_instr_conv(proc, irConv_zext, b, t_llvm_bool, t));
|
||||
}
|
||||
@@ -4247,7 +4245,7 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) {
|
||||
}
|
||||
|
||||
void ir_build_stmt_list(irProcedure *proc, Array<Ast *> stmts);
|
||||
|
||||
void ir_build_assign_op(irProcedure *proc, irAddr const &lhs, irValue *value, TokenKind op);
|
||||
|
||||
bool is_double_pointer(Type *t) {
|
||||
if (!is_type_pointer(t)) {
|
||||
@@ -5610,8 +5608,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
|
||||
Type *et = nullptr;
|
||||
switch (bt->kind) {
|
||||
case Type_Array: et = bt->Array.elem; break;
|
||||
case Type_Slice: et = bt->Slice.elem; break;
|
||||
case Type_Array: et = bt->Array.elem; break;
|
||||
case Type_Slice: et = bt->Slice.elem; break;
|
||||
case Type_BitSet: et = bt->BitSet.base_type; break;
|
||||
}
|
||||
|
||||
String proc_name = {};
|
||||
@@ -5821,7 +5820,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
ir_emit_store(proc, gep, fv);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type_BitSet: {
|
||||
|
||||
i64 sz = type_size_of(type);
|
||||
if (cl->elems.count > 0 && sz > 0) {
|
||||
ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
|
||||
|
||||
irValue *lower = ir_value_constant(t_int, exact_value_i64(bt->BitSet.min));
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
GB_ASSERT(elem->kind != Ast_FieldValue);
|
||||
|
||||
if (ir_is_elem_const(proc->module, elem, et)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
irValue *expr = ir_build_expr(proc, elem);
|
||||
GB_ASSERT(ir_type(expr)->kind != Type_Tuple);
|
||||
|
||||
Type *it = bit_set_to_int(bt);
|
||||
irValue *e = ir_emit_conv(proc, expr, it);
|
||||
e = ir_emit_arith(proc, Token_Sub, e, lower, it);
|
||||
e = ir_emit_arith(proc, Token_Shl, v_one, e, it);
|
||||
|
||||
irValue *old_value = ir_emit_bitcast(proc, ir_emit_load(proc, v), it);
|
||||
irValue *new_value = ir_emit_arith(proc, Token_Or, old_value, e, it);
|
||||
new_value = ir_emit_bitcast(proc, new_value, type);
|
||||
ir_emit_store(proc, v, new_value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ir_addr(v);
|
||||
@@ -8025,8 +8059,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case Type_BitSet:
|
||||
ir_emit_comment(proc, str_lit("Type_Info_Bit_Set"));
|
||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_bit_set_ptr);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->BitSet.base_type));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (tag != nullptr) {
|
||||
Type *tag_type = type_deref(ir_type(tag));
|
||||
|
||||
@@ -65,6 +65,10 @@ void ir_write_i64(irFileBuffer *f, i64 i) {
|
||||
String str = i64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
|
||||
ir_write_string(f, str);
|
||||
}
|
||||
void ir_write_u64(irFileBuffer *f, u64 i) {
|
||||
String str = u64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
|
||||
ir_write_string(f, str);
|
||||
}
|
||||
void ir_write_big_int(irFileBuffer *f, BigInt const &x) {
|
||||
i64 i = 0;
|
||||
if (x.neg) {
|
||||
@@ -502,6 +506,19 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type_BitSet: {
|
||||
i64 align = type_align_of(t);
|
||||
i64 size = type_size_of(t);
|
||||
switch (size) {
|
||||
case 0: ir_write_str_lit(f, "{}"); 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,6 +783,34 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
|
||||
ir_write_byte(f, '}');
|
||||
if (type->Struct.is_packed) ir_write_byte(f, '>');
|
||||
} else if (is_type_bit_set(type)) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
ir_write_str_lit(f, "zeroinitializer");
|
||||
break;
|
||||
}
|
||||
|
||||
i64 sz = type_size_of(type);
|
||||
if (sz == 0) {
|
||||
ir_write_str_lit(f, "zeroinitializer");
|
||||
break;
|
||||
}
|
||||
|
||||
u64 bits = 0;
|
||||
for_array(i, cl->elems) {
|
||||
Ast *e = cl->elems[i];
|
||||
GB_ASSERT(e->kind != Ast_FieldValue);
|
||||
|
||||
TypeAndValue tav = e->tav;
|
||||
if (tav.mode != Addressing_Constant) {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT(tav.value.kind == ExactValue_Integer);
|
||||
i64 v = big_int_to_i64(&tav.value.value_integer);
|
||||
i64 lower = type->BitSet.min;
|
||||
bits |= 1ull<<cast(u64)(v-lower);
|
||||
}
|
||||
ir_write_u64(f, bits);
|
||||
} else {
|
||||
ir_write_str_lit(f, "zeroinitializer");
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ Token ast_token(Ast *node) {
|
||||
case Ast_UnionType: return node->UnionType.token;
|
||||
case Ast_EnumType: return node->EnumType.token;
|
||||
case Ast_BitFieldType: return node->BitFieldType.token;
|
||||
case Ast_BitSetType: return node->BitSetType.token;
|
||||
case Ast_MapType: return node->MapType.token;
|
||||
}
|
||||
|
||||
@@ -344,6 +345,10 @@ Ast *clone_ast(Ast *node) {
|
||||
case Ast_BitFieldType:
|
||||
n->BitFieldType.fields = clone_ast_array(n->BitFieldType.fields);
|
||||
n->BitFieldType.align = clone_ast(n->BitFieldType.align);
|
||||
break;
|
||||
case Ast_BitSetType:
|
||||
n->BitSetType.base_type = clone_ast(n->BitSetType.base_type);
|
||||
break;
|
||||
case Ast_MapType:
|
||||
n->MapType.count = clone_ast(n->MapType.count);
|
||||
n->MapType.key = clone_ast(n->MapType.key);
|
||||
@@ -922,6 +927,13 @@ Ast *ast_bit_field_type(AstFile *f, Token token, Array<Ast *> fields, Ast *align
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_bit_set_type(AstFile *f, Token token, Ast *base_type) {
|
||||
Ast *result = alloc_ast_node(f, Ast_BitSetType);
|
||||
result->BitSetType.token = token;
|
||||
result->BitSetType.base_type = base_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) {
|
||||
Ast *result = alloc_ast_node(f, Ast_MapType);
|
||||
result->MapType.token = token;
|
||||
@@ -1962,6 +1974,15 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
return ast_bit_field_type(f, token, fields, align);
|
||||
} break;
|
||||
|
||||
case Token_bit_set: {
|
||||
Token token = expect_token(f, Token_bit_set);
|
||||
Token open = expect_token(f, Token_OpenBracket);
|
||||
Ast *base_type = parse_type(f);
|
||||
Token close = expect_token(f, Token_CloseBracket);
|
||||
|
||||
return ast_bit_set_type(f, token, base_type);
|
||||
}
|
||||
|
||||
default: {
|
||||
#if 0
|
||||
Ast *type = parse_type_or_ident(f);
|
||||
|
||||
@@ -480,6 +480,10 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
Array<Ast *> fields; /* FieldValue with : */ \
|
||||
Ast * align; \
|
||||
}) \
|
||||
AST_KIND(BitSetType, "bit set type", struct { \
|
||||
Token token; \
|
||||
Ast * base_type; \
|
||||
}) \
|
||||
AST_KIND(MapType, "map type", struct { \
|
||||
Token token; \
|
||||
Ast *count; \
|
||||
|
||||
@@ -105,6 +105,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||
TOKEN_KIND(Token_bit_set, "bit_set"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
|
||||
@@ -178,6 +178,11 @@ struct TypeStruct {
|
||||
Scope * scope; \
|
||||
i64 custom_align; \
|
||||
}) \
|
||||
TYPE_KIND(BitSet, struct { \
|
||||
Type *base_type; \
|
||||
i64 min; \
|
||||
i64 max; \
|
||||
}) \
|
||||
|
||||
|
||||
|
||||
@@ -376,6 +381,7 @@ gb_global Type *t_type_info_union = nullptr;
|
||||
gb_global Type *t_type_info_enum = nullptr;
|
||||
gb_global Type *t_type_info_map = nullptr;
|
||||
gb_global Type *t_type_info_bit_field = nullptr;
|
||||
gb_global Type *t_type_info_bit_set = nullptr;
|
||||
|
||||
gb_global Type *t_type_info_named_ptr = nullptr;
|
||||
gb_global Type *t_type_info_integer_ptr = nullptr;
|
||||
@@ -398,6 +404,7 @@ gb_global Type *t_type_info_union_ptr = nullptr;
|
||||
gb_global Type *t_type_info_enum_ptr = nullptr;
|
||||
gb_global Type *t_type_info_map_ptr = nullptr;
|
||||
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
||||
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
||||
|
||||
gb_global Type *t_allocator = nullptr;
|
||||
gb_global Type *t_allocator_ptr = nullptr;
|
||||
@@ -607,6 +614,10 @@ Type *alloc_type_bit_field() {
|
||||
Type *t = alloc_type(Type_BitField);
|
||||
return t;
|
||||
}
|
||||
Type *alloc_type_bit_set() {
|
||||
Type *t = alloc_type(Type_BitSet);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -903,6 +914,10 @@ bool is_type_bit_field_value(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_BitFieldValue);
|
||||
}
|
||||
bool is_type_bit_set(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_BitSet);
|
||||
}
|
||||
bool is_type_map(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Map;
|
||||
@@ -963,6 +978,19 @@ bool is_type_valid_for_keys(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *bit_set_to_int(Type *t) {
|
||||
GB_ASSERT(is_type_bit_set(t));
|
||||
i64 sz = type_size_of(t);
|
||||
switch (sz) {
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
case 8: return t_u64;
|
||||
}
|
||||
GB_PANIC("Unknown bit_set size");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_indexable(Type *t) {
|
||||
Type *bt = base_type(t);
|
||||
@@ -1108,6 +1136,10 @@ bool type_has_nil(Type *t) {
|
||||
}
|
||||
return false;
|
||||
} break;
|
||||
case Type_Enum:
|
||||
case Type_BitSet:
|
||||
case Type_BitField:
|
||||
return true;
|
||||
case Type_Slice:
|
||||
case Type_Proc:
|
||||
case Type_Pointer:
|
||||
@@ -1158,6 +1190,9 @@ bool is_type_comparable(Type *t) {
|
||||
return is_type_comparable(t->Array.elem);
|
||||
case Type_Proc:
|
||||
return true;
|
||||
|
||||
case Type_BitSet:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1237,6 +1272,12 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_BitSet:
|
||||
if (y->kind == Type_BitSet) {
|
||||
return are_types_identical(x->BitSet.base_type, y->BitSet.base_type);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case Type_Enum:
|
||||
return x == y; // NOTE(bill): All enums are unique
|
||||
@@ -2023,6 +2064,16 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
}
|
||||
return gb_clamp(next_pow2(align), 1, build_context.max_align);
|
||||
} break;
|
||||
|
||||
case Type_BitSet: {
|
||||
i64 bits = t->BitSet.max - t->BitSet.min + 1;
|
||||
if (bits == 0) return 0;
|
||||
if (bits <= 8) return 1;
|
||||
if (bits <= 16) return 2;
|
||||
if (bits <= 32) return 4;
|
||||
if (bits <= 64) return 8;
|
||||
GB_PANIC("unknown bit_set size");
|
||||
}
|
||||
}
|
||||
|
||||
// return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align);
|
||||
@@ -2239,6 +2290,16 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
|
||||
GB_ASSERT((bits%8) == 0);
|
||||
return bits/8;
|
||||
} break;
|
||||
|
||||
case Type_BitSet: {
|
||||
i64 bits = t->BitSet.max - t->BitSet.min + 1;
|
||||
if (bits == 0) return 0;
|
||||
if (bits <= 8) return 1;
|
||||
if (bits <= 16) return 2;
|
||||
if (bits <= 32) return 4;
|
||||
if (bits <= 64) return 8;
|
||||
GB_PANIC("unknown bit_set size");
|
||||
}
|
||||
}
|
||||
|
||||
// Catch all
|
||||
@@ -2549,6 +2610,12 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
case Type_BitFieldValue:
|
||||
str = gb_string_append_fmt(str, "(bit field value with %d bits)", cast(int)type->BitFieldValue.bits);
|
||||
break;
|
||||
|
||||
case Type_BitSet:
|
||||
str = gb_string_appendc(str, "bit_field[");
|
||||
str = write_type_to_string(str, type->BitSet.base_type);
|
||||
str = gb_string_appendc(str, "]");
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
|
||||
Reference in New Issue
Block a user