mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Nested record declarations
This commit is contained in:
@@ -34,6 +34,8 @@ CallingConvention :: enum {
|
|||||||
}
|
}
|
||||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||||
// The compiler relies upon this _exact_ order
|
// The compiler relies upon this _exact_ order
|
||||||
|
|
||||||
|
|
||||||
TypeInfoEnumValue :: raw_union {
|
TypeInfoEnumValue :: raw_union {
|
||||||
f: f64;
|
f: f64;
|
||||||
i: i128;
|
i: i128;
|
||||||
@@ -49,6 +51,7 @@ TypeInfoRecord :: struct #ordered {
|
|||||||
custom_align: bool;
|
custom_align: bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TypeInfo :: union {
|
TypeInfo :: union {
|
||||||
size: int;
|
size: int;
|
||||||
align: int;
|
align: int;
|
||||||
|
|||||||
+85
-65
@@ -692,14 +692,16 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
|
|||||||
|
|
||||||
|
|
||||||
// Returns filled field_count
|
// Returns filled field_count
|
||||||
isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
Array<Entity *> check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
||||||
Entity **fields, isize field_count,
|
isize init_field_capacity, String context) {
|
||||||
String context) {
|
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||||
defer (gb_temp_arena_memory_end(tmp));
|
defer (gb_temp_arena_memory_end(tmp));
|
||||||
|
|
||||||
|
Array<Entity *> fields = {};
|
||||||
|
array_init(&fields, heap_allocator(), init_field_capacity);
|
||||||
|
|
||||||
Map<Entity *> entity_map = {};
|
Map<Entity *> entity_map = {};
|
||||||
map_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count);
|
map_init_with_reserve(&entity_map, c->tmp_allocator, 2*init_field_capacity);
|
||||||
|
|
||||||
Entity *using_index_expr = nullptr;
|
Entity *using_index_expr = nullptr;
|
||||||
|
|
||||||
@@ -707,14 +709,33 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
|||||||
GB_ASSERT(node->kind != AstNode_UnionType);
|
GB_ASSERT(node->kind != AstNode_UnionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
isize field_index = 0;
|
check_collect_entities(c, decls, false);
|
||||||
|
for_array(i, c->context.scope->elements.entries) {
|
||||||
|
Entity *e = c->context.scope->elements.entries[i].value;
|
||||||
|
if (e->token.string == "EnumValue") {
|
||||||
|
// gb_printf_err("EnumValue\n");
|
||||||
|
}
|
||||||
|
DeclInfo *d = nullptr;
|
||||||
|
switch (e->kind) {
|
||||||
|
default: continue;
|
||||||
|
case Entity_Constant:
|
||||||
|
case Entity_TypeName:
|
||||||
|
d = decl_info_of_entity(&c->info, e);
|
||||||
|
if (d != nullptr) {
|
||||||
|
check_entity_decl(c, e, d, nullptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for_array(decl_index, decls) {
|
for_array(decl_index, decls) {
|
||||||
AstNode *decl = decls[decl_index];
|
AstNode *decl = decls[decl_index];
|
||||||
if (decl->kind != AstNode_ValueDecl) {
|
if (decl->kind != AstNode_ValueDecl) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ast_node(vd, ValueDecl, decl);
|
ast_node(vd, ValueDecl, decl);
|
||||||
|
|
||||||
|
if (!vd->is_mutable) continue;
|
||||||
|
|
||||||
Type *type = nullptr;
|
Type *type = nullptr;
|
||||||
if (vd->type != nullptr) {
|
if (vd->type != nullptr) {
|
||||||
type = check_type(c, vd->type);
|
type = check_type(c, vd->type);
|
||||||
@@ -746,10 +767,10 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
|||||||
|
|
||||||
Token name_token = name->Ident.token;
|
Token name_token = name->Ident.token;
|
||||||
|
|
||||||
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)field_index);
|
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)fields.count);
|
||||||
e->identifier = name;
|
e->identifier = name;
|
||||||
if (name_token.string == "_") {
|
if (name_token.string == "_") {
|
||||||
fields[field_index++] = e;
|
array_add(&fields, e);
|
||||||
} else if (name_token.string == "__tag") {
|
} else if (name_token.string == "__tag") {
|
||||||
error(name, "`__tag` is a reserved identifier for fields");
|
error(name, "`__tag` is a reserved identifier for fields");
|
||||||
} else {
|
} else {
|
||||||
@@ -763,7 +784,7 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
|||||||
error(e->token, "\tpreviously declared");
|
error(e->token, "\tpreviously declared");
|
||||||
} else {
|
} else {
|
||||||
map_set(&entity_map, key, e);
|
map_set(&entity_map, key, e);
|
||||||
fields[field_index++] = e;
|
array_add(&fields, e);
|
||||||
add_entity(c, c->context.scope, name, e);
|
add_entity(c, c->context.scope, name, e);
|
||||||
}
|
}
|
||||||
add_entity_use(c, name, e);
|
add_entity_use(c, name, e);
|
||||||
@@ -792,9 +813,9 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
using_index_expr = fields[field_index-1];
|
using_index_expr = fields[fields.count-1];
|
||||||
} else {
|
} else {
|
||||||
fields[field_index-1]->flags &= ~EntityFlag_Using;
|
fields[fields.count-1]->flags &= ~EntityFlag_Using;
|
||||||
error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string));
|
error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -810,7 +831,7 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return field_index;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -863,26 +884,26 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
|
|||||||
GB_ASSERT(is_type_struct(struct_type));
|
GB_ASSERT(is_type_struct(struct_type));
|
||||||
ast_node(st, StructType, node);
|
ast_node(st, StructType, node);
|
||||||
|
|
||||||
isize field_count = 0;
|
isize min_field_count = 0;
|
||||||
for_array(field_index, st->fields) {
|
for_array(field_index, st->fields) {
|
||||||
AstNode *field = st->fields[field_index];
|
AstNode *field = st->fields[field_index];
|
||||||
switch (field->kind) {
|
switch (field->kind) {
|
||||||
case_ast_node(f, ValueDecl, field);
|
case_ast_node(f, ValueDecl, field);
|
||||||
field_count += f->names.count;
|
min_field_count += f->names.count;
|
||||||
case_end;
|
case_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
struct_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||||
|
|
||||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
|
auto fields = check_fields(c, node, st->fields, min_field_count, str_lit("struct"));
|
||||||
|
|
||||||
field_count = check_fields(c, node, st->fields, fields, field_count, str_lit("struct"));
|
|
||||||
|
|
||||||
|
struct_type->Record.scope = c->context.scope;
|
||||||
struct_type->Record.is_packed = st->is_packed;
|
struct_type->Record.is_packed = st->is_packed;
|
||||||
struct_type->Record.is_ordered = st->is_ordered;
|
struct_type->Record.is_ordered = st->is_ordered;
|
||||||
struct_type->Record.fields = fields;
|
struct_type->Record.fields = fields.data;
|
||||||
struct_type->Record.fields_in_src_order = fields;
|
struct_type->Record.fields_in_src_order = fields.data;
|
||||||
struct_type->Record.field_count = field_count;
|
struct_type->Record.field_count = fields.count;
|
||||||
struct_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
|
||||||
|
|
||||||
type_set_offsets(c->allocator, struct_type);
|
type_set_offsets(c->allocator, struct_type);
|
||||||
|
|
||||||
@@ -893,8 +914,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
|
|||||||
struct_type->Record.offsets = nullptr;
|
struct_type->Record.offsets = nullptr;
|
||||||
// NOTE(bill): Reorder fields for reduced size/performance
|
// NOTE(bill): Reorder fields for reduced size/performance
|
||||||
|
|
||||||
Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, field_count);
|
Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
|
||||||
for (isize i = 0; i < field_count; i++) {
|
for (isize i = 0; i < fields.count; i++) {
|
||||||
reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
|
reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,9 +923,9 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
|
|||||||
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
|
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
|
||||||
__checker_allocator = c->allocator;
|
__checker_allocator = c->allocator;
|
||||||
// NOTE(bill): compound literal order must match source not layout
|
// NOTE(bill): compound literal order must match source not layout
|
||||||
gb_sort_array(reordered_fields, field_count, cmp_reorder_struct_fields);
|
gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
|
||||||
|
|
||||||
for (isize i = 0; i < field_count; i++) {
|
for (isize i = 0; i < fields.count; i++) {
|
||||||
reordered_fields[i]->Variable.field_index = i;
|
reordered_fields[i]->Variable.field_index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -959,12 +980,12 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
|||||||
ast_node(ut, UnionType, node);
|
ast_node(ut, UnionType, node);
|
||||||
|
|
||||||
isize variant_count = ut->variants.count+1;
|
isize variant_count = ut->variants.count+1;
|
||||||
isize field_count = 0;
|
isize min_field_count = 0;
|
||||||
for_array(i, ut->fields) {
|
for_array(i, ut->fields) {
|
||||||
AstNode *field = ut->fields[i];
|
AstNode *field = ut->fields[i];
|
||||||
switch (field->kind) {
|
switch (field->kind) {
|
||||||
case_ast_node(f, ValueDecl, field);
|
case_ast_node(f, ValueDecl, field);
|
||||||
field_count += f->names.count;
|
min_field_count += f->names.count;
|
||||||
case_end;
|
case_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -977,23 +998,23 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
|||||||
|
|
||||||
Entity *using_index_expr = nullptr;
|
Entity *using_index_expr = nullptr;
|
||||||
|
|
||||||
Entity **variants = gb_alloc_array(c->allocator, Entity *, variant_count);
|
Array<Entity *> variants = {};
|
||||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
|
array_init(&variants, heap_allocator(), variant_count);
|
||||||
|
|
||||||
isize variant_index = 0;
|
array_add(&variants, make_entity_type_name(c->allocator, c->context.scope, empty_token, nullptr));
|
||||||
variants[variant_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, nullptr);
|
|
||||||
|
|
||||||
field_count = check_fields(c, nullptr, ut->fields, fields, field_count, str_lit("union"));
|
auto fields = check_fields(c, nullptr, ut->fields, min_field_count, str_lit("union"));
|
||||||
|
|
||||||
for (isize i = 0; i < field_count; i++) {
|
for (isize i = 0; i < fields.count; i++) {
|
||||||
Entity *f = fields[i];
|
Entity *f = fields[i];
|
||||||
String name = f->token.string;
|
String name = f->token.string;
|
||||||
map_set(&entity_map, hash_string(name), f);
|
map_set(&entity_map, hash_string(name), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
union_type->Record.fields = fields;
|
union_type->Record.scope = c->context.scope;
|
||||||
union_type->Record.fields_in_src_order = fields;
|
union_type->Record.fields = fields.data;
|
||||||
union_type->Record.field_count = field_count;
|
union_type->Record.fields_in_src_order = fields.data;
|
||||||
|
union_type->Record.field_count = fields.count;
|
||||||
union_type->Record.are_offsets_set = false;
|
union_type->Record.are_offsets_set = false;
|
||||||
union_type->Record.is_ordered = true;
|
union_type->Record.is_ordered = true;
|
||||||
{
|
{
|
||||||
@@ -1035,17 +1056,16 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
|||||||
AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, list, list_count, false, true, nullptr);
|
AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, list, list_count, false, true, nullptr);
|
||||||
|
|
||||||
check_open_scope(c, dummy_struct);
|
check_open_scope(c, dummy_struct);
|
||||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, list_count);
|
base_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||||
isize field_count = check_fields(c, dummy_struct, list, fields, list_count, str_lit("variant"));
|
auto fields = check_fields(c, dummy_struct, list, list_count, str_lit("variant"));
|
||||||
base_type->Record.is_packed = false;
|
base_type->Record.is_packed = false;
|
||||||
base_type->Record.is_ordered = true;
|
base_type->Record.is_ordered = true;
|
||||||
base_type->Record.fields = fields;
|
base_type->Record.fields = fields.data;
|
||||||
base_type->Record.fields_in_src_order = fields;
|
base_type->Record.fields_in_src_order = fields.data;
|
||||||
base_type->Record.field_count = field_count;
|
base_type->Record.field_count = fields.count;
|
||||||
base_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
base_type->Record.node = dummy_struct;
|
||||||
base_type->Record.node = dummy_struct;
|
base_type->Record.variant_parent = named_type != nullptr ? named_type : union_type;
|
||||||
base_type->Record.variant_parent = named_type != nullptr ? named_type : union_type;
|
base_type->Record.variant_index = variants.count;
|
||||||
base_type->Record.variant_index = variant_index;
|
|
||||||
|
|
||||||
|
|
||||||
type_set_offsets(c->allocator, base_type);
|
type_set_offsets(c->allocator, base_type);
|
||||||
@@ -1069,7 +1089,7 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
|||||||
error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
|
error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
|
||||||
} else {
|
} else {
|
||||||
map_set(&entity_map, key, e);
|
map_set(&entity_map, key, e);
|
||||||
variants[variant_index++] = e;
|
array_add(&variants, e);
|
||||||
}
|
}
|
||||||
add_entity_use(c, f->name, e);
|
add_entity_use(c, f->name, e);
|
||||||
}
|
}
|
||||||
@@ -1077,8 +1097,8 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
|||||||
type_set_offsets(c->allocator, union_type);
|
type_set_offsets(c->allocator, union_type);
|
||||||
|
|
||||||
|
|
||||||
union_type->Record.variants = variants;
|
union_type->Record.variants = variants.data;
|
||||||
union_type->Record.variant_count = variant_index;
|
union_type->Record.variant_count = variants.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||||
@@ -1086,23 +1106,23 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
|||||||
GB_ASSERT(is_type_raw_union(union_type));
|
GB_ASSERT(is_type_raw_union(union_type));
|
||||||
ast_node(ut, RawUnionType, node);
|
ast_node(ut, RawUnionType, node);
|
||||||
|
|
||||||
isize field_count = 0;
|
isize min_field_count = 0;
|
||||||
for_array(i, ut->fields) {
|
for_array(i, ut->fields) {
|
||||||
AstNode *field = ut->fields[i];
|
AstNode *field = ut->fields[i];
|
||||||
switch (field->kind) {
|
switch (field->kind) {
|
||||||
case_ast_node(f, ValueDecl, field);
|
case_ast_node(f, ValueDecl, field);
|
||||||
field_count += f->names.count;
|
min_field_count += f->names.count;
|
||||||
case_end;
|
case_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
|
|
||||||
|
|
||||||
field_count = check_fields(c, node, ut->fields, fields, field_count, str_lit("raw_union"));
|
|
||||||
|
|
||||||
union_type->Record.fields = fields;
|
|
||||||
union_type->Record.field_count = field_count;
|
|
||||||
union_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
union_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||||
|
|
||||||
|
auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
|
||||||
|
|
||||||
|
union_type->Record.scope = c->context.scope;
|
||||||
|
union_type->Record.fields = fields.data;
|
||||||
|
union_type->Record.field_count = fields.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1133,8 +1153,8 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
|||||||
Map<Entity *> entity_map = {}; // Key: String
|
Map<Entity *> entity_map = {}; // Key: String
|
||||||
map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count));
|
map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count));
|
||||||
|
|
||||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, et->fields.count);
|
Array<Entity *> fields = {};
|
||||||
isize field_count = 0;
|
array_init(&fields, c->allocator, et->fields.count);
|
||||||
|
|
||||||
Type *constant_type = enum_type;
|
Type *constant_type = enum_type;
|
||||||
if (named_type != nullptr) {
|
if (named_type != nullptr) {
|
||||||
@@ -1222,18 +1242,18 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
|||||||
} else {
|
} else {
|
||||||
map_set(&entity_map, key, e);
|
map_set(&entity_map, key, e);
|
||||||
add_entity(c, c->context.scope, nullptr, e);
|
add_entity(c, c->context.scope, nullptr, e);
|
||||||
fields[field_count++] = e;
|
array_add(&fields, e);
|
||||||
add_entity_use(c, field, e);
|
add_entity_use(c, field, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GB_ASSERT(field_count <= et->fields.count);
|
GB_ASSERT(fields.count <= et->fields.count);
|
||||||
|
|
||||||
|
|
||||||
enum_type->Record.fields = fields;
|
enum_type->Record.fields = fields.data;
|
||||||
enum_type->Record.field_count = field_count;
|
enum_type->Record.field_count = fields.count;
|
||||||
|
|
||||||
enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope,
|
enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope,
|
||||||
make_token_ident(str_lit("count")), t_int, exact_value_i64(field_count));
|
make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
|
||||||
enum_type->Record.enum_min_value = make_entity_constant(c->allocator, c->context.scope,
|
enum_type->Record.enum_min_value = make_entity_constant(c->allocator, c->context.scope,
|
||||||
make_token_ident(str_lit("min_value")), constant_type, min_value);
|
make_token_ident(str_lit("min_value")), constant_type, min_value);
|
||||||
enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope,
|
enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope,
|
||||||
|
|||||||
+34
-2
@@ -473,7 +473,39 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
|||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_TypeName: {
|
case Entity_TypeName: {
|
||||||
Type *t = base_type(e->type);
|
Type *t = base_type(e->type);
|
||||||
if (is_type_union(t)) {
|
if (t->kind == Type_Record) {
|
||||||
|
Scope *s = t->Record.scope;
|
||||||
|
if (s != nullptr) {
|
||||||
|
for_array(i, s->elements.entries) {
|
||||||
|
Entity *f = s->elements.entries[i].value;
|
||||||
|
if (f->kind != Entity_Variable) {
|
||||||
|
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||||
|
if (found != nullptr) {
|
||||||
|
gbString expr_str = expr_to_string(expr);
|
||||||
|
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
f->using_parent = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is_type_enum(t)) {
|
||||||
|
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||||
|
Entity *f = t->Record.fields[i];
|
||||||
|
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||||
|
if (found != nullptr) {
|
||||||
|
gbString expr_str = expr_to_string(expr);
|
||||||
|
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
f->using_parent = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(us->token, "`using` can be only applied to record type entities");
|
||||||
|
}
|
||||||
|
/* if (is_type_union(t)) {
|
||||||
TokenPos pos = ast_node_token(expr).pos;
|
TokenPos pos = ast_node_token(expr).pos;
|
||||||
for (isize i = 1; i < t->Record.variant_count; i++) {
|
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||||
Entity *f = t->Record.variants[i];
|
Entity *f = t->Record.variants[i];
|
||||||
@@ -502,7 +534,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
|
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
|
||||||
}
|
} */
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Entity_ImportName: {
|
case Entity_ImportName: {
|
||||||
|
|||||||
+42
-6
@@ -233,6 +233,7 @@ struct Scope {
|
|||||||
bool is_global;
|
bool is_global;
|
||||||
bool is_file;
|
bool is_file;
|
||||||
bool is_init;
|
bool is_init;
|
||||||
|
bool is_record;
|
||||||
bool has_been_imported; // This is only applicable to file scopes
|
bool has_been_imported; // This is only applicable to file scopes
|
||||||
AstFile * file;
|
AstFile * file;
|
||||||
};
|
};
|
||||||
@@ -447,8 +448,16 @@ void check_open_scope(Checker *c, AstNode *node) {
|
|||||||
is_ast_node_type(node));
|
is_ast_node_type(node));
|
||||||
Scope *scope = make_scope(c->context.scope, c->allocator);
|
Scope *scope = make_scope(c->context.scope, c->allocator);
|
||||||
add_scope(c, node, scope);
|
add_scope(c, node, scope);
|
||||||
if (node->kind == AstNode_ProcType) {
|
switch (node->kind) {
|
||||||
|
case AstNode_ProcType:
|
||||||
scope->is_proc = true;
|
scope->is_proc = true;
|
||||||
|
break;
|
||||||
|
case AstNode_StructType:
|
||||||
|
case AstNode_EnumType:
|
||||||
|
case AstNode_UnionType:
|
||||||
|
case AstNode_RawUnionType:
|
||||||
|
scope->is_record = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
c->context.scope = scope;
|
c->context.scope = scope;
|
||||||
c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
|
c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||||
@@ -1307,9 +1316,26 @@ void init_preload(Checker *c) {
|
|||||||
GB_ASSERT(is_type_union(type_info_entity->type));
|
GB_ASSERT(is_type_union(type_info_entity->type));
|
||||||
TypeRecord *record = &base_type(type_info_entity->type)->Record;
|
TypeRecord *record = &base_type(type_info_entity->type)->Record;
|
||||||
|
|
||||||
t_type_info_record = find_core_entity(c, str_lit("TypeInfoRecord"))->type;
|
// Entity *type_info_record = current_scope_lookup_entity(record->scope, str_lit("Record"));
|
||||||
|
// if (type_info_record == nullptr) {
|
||||||
|
// compiler_error("Could not find type declaration for TypeInfo.Record\n"
|
||||||
|
// "Is `_preload.odin` missing from the `core` directory relative to the odin executable?");
|
||||||
|
// }
|
||||||
|
// Entity *type_info_enum_value = current_scope_lookup_entity(record->scope, str_lit("EnumValue"));
|
||||||
|
// if (type_info_record == nullptr) {
|
||||||
|
// compiler_error("Could not find type declaration for TypeInfo.EnumValue\n"
|
||||||
|
// "Is `_preload.odin` missing from the `core` directory relative to the odin executable?");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// GB_ASSERT(type_info_record->type != nullptr);
|
||||||
|
// GB_ASSERT(type_info_enum_value->type != nullptr);
|
||||||
|
Entity *type_info_record = find_core_entity(c, str_lit("TypeInfoRecord"));
|
||||||
|
Entity *type_info_enum_value = find_core_entity(c, str_lit("TypeInfoEnumValue"));
|
||||||
|
|
||||||
|
|
||||||
|
t_type_info_record = type_info_record->type;
|
||||||
t_type_info_record_ptr = make_type_pointer(c->allocator, t_type_info_record);
|
t_type_info_record_ptr = make_type_pointer(c->allocator, t_type_info_record);
|
||||||
t_type_info_enum_value = find_core_entity(c, str_lit("TypeInfoEnumValue"))->type;
|
t_type_info_enum_value = type_info_enum_value->type;
|
||||||
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
|
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
|
||||||
|
|
||||||
|
|
||||||
@@ -1692,20 +1718,29 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token token = name->Ident.token;
|
||||||
|
if (token.string == "EnumValue") {
|
||||||
|
gb_printf_err("EnumValue %p\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
AstNode *fl = c->context.curr_foreign_library;
|
AstNode *fl = c->context.curr_foreign_library;
|
||||||
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
|
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
|
||||||
Entity *e = nullptr;
|
Entity *e = nullptr;
|
||||||
|
|
||||||
if (is_ast_node_type(init)) {
|
if (is_ast_node_type(init)) {
|
||||||
e = make_entity_type_name(c->allocator, d->scope, name->Ident.token, nullptr);
|
e = make_entity_type_name(c->allocator, d->scope, token, nullptr);
|
||||||
if (vd->type != nullptr) {
|
if (vd->type != nullptr) {
|
||||||
error(name, "A type declaration cannot have an type parameter");
|
error(name, "A type declaration cannot have an type parameter");
|
||||||
}
|
}
|
||||||
d->type_expr = init;
|
d->type_expr = init;
|
||||||
d->init_expr = init;
|
d->init_expr = init;
|
||||||
} else if (init->kind == AstNode_ProcLit) {
|
} else if (init->kind == AstNode_ProcLit) {
|
||||||
|
if (c->context.scope->is_record) {
|
||||||
|
error(name, "Procedure declarations are not allowed within a record");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ast_node(pl, ProcLit, init);
|
ast_node(pl, ProcLit, init);
|
||||||
e = make_entity_procedure(c->allocator, d->scope, name->Ident.token, nullptr, pl->tags);
|
e = make_entity_procedure(c->allocator, d->scope, token, nullptr, pl->tags);
|
||||||
if (fl != nullptr) {
|
if (fl != nullptr) {
|
||||||
GB_ASSERT(fl->kind == AstNode_Ident);
|
GB_ASSERT(fl->kind == AstNode_Ident);
|
||||||
e->Procedure.foreign_library_ident = fl;
|
e->Procedure.foreign_library_ident = fl;
|
||||||
@@ -1714,7 +1749,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
|
|||||||
d->proc_lit = init;
|
d->proc_lit = init;
|
||||||
d->type_expr = pl->type;
|
d->type_expr = pl->type;
|
||||||
} else {
|
} else {
|
||||||
e = make_entity_constant(c->allocator, d->scope, name->Ident.token, nullptr, empty_exact_value);
|
e = make_entity_constant(c->allocator, d->scope, token, nullptr, empty_exact_value);
|
||||||
d->type_expr = vd->type;
|
d->type_expr = vd->type;
|
||||||
d->init_expr = init;
|
d->init_expr = init;
|
||||||
}
|
}
|
||||||
@@ -1730,6 +1765,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
add_entity_and_decl_info(c, name, e, d);
|
add_entity_and_decl_info(c, name, e, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
@@ -3632,10 +3632,13 @@ void ir_pop_target_list(irProcedure *proc) {
|
|||||||
|
|
||||||
|
|
||||||
void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
|
void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
|
||||||
|
if (e->type == nullptr) return;
|
||||||
|
|
||||||
irValue *t = ir_value_type_name(m->allocator, name, e->type);
|
irValue *t = ir_value_type_name(m->allocator, name, e->type);
|
||||||
ir_module_add_value(m, e, t);
|
ir_module_add_value(m, e, t);
|
||||||
map_set(&m->members, hash_string(name), t);
|
map_set(&m->members, hash_string(name), t);
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (is_type_union(e->type)) {
|
if (is_type_union(e->type)) {
|
||||||
Type *bt = base_type(e->type);
|
Type *bt = base_type(e->type);
|
||||||
// NOTE(bill): Zeroth entry is null (for `match type` stmts)
|
// NOTE(bill): Zeroth entry is null (for `match type` stmts)
|
||||||
@@ -3643,6 +3646,20 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
|
|||||||
ir_mangle_add_sub_type_name(m, bt->Record.variants[j], name);
|
ir_mangle_add_sub_type_name(m, bt->Record.variants[j], name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Type *bt = base_type(e->type);
|
||||||
|
if (bt->kind == Type_Record) {
|
||||||
|
Scope *s = bt->Record.scope;
|
||||||
|
if (s != nullptr) {
|
||||||
|
for_array(i, s->elements.entries) {
|
||||||
|
Entity *e = s->elements.entries[i].value;
|
||||||
|
if (e->kind == Entity_TypeName) {
|
||||||
|
ir_mangle_add_sub_type_name(m, e, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+26
-19
@@ -1366,6 +1366,7 @@ AstNode *ast_field_list(AstFile *f, Token token, Array<AstNode *> list) {
|
|||||||
result->FieldList.list = list;
|
result->FieldList.list = list;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
|
AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
|
||||||
AstNode *result = make_ast_node(f, AstNode_UnionField);
|
AstNode *result = make_ast_node(f, AstNode_UnionField);
|
||||||
result->UnionField.name = name;
|
result->UnionField.name = name;
|
||||||
@@ -3390,20 +3391,28 @@ AstNode *parse_record_field_list(AstFile *f, isize *name_count_) {
|
|||||||
while (f->curr_token.kind != Token_CloseBrace &&
|
while (f->curr_token.kind != Token_CloseBrace &&
|
||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
AstNode *decl = parse_stmt(f);
|
AstNode *decl = parse_stmt(f);
|
||||||
if (decl->kind != AstNode_ValueDecl) {
|
switch (decl->kind) {
|
||||||
error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind]));
|
case AstNode_EmptyStmt:
|
||||||
} else {
|
case AstNode_BadStmt:
|
||||||
ast_node(vd, ValueDecl, decl);
|
case AstNode_BadDecl:
|
||||||
if (vd->is_mutable) {
|
break;
|
||||||
if (vd->flags&VarDeclFlag_thread_local) {
|
|
||||||
vd->flags &= ~VarDeclFlag_thread_local;
|
case_ast_node(vd, ValueDecl, decl);
|
||||||
error(decl, "Field values cannot be #thread_local");
|
if (vd->flags&VarDeclFlag_thread_local) {
|
||||||
}
|
vd->flags &= ~VarDeclFlag_thread_local;
|
||||||
array_add(&decls, decl);
|
error(decl, "Field values cannot be #thread_local");
|
||||||
total_name_count += vd->names.count;
|
|
||||||
} else {
|
|
||||||
error(decl, "Only variable declarations are allowed at the moment");
|
|
||||||
}
|
}
|
||||||
|
array_add(&decls, decl);
|
||||||
|
total_name_count += vd->names.count;
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case AstNode_WhenStmt:
|
||||||
|
array_add(&decls, decl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(decl, "Expected a value declaration, got %.*s", LIT(ast_node_strings[decl->kind]));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3683,8 +3692,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
|||||||
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
||||||
|
|
||||||
isize name_count = 0;
|
isize name_count = 0;
|
||||||
AstNode *fields = parse_record_field_list(f, &name_count);
|
AstNode *fields = parse_record_field_list(f, &name_count);
|
||||||
Token close = expect_token(f, Token_CloseBrace);
|
Token close = expect_token(f, Token_CloseBrace);
|
||||||
|
|
||||||
Array<AstNode *> decls = {};
|
Array<AstNode *> decls = {};
|
||||||
if (fields != nullptr) {
|
if (fields != nullptr) {
|
||||||
@@ -3742,11 +3751,9 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
|||||||
vd->flags &= ~VarDeclFlag_thread_local;
|
vd->flags &= ~VarDeclFlag_thread_local;
|
||||||
error(decl, "Field values cannot be #thread_local");
|
error(decl, "Field values cannot be #thread_local");
|
||||||
}
|
}
|
||||||
array_add(&decls, decl);
|
|
||||||
total_decl_name_count += vd->names.count;
|
|
||||||
} else {
|
|
||||||
error(decl, "Only variable declarations are allowed at the moment");
|
|
||||||
}
|
}
|
||||||
|
array_add(&decls, decl);
|
||||||
|
total_decl_name_count += vd->names.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ struct TypeRecord {
|
|||||||
i32 field_count; // == struct_offsets count
|
i32 field_count; // == struct_offsets count
|
||||||
Entity **fields_in_src_order; // Entity_Variable
|
Entity **fields_in_src_order; // Entity_Variable
|
||||||
AstNode *node;
|
AstNode *node;
|
||||||
|
Scope * scope;
|
||||||
|
|
||||||
// Entity_TypeName - union
|
// Entity_TypeName - union
|
||||||
Entity **variants;
|
Entity **variants;
|
||||||
@@ -1477,6 +1478,8 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
|
|||||||
gb_global Entity *entity__any_data = nullptr;
|
gb_global Entity *entity__any_data = nullptr;
|
||||||
gb_global Entity *entity__any_type_info = nullptr;
|
gb_global Entity *entity__any_type_info = nullptr;
|
||||||
|
|
||||||
|
Entity *current_scope_lookup_entity(Scope *s, String name);
|
||||||
|
|
||||||
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
|
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
|
||||||
GB_ASSERT(type_ != nullptr);
|
GB_ASSERT(type_ != nullptr);
|
||||||
|
|
||||||
@@ -1593,6 +1596,18 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type->kind == Type_Record) {
|
||||||
|
Scope *s = type->Record.scope;
|
||||||
|
if (s != nullptr) {
|
||||||
|
Entity *found = current_scope_lookup_entity(s, field_name);
|
||||||
|
if (found != nullptr && found->kind != Entity_Variable) {
|
||||||
|
sel.entity = found;
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (type->kind == Type_Record) {
|
} else if (type->kind == Type_Record) {
|
||||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||||
Entity *f = type->Record.fields[i];
|
Entity *f = type->Record.fields[i];
|
||||||
|
|||||||
Reference in New Issue
Block a user