mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-26 17:30:02 +00:00
Add bit_set type
This commit is contained in:
+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