mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-22 13:44:59 -07:00
Begin work adding bit_field
This commit is contained in:
@@ -925,6 +925,144 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam
|
||||
enum_type->Enum.max_value_index = max_value_index;
|
||||
}
|
||||
|
||||
gb_internal bool is_valid_bit_field_backing_type(Type *type) {
|
||||
if (type == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
type = base_type(type);
|
||||
if (is_type_untyped(type)) {
|
||||
return false;
|
||||
}
|
||||
if (is_type_integer(type)) {
|
||||
return true;
|
||||
}
|
||||
if (type->kind == Type_Array) {
|
||||
return is_type_integer(type->Array.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Type *named_type, Ast *node) {
|
||||
ast_node(bf, BitFieldType, node);
|
||||
GB_ASSERT(is_type_bit_field(bit_field_type));
|
||||
|
||||
Type *backing_type = check_type(ctx, bf->backing_type);
|
||||
if (backing_type == nullptr || !is_valid_bit_field_backing_type(backing_type)) {
|
||||
error(node, "Backing type for a bit_field must be an integer or an array of an integer");
|
||||
return;
|
||||
}
|
||||
|
||||
bit_field_type->BitField.backing_type = backing_type;
|
||||
bit_field_type->BitField.scope = ctx->scope;
|
||||
|
||||
auto fields = array_make<Entity *>(permanent_allocator(), 0, bf->fields.count);
|
||||
auto bit_sizes = array_make<u8> (permanent_allocator(), 0, bf->fields.count);
|
||||
|
||||
u64 maximum_bit_size = 8 * type_size_of(backing_type);
|
||||
u64 total_bit_size = 0;
|
||||
|
||||
for_array(i, bf->fields) {
|
||||
i32 field_src_index = cast(i32)i;
|
||||
Ast *field = bf->fields[i];
|
||||
if (field->kind != Ast_BitFieldField) {
|
||||
error(field, "Invalid AST for a bit_field");
|
||||
continue;
|
||||
}
|
||||
ast_node(f, BitFieldField, field);
|
||||
if (f->name == nullptr || f->name->kind != Ast_Ident) {
|
||||
error(field, "A bit_field's field name must be an identifier");
|
||||
continue;
|
||||
}
|
||||
CommentGroup *docs = f->docs;
|
||||
CommentGroup *comment = f->comment;
|
||||
|
||||
String name = f->name->Ident.token.string;
|
||||
|
||||
if (f->type == nullptr) {
|
||||
error(field, "A bit_field's field must have a type");
|
||||
continue;
|
||||
}
|
||||
|
||||
Type *type = check_type(ctx, f->type);
|
||||
if (type_size_of(type) > 8) {
|
||||
error(f->type, "The type of a bit_field's field must be <= 8 bytes, got %lld", cast(long long)type_size_of(type));
|
||||
}
|
||||
|
||||
if (is_type_untyped(type)) {
|
||||
gbString s = type_to_string(type);
|
||||
error(f->type, "The type of a bit_field's field must be a typed integer, enum, or boolean, got %s", s);
|
||||
gb_string_free(s);
|
||||
} else if (!(is_type_integer(type) || is_type_enum(type) || is_type_boolean(type))) {
|
||||
gbString s = type_to_string(type);
|
||||
error(f->type, "The type of a bit_field's field must be an integer, enum, or boolean, got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
if (f->bit_size == nullptr) {
|
||||
error(field, "A bit_field's field must have a specified bit size");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Operand o = {};
|
||||
check_expr(ctx, &o, f->bit_size);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
error(f->bit_size, "A bit_field's specified bit size must be a constant");
|
||||
o.mode = Addressing_Invalid;
|
||||
}
|
||||
if (o.value.kind == ExactValue_Float) {
|
||||
o.value = exact_value_to_integer(o.value);
|
||||
}
|
||||
|
||||
ExactValue bit_size = o.value;
|
||||
|
||||
if (bit_size.kind != ExactValue_Integer) {
|
||||
gbString s = expr_to_string(f->bit_size);
|
||||
error(f->bit_size, "Expected an integer constant value for the specified bit size, got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
if (scope_lookup_current(ctx->scope, name) != nullptr) {
|
||||
error(f->name, "'%.*s' is already declared in this bit_field", LIT(name));
|
||||
} else {
|
||||
i64 bit_size_i64 = exact_value_to_i64(bit_size);
|
||||
u8 bit_size_u8 = 0;
|
||||
if (bit_size_i64 <= 0) {
|
||||
error(f->bit_size, "A bit_field's specified bit size cannot be <= 0, got %lld", cast(long long)bit_size_i64);
|
||||
bit_size_i64 = 1;
|
||||
}
|
||||
if (bit_size_i64 > 64) {
|
||||
error(f->bit_size, "A bit_field's specified bit size cannot exceed 64 bits, got %lld", cast(long long)bit_size_i64);
|
||||
bit_size_i64 = 64;
|
||||
}
|
||||
bit_size_u8 = cast(u8)bit_size_i64;
|
||||
|
||||
Entity *e = alloc_entity_field(ctx->scope, f->name->Ident.token, type, false, field_src_index);
|
||||
e->Variable.docs = docs;
|
||||
e->Variable.comment = comment;
|
||||
|
||||
add_entity(ctx, ctx->scope, nullptr, e);
|
||||
array_add(&fields, e);
|
||||
array_add(&bit_sizes, bit_size_u8);
|
||||
add_entity_use(ctx, field, e);
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT(fields.count <= bf->fields.count);
|
||||
|
||||
if (total_bit_size > maximum_bit_size) {
|
||||
gbString s = type_to_string(backing_type);
|
||||
error(node, "The numbers required %llu exceeds the backing type's (%s) bit size %llu",
|
||||
cast(unsigned long long)total_bit_size,
|
||||
s,
|
||||
cast(unsigned long long)maximum_bit_size);
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
bit_field_type->BitField.fields = slice_from_array(fields);
|
||||
bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes);
|
||||
}
|
||||
|
||||
gb_internal bool is_type_valid_bit_set_range(Type *t) {
|
||||
if (is_type_integer(t)) {
|
||||
return true;
|
||||
@@ -3051,6 +3189,20 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(bf, BitFieldType, e);
|
||||
bool ips = ctx->in_polymorphic_specialization;
|
||||
defer (ctx->in_polymorphic_specialization = ips);
|
||||
ctx->in_polymorphic_specialization = false;
|
||||
|
||||
*type = alloc_type_bit_field();
|
||||
set_base_type(named_type, *type);
|
||||
check_open_scope(ctx, e);
|
||||
check_bit_field_type(ctx, *type, named_type, e);
|
||||
check_close_scope(ctx);
|
||||
(*type)->BitField.node = e;
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(pt, ProcType, e);
|
||||
bool ips = ctx->in_polymorphic_specialization;
|
||||
|
||||
Reference in New Issue
Block a user