struct Scope; struct Checker; struct Type; struct DeclInfo; struct lbModule; struct lbProcedure; #define ENTITY_KINDS \ ENTITY_KIND(Invalid) \ ENTITY_KIND(Constant) \ ENTITY_KIND(Variable) \ ENTITY_KIND(TypeName) \ ENTITY_KIND(Procedure) \ ENTITY_KIND(ProcGroup) \ ENTITY_KIND(Builtin) \ ENTITY_KIND(ImportName) \ ENTITY_KIND(LibraryName) \ ENTITY_KIND(Nil) \ ENTITY_KIND(Label) enum EntityKind { #define ENTITY_KIND(k) GB_JOIN2(Entity_, k), ENTITY_KINDS #undef ENTITY_KIND Entity_Count, }; String const entity_strings[] = { #define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1}, ENTITY_KINDS #undef ENTITY_KIND }; enum EntityFlag : u64 { EntityFlag_Visited = 1ull<<0, EntityFlag_Used = 1ull<<1, EntityFlag_Using = 1ull<<2, EntityFlag_Field = 1ull<<3, EntityFlag_Param = 1ull<<4, EntityFlag_Result = 1ull<<5, EntityFlag_ArrayElem = 1ull<<6, EntityFlag_ArraySwizzle = 1ull<<7, EntityFlag_Ellipsis = 1ull<<8, EntityFlag_NoAlias = 1ull<<9, EntityFlag_TypeField = 1ull<<10, EntityFlag_Value = 1ull<<11, EntityFlag_Sret = 1ull<<12, EntityFlag_ByVal = 1ull<<13, EntityFlag_BitFieldValue = 1ull<<14, EntityFlag_PolyConst = 1ull<<15, EntityFlag_NotExported = 1ull<<16, EntityFlag_ConstInput = 1ull<<17, EntityFlag_Static = 1ull<<18, EntityFlag_ImplicitReference = 1ull<<19, // NOTE(bill): equivalent to `const &` in C++ EntityFlag_SoaPtrField = 1ull<<20, // to allow s.x[0] where `s.x` is a pointer rather than a slice EntityFlag_ProcBodyChecked = 1ull<<21, EntityFlag_CVarArg = 1ull<<22, EntityFlag_AutoCast = 1ull<<23, EntityFlag_AnyInt = 1ull<<24, EntityFlag_Disabled = 1ull<<25, EntityFlag_Cold = 1ull<<26, // procedure is rarely called EntityFlag_Lazy = 1ull<<27, // Lazily type checked EntityFlag_Test = 1ull<<30, EntityFlag_Overridden = 1ull<<63, }; enum EntityState : u32 { EntityState_Unresolved = 0, EntityState_InProgress = 1, EntityState_Resolved = 2, }; enum ParameterValueKind { ParameterValue_Invalid, ParameterValue_Constant, ParameterValue_Nil, ParameterValue_Location, ParameterValue_Value, }; struct ParameterValue { ParameterValueKind kind; Ast *original_ast_expr; union { ExactValue value; Ast *ast_value; }; }; enum EntityConstantFlags : u32 { EntityConstantFlag_ImplicitEnumValue = 1<<0, }; enum ProcedureOptimizationMode : u32 { ProcedureOptimizationMode_Default, ProcedureOptimizationMode_None, ProcedureOptimizationMode_Minimal, ProcedureOptimizationMode_Size, ProcedureOptimizationMode_Speed, }; // An Entity is a named "thing" in the language struct Entity { EntityKind kind; u64 id; std::atomic flags; std::atomic state; Token token; Scope * scope; Type * type; std::atomic identifier; // Can be nullptr DeclInfo * decl_info; DeclInfo * parent_proc_decl; // nullptr if in file/global scope AstFile * file; AstPackage *pkg; // TODO(bill): Cleanup how `using` works for entities Entity * using_parent; Ast * using_expr; Entity * aliased_of; lbModule * code_gen_module; lbProcedure *code_gen_procedure; u64 order_in_src; String deprecated_message; String warning_message; // IMPORTANT NOTE(bill): This must be a discriminated union because of patching // later entity kinds union { struct { u8 start; } Dummy; struct { ExactValue value; ParameterValue param_value; u32 flags; } Constant; struct { Ast *init_expr; // only used for some variables within procedure bodies i32 field_index; i32 field_src_index; ParameterValue param_value; Ast * param_expr; String thread_local_model; Entity * foreign_library; Ast * foreign_library_ident; String link_name; String link_prefix; String link_section; bool is_foreign; bool is_export; } Variable; struct { Type * type_parameter_specialization; String ir_mangled_name; bool is_type_alias; } TypeName; struct { u64 tags; Entity *foreign_library; Ast * foreign_library_ident; String link_name; String link_prefix; DeferredProcedure deferred_procedure; bool is_foreign; bool is_export; ProcedureOptimizationMode optimization_mode; } Procedure; struct { Array entities; } ProcGroup; struct { i32 id; } Builtin; struct { String path; String name; Scope *scope; } ImportName; struct { Slice paths; String name; } LibraryName; i32 Nil; struct { String name; Ast *node; Ast *parent; } Label; }; }; bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) { switch (kind) { case Entity_Builtin: return allow_builtin; case Entity_ImportName: case Entity_LibraryName: case Entity_Nil: return false; } return true; } bool is_entity_exported(Entity *e, bool allow_builtin = false) { // TODO(bill): Determine the actual exportation rules for imports of entities GB_ASSERT(e != nullptr); if (!is_entity_kind_exported(e->kind, allow_builtin)) { return false; } if (e->flags & EntityFlag_NotExported) { return false; } if (e->file != nullptr && (e->file->flags & AstFile_IsPrivate) != 0) { return false; } String name = e->token.string; switch (name.len) { case 0: return false; case 1: return name[0] != '_'; } return true; } bool entity_has_deferred_procedure(Entity *e) { GB_ASSERT(e != nullptr); if (e->kind == Entity_Procedure) { return e->Procedure.deferred_procedure.entity != nullptr; } return false; } gb_global std::atomic global_entity_id; Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) { gbAllocator a = permanent_allocator(); Entity *entity = gb_alloc_item(a, Entity); entity->kind = kind; entity->state = EntityState_Unresolved; entity->scope = scope; entity->token = token; entity->type = type; entity->id = 1 + global_entity_id.fetch_add(1); return entity; } Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) { Entity *entity = alloc_entity(Entity_Variable, scope, token, type); entity->state = state; return entity; } Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) { GB_ASSERT(parent != nullptr); token.pos = parent->token.pos; Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type); entity->using_parent = parent; entity->parent_proc_decl = parent->parent_proc_decl; entity->using_expr = using_expr; entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Used; entity->state = EntityState_Resolved; return entity; } Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) { Entity *entity = alloc_entity(Entity_Constant, scope, token, type); entity->Constant.value = value; return entity; } Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) { Entity *entity = alloc_entity(Entity_TypeName, scope, token, type); entity->state = state; return entity; } Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) { Entity *entity = alloc_entity_variable(scope, token, type); entity->flags |= EntityFlag_Used; entity->flags |= EntityFlag_Param; entity->state = EntityState_Resolved; if (is_using) entity->flags |= EntityFlag_Using; if (is_value) entity->flags |= EntityFlag_Value; return entity; } Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) { Entity *entity = alloc_entity_constant(scope, token, type, value); entity->flags |= EntityFlag_Used; if (poly_const) entity->flags |= EntityFlag_PolyConst; entity->flags |= EntityFlag_Param; return entity; } Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index, EntityState state = EntityState_Unresolved) { Entity *entity = alloc_entity_variable(scope, token, type); entity->Variable.field_src_index = field_src_index; entity->Variable.field_index = field_src_index; if (is_using) entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Field; entity->state = state; return entity; } Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_src_index) { Entity *entity = alloc_entity_variable(scope, token, type); entity->Variable.field_src_index = field_src_index; entity->Variable.field_index = field_src_index; entity->flags |= EntityFlag_Field; entity->flags |= EntityFlag_ArrayElem; entity->state = EntityState_Resolved; return entity; } Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) { Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type); entity->Procedure.tags = tags; return entity; } Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) { Entity *entity = alloc_entity(Entity_ProcGroup, scope, token, type); return entity; } Entity *alloc_entity_builtin(Scope *scope, Token token, Type *type, i32 id) { Entity *entity = alloc_entity(Entity_Builtin, scope, token, type); entity->Builtin.id = id; entity->state = EntityState_Resolved; return entity; } Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type, String path, String name, Scope *import_scope) { Entity *entity = alloc_entity(Entity_ImportName, scope, token, type); entity->ImportName.path = path; entity->ImportName.name = name; entity->ImportName.scope = import_scope; entity->state = EntityState_Resolved; // TODO(bill): Is this correct? return entity; } Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type, Slice paths, String name) { Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type); entity->LibraryName.paths = paths; entity->LibraryName.name = name; entity->state = EntityState_Resolved; // TODO(bill): Is this correct? return entity; } Entity *alloc_entity_nil(String name, Type *type) { Entity *entity = alloc_entity(Entity_Nil, nullptr, make_token_ident(name), type); return entity; } Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast *parent) { Entity *entity = alloc_entity(Entity_Label, scope, token, type); entity->Label.node = node; entity->Label.parent = parent; entity->state = EntityState_Resolved; return entity; } Entity *alloc_entity_dummy_variable(Scope *scope, Token token) { token.string = str_lit("_"); return alloc_entity_variable(scope, token, nullptr); } Entity *entity_from_expr(Ast *expr); Entity *strip_entity_wrapping(Entity *e) { if (e == nullptr) { return nullptr; } if (e->kind != Entity_Constant) { return e; } if (e->Constant.value.kind == ExactValue_Procedure) { return strip_entity_wrapping(e->Constant.value.value_procedure); } return e; } Entity *strip_entity_wrapping(Ast *expr) { Entity *e = entity_from_expr(expr); return strip_entity_wrapping(e); }