mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00: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) {
|
write_i64 :: proc(buf: ^String_Buffer, i: i64, base: int) {
|
||||||
b: [129]byte;
|
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);
|
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_i64(buf, i64(info.bits[i]), 10);
|
||||||
}
|
}
|
||||||
write_string(buf, "}");
|
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) {
|
fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||||
if v.data == nil || v.typeid == nil {
|
if v.data == nil || v.typeid == nil {
|
||||||
write_string(fi.buf, "<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');
|
if hash do for in 0..indent-1 do write_byte(fi.buf, '\t');
|
||||||
write_byte(fi.buf, '}');
|
write_byte(fi.buf, '}');
|
||||||
|
|
||||||
|
case runtime.Type_Info_Bit_Set:
|
||||||
|
fmt_bit_set(fi, v);
|
||||||
case:
|
case:
|
||||||
fmt_value(fi, any{v.data, typeid_of(info.base)}, verb);
|
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:
|
case runtime.Type_Info_Type_Id:
|
||||||
id := (^typeid)(v.data)^;
|
id := (^typeid)(v.data)^;
|
||||||
write_typeid(fi.buf, id);
|
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,
|
bits: []i32,
|
||||||
offsets: []i32,
|
offsets: []i32,
|
||||||
};
|
};
|
||||||
|
Type_Info_Bit_Set :: struct {
|
||||||
|
base: ^Type_Info,
|
||||||
|
};
|
||||||
|
|
||||||
Type_Info :: struct {
|
Type_Info :: struct {
|
||||||
size: int,
|
size: int,
|
||||||
@@ -127,6 +129,7 @@ Type_Info :: struct {
|
|||||||
Type_Info_Enum,
|
Type_Info_Enum,
|
||||||
Type_Info_Map,
|
Type_Info_Map,
|
||||||
Type_Info_Bit_Field,
|
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 {
|
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 {
|
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);
|
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];
|
i-=1; a[i] = digits[u % b];
|
||||||
|
|
||||||
if flags&Int_Flag.Prefix != 0 {
|
if flags&Int_Flag.Prefix != nil {
|
||||||
ok := true;
|
ok := true;
|
||||||
switch base {
|
switch base {
|
||||||
case 2: i-=1; a[i] = 'b';
|
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 {
|
switch {
|
||||||
case neg:
|
case neg:
|
||||||
i-=1; a[i] = '-';
|
i-=1; a[i] = '-';
|
||||||
case flags&Int_Flag.Plus != 0:
|
case flags&Int_Flag.Plus != nil:
|
||||||
i-=1; a[i] = '+';
|
i-=1; a[i] = '+';
|
||||||
case flags&Int_Flag.Space != 0:
|
case flags&Int_Flag.Space != nil:
|
||||||
i-=1; a[i] = ' ';
|
i-=1; a[i] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -712,6 +712,25 @@ deprecated_attribute :: proc() {
|
|||||||
// foo_v1(1);
|
// 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() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
general_stuff();
|
general_stuff();
|
||||||
@@ -725,5 +744,6 @@ main :: proc() {
|
|||||||
complete_switch();
|
complete_switch();
|
||||||
cstring_example();
|
cstring_example();
|
||||||
deprecated_attribute();
|
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:
|
case Type_Enum:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
case Type_BitSet:
|
||||||
|
return false;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
if (source->kind == Type_Union) {
|
if (source->kind == Type_Union) {
|
||||||
TypeUnion *x = &poly->Union;
|
TypeUnion *x = &poly->Union;
|
||||||
@@ -1115,8 +1118,8 @@ bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Token_Xor:
|
case Token_Xor:
|
||||||
if (!is_type_integer(type) && !is_type_boolean(type)) {
|
if (!is_type_integer(type) && !is_type_boolean(type) && !is_type_bit_set(type)) {
|
||||||
error(op, "Operator '%.*s' is only allowed with integers or booleans", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with integers, booleans, or bit sets", LIT(op.string));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1142,33 +1145,17 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
|||||||
switch (op.kind) {
|
switch (op.kind) {
|
||||||
case Token_Sub:
|
case Token_Sub:
|
||||||
case Token_SubEq:
|
case Token_SubEq:
|
||||||
if (!is_type_numeric(type) && !is_type_pointer(type)) {
|
if (!is_type_numeric(type)) {
|
||||||
error(op, "Operator '%.*s' is only allowed with numeric or pointer expressions", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with numeric 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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case Token_Mul:
|
case Token_Mul:
|
||||||
case Token_Quo:
|
case Token_Quo:
|
||||||
case Token_AddEq:
|
|
||||||
case Token_MulEq:
|
case Token_MulEq:
|
||||||
case Token_QuoEq:
|
case Token_QuoEq:
|
||||||
|
case Token_AddEq:
|
||||||
if (!is_type_numeric(type)) {
|
if (!is_type_numeric(type)) {
|
||||||
error(op, "Operator '%.*s' is only allowed with numeric expressions", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with numeric expressions", LIT(op.string));
|
||||||
return false;
|
return false;
|
||||||
@@ -1194,24 +1181,30 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
|||||||
case Token_OrEq:
|
case Token_OrEq:
|
||||||
case Token_Xor:
|
case Token_Xor:
|
||||||
case Token_XorEq:
|
case Token_XorEq:
|
||||||
if (!is_type_integer(type) && !is_type_boolean(type)) {
|
if (!is_type_integer(type) && !is_type_boolean(type) && !is_type_bit_set(type)) {
|
||||||
error(op, "Operator '%.*s' is only allowed with integers or booleans", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with integers, booleans, or bit sets", LIT(op.string));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token_Mod:
|
case Token_Mod:
|
||||||
case Token_ModMod:
|
case Token_ModMod:
|
||||||
case Token_AndNot:
|
|
||||||
case Token_ModEq:
|
case Token_ModEq:
|
||||||
case Token_ModModEq:
|
case Token_ModModEq:
|
||||||
case Token_AndNotEq:
|
|
||||||
if (!is_type_integer(type)) {
|
if (!is_type_integer(type)) {
|
||||||
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
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_CmpAnd:
|
||||||
case Token_CmpOr:
|
case Token_CmpOr:
|
||||||
case Token_CmpAndEq:
|
case Token_CmpAndEq:
|
||||||
@@ -2329,7 +2322,11 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
|||||||
return;
|
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) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
if (operand->mode == Addressing_Constant) {
|
if (operand->mode == Addressing_Constant) {
|
||||||
@@ -4264,6 +4261,12 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
|
|||||||
} else {
|
} else {
|
||||||
pt = type_to_string(t);
|
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;
|
String name = proc->token.string;
|
||||||
|
|
||||||
char const *sep = "::";
|
char const *sep = "::";
|
||||||
@@ -4271,7 +4274,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
|
|||||||
sep = ":=";
|
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) 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) {
|
if (procs.count > 0) {
|
||||||
gb_printf_err("\n");
|
gb_printf_err("\n");
|
||||||
@@ -5096,9 +5099,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Struct: {
|
case Type_Struct: {
|
||||||
if (is_type_union(t)) {
|
|
||||||
is_constant = false;
|
|
||||||
}
|
|
||||||
if (cl->elems.count == 0) {
|
if (cl->elems.count == 0) {
|
||||||
break; // NOTE(bill): No need to init
|
break; // NOTE(bill): No need to init
|
||||||
}
|
}
|
||||||
@@ -5111,7 +5111,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Checker values
|
if (is_type_struct(t)) { // Checker values
|
||||||
isize field_count = t->Struct.fields.count;
|
isize field_count = t->Struct.fields.count;
|
||||||
isize min_field_count = t->Struct.fields.count;
|
isize min_field_count = t->Struct.fields.count;
|
||||||
for (isize i = min_field_count-1; i >= 0; i--) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5409,6 +5410,39 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
break;
|
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: {
|
default: {
|
||||||
if (cl->elems.count == 0) {
|
if (cl->elems.count == 0) {
|
||||||
break; // NOTE(bill): No need to init
|
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);
|
str = write_expr_to_string(str, at->elem);
|
||||||
case_end;
|
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);
|
case_ast_node(mt, MapType, node);
|
||||||
str = gb_string_appendc(str, "map[");
|
str = gb_string_appendc(str, "map[");
|
||||||
str = write_expr_to_string(str, mt->key);
|
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) {
|
bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
|
||||||
if (type == nullptr ||
|
if (type == nullptr ||
|
||||||
type == t_invalid) {
|
type == t_invalid) {
|
||||||
@@ -1014,6 +1067,12 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
type = t_invalid;
|
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 = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
|
||||||
param->TypeName.is_type_alias = true;
|
param->TypeName.is_type_alias = true;
|
||||||
} else {
|
} 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_enum_type(ctx, *type, named_type, e);
|
||||||
check_close_scope(ctx);
|
check_close_scope(ctx);
|
||||||
(*type)->Enum.node = e;
|
(*type)->Enum.node = e;
|
||||||
|
|
||||||
|
ctx->in_enum_type = false;
|
||||||
return true;
|
return true;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(et, BitFieldType, e);
|
case_ast_node(et, BitFieldType, e);
|
||||||
*type = alloc_type_bit_field();
|
*type = alloc_type_bit_field();
|
||||||
set_base_type(named_type, *type);
|
set_base_type(named_type, *type);
|
||||||
check_open_scope(ctx, e);
|
|
||||||
check_bit_field_type(ctx, *type, 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);
|
check_close_scope(ctx);
|
||||||
return true;
|
return true;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
case_ast_node(pt, ProcType, e);
|
case_ast_node(pt, ProcType, e);
|
||||||
bool ips = ctx->in_polymorphic_specialization;
|
bool ips = ctx->in_polymorphic_specialization;
|
||||||
defer (ctx->in_polymorphic_specialization = ips);
|
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);
|
add_type_info_type(c, bt->Enum.base_type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_BitSet:
|
||||||
|
add_type_info_type(c, bt->BitSet.base_type);
|
||||||
|
break;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
add_type_info_type(c, t_int);
|
add_type_info_type(c, t_int);
|
||||||
add_type_info_type(c, t_type_info_ptr);
|
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_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_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_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_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);
|
||||||
@@ -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_enum_ptr = alloc_type_pointer(t_type_info_enum);
|
||||||
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
|
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_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) {
|
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
|
// boolean -> boolean/integer
|
||||||
if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) {
|
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));
|
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));
|
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_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) {
|
bool is_double_pointer(Type *t) {
|
||||||
if (!is_type_pointer(t)) {
|
if (!is_type_pointer(t)) {
|
||||||
@@ -5610,8 +5608,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
|
|
||||||
Type *et = nullptr;
|
Type *et = nullptr;
|
||||||
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_type; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
String proc_name = {};
|
String proc_name = {};
|
||||||
@@ -5821,7 +5820,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
ir_emit_store(proc, gep, fv);
|
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);
|
return ir_addr(v);
|
||||||
@@ -8025,8 +8059,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
}
|
}
|
||||||
break;
|
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) {
|
if (tag != nullptr) {
|
||||||
Type *tag_type = type_deref(ir_type(tag));
|
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);
|
String str = i64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
|
||||||
ir_write_string(f, str);
|
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) {
|
void ir_write_big_int(irFileBuffer *f, BigInt const &x) {
|
||||||
i64 i = 0;
|
i64 i = 0;
|
||||||
if (x.neg) {
|
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);
|
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size);
|
||||||
break;
|
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, '}');
|
ir_write_byte(f, '}');
|
||||||
if (type->Struct.is_packed) 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 {
|
} else {
|
||||||
ir_write_str_lit(f, "zeroinitializer");
|
ir_write_str_lit(f, "zeroinitializer");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ Token ast_token(Ast *node) {
|
|||||||
case Ast_UnionType: return node->UnionType.token;
|
case Ast_UnionType: return node->UnionType.token;
|
||||||
case Ast_EnumType: return node->EnumType.token;
|
case Ast_EnumType: return node->EnumType.token;
|
||||||
case Ast_BitFieldType: return node->BitFieldType.token;
|
case Ast_BitFieldType: return node->BitFieldType.token;
|
||||||
|
case Ast_BitSetType: return node->BitSetType.token;
|
||||||
case Ast_MapType: return node->MapType.token;
|
case Ast_MapType: return node->MapType.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,6 +345,10 @@ Ast *clone_ast(Ast *node) {
|
|||||||
case Ast_BitFieldType:
|
case Ast_BitFieldType:
|
||||||
n->BitFieldType.fields = clone_ast_array(n->BitFieldType.fields);
|
n->BitFieldType.fields = clone_ast_array(n->BitFieldType.fields);
|
||||||
n->BitFieldType.align = clone_ast(n->BitFieldType.align);
|
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:
|
case Ast_MapType:
|
||||||
n->MapType.count = clone_ast(n->MapType.count);
|
n->MapType.count = clone_ast(n->MapType.count);
|
||||||
n->MapType.key = clone_ast(n->MapType.key);
|
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;
|
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 *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_MapType);
|
Ast *result = alloc_ast_node(f, Ast_MapType);
|
||||||
result->MapType.token = token;
|
result->MapType.token = token;
|
||||||
@@ -1962,6 +1974,15 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
return ast_bit_field_type(f, token, fields, align);
|
return ast_bit_field_type(f, token, fields, align);
|
||||||
} break;
|
} 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: {
|
default: {
|
||||||
#if 0
|
#if 0
|
||||||
Ast *type = parse_type_or_ident(f);
|
Ast *type = parse_type_or_ident(f);
|
||||||
|
|||||||
@@ -480,6 +480,10 @@ AST_KIND(_TypeBegin, "", bool) \
|
|||||||
Array<Ast *> fields; /* FieldValue with : */ \
|
Array<Ast *> fields; /* FieldValue with : */ \
|
||||||
Ast * align; \
|
Ast * align; \
|
||||||
}) \
|
}) \
|
||||||
|
AST_KIND(BitSetType, "bit set type", struct { \
|
||||||
|
Token token; \
|
||||||
|
Ast * base_type; \
|
||||||
|
}) \
|
||||||
AST_KIND(MapType, "map type", struct { \
|
AST_KIND(MapType, "map type", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
Ast *count; \
|
Ast *count; \
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
|||||||
TOKEN_KIND(Token_union, "union"), \
|
TOKEN_KIND(Token_union, "union"), \
|
||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||||
|
TOKEN_KIND(Token_bit_set, "bit_set"), \
|
||||||
TOKEN_KIND(Token_map, "map"), \
|
TOKEN_KIND(Token_map, "map"), \
|
||||||
TOKEN_KIND(Token_static, "static"), \
|
TOKEN_KIND(Token_static, "static"), \
|
||||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||||
|
|||||||
@@ -178,6 +178,11 @@ struct TypeStruct {
|
|||||||
Scope * scope; \
|
Scope * scope; \
|
||||||
i64 custom_align; \
|
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_enum = nullptr;
|
||||||
gb_global Type *t_type_info_map = 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_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_named_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_integer_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_enum_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_map_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_field_ptr = nullptr;
|
||||||
|
gb_global Type *t_type_info_bit_set_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;
|
||||||
@@ -607,6 +614,10 @@ Type *alloc_type_bit_field() {
|
|||||||
Type *t = alloc_type(Type_BitField);
|
Type *t = alloc_type(Type_BitField);
|
||||||
return t;
|
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);
|
t = base_type(t);
|
||||||
return (t->kind == Type_BitFieldValue);
|
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) {
|
bool is_type_map(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return t->kind == Type_Map;
|
return t->kind == Type_Map;
|
||||||
@@ -963,6 +978,19 @@ bool is_type_valid_for_keys(Type *t) {
|
|||||||
return false;
|
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) {
|
bool is_type_indexable(Type *t) {
|
||||||
Type *bt = base_type(t);
|
Type *bt = base_type(t);
|
||||||
@@ -1108,6 +1136,10 @@ bool type_has_nil(Type *t) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} break;
|
} break;
|
||||||
|
case Type_Enum:
|
||||||
|
case Type_BitSet:
|
||||||
|
case Type_BitField:
|
||||||
|
return true;
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
@@ -1158,6 +1190,9 @@ bool is_type_comparable(Type *t) {
|
|||||||
return is_type_comparable(t->Array.elem);
|
return is_type_comparable(t->Array.elem);
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case Type_BitSet:
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1237,6 +1272,12 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case Type_Enum:
|
||||||
return x == y; // NOTE(bill): All enums are unique
|
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);
|
return gb_clamp(next_pow2(align), 1, build_context.max_align);
|
||||||
} break;
|
} 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);
|
// 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);
|
GB_ASSERT((bits%8) == 0);
|
||||||
return bits/8;
|
return bits/8;
|
||||||
} break;
|
} 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
|
// Catch all
|
||||||
@@ -2549,6 +2610,12 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
case Type_BitFieldValue:
|
case Type_BitFieldValue:
|
||||||
str = gb_string_append_fmt(str, "(bit field value with %d bits)", cast(int)type->BitFieldValue.bits);
|
str = gb_string_append_fmt(str, "(bit field value with %d bits)", cast(int)type->BitFieldValue.bits);
|
||||||
break;
|
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;
|
return str;
|
||||||
|
|||||||
Reference in New Issue
Block a user