diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index aa0d73eb0..4b776c7f4 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -1,7 +1,7 @@ package os import "core:sys/win32" -// import "core:mem" +import "core:mem" Handle :: distinct uintptr; File_Time :: distinct u64; diff --git a/core/runtime/_preload.odin b/core/runtime/_preload.odin index b774350ee..5f80594b9 100644 --- a/core/runtime/_preload.odin +++ b/core/runtime/_preload.odin @@ -1,7 +1,6 @@ package runtime import "core:os" -// import "core:fmt" // TODO(bill): Remove the need for `fmt` here import "core:unicode/utf8" import "core:raw" import "core:mem" diff --git a/src/check_decl.cpp b/src/check_decl.cpp index ff4fc6184..2626610de 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -583,7 +583,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { GB_ASSERT(pl->body->kind == AstNode_BlockStmt); if (!pt->is_polymorphic) { - check_procedure_later(c, c->curr_ast_package, e->token, d, proc_type, pl->body, pl->tags); + check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags); } } else if (!is_foreign) { if (e->Procedure.is_export) { @@ -915,7 +915,6 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { e->parent_proc_decl = c->context.curr_proc_decl; e->state = EntityState_InProgress; - switch (e->kind) { case Entity_Variable: check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 34337ce0e..9e7e2da60 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -342,18 +342,17 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ // NOTE(bill): Set the scope afterwards as this is not real overloading entity->scope = scope->parent; - AstPackage *package = nullptr; + AstFile *file = nullptr; { Scope *s = entity->scope; - while (s != nullptr && s->package == nullptr) { - package = s->package; + while (s != nullptr && s->file == nullptr) { + file = s->file; s = s->parent; } } ProcedureInfo proc_info = {}; - // proc_info.file = file; - proc_info.package = package; + proc_info.file = file; proc_info.token = token; proc_info.decl = d; proc_info.type = final_proc_type; @@ -5363,7 +5362,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return kind; } - check_procedure_later(c, c->curr_ast_package, empty_token, decl, type, pl->body, pl->tags); + check_procedure_later(c, c->curr_ast_file, empty_token, decl, type, pl->body, pl->tags); } check_close_scope(c); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c0e885664..4c47385cc 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1487,7 +1487,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } if (entity == nullptr) { - entity = alloc_entity_dummy_variable(c->global_scope, ast_node_token(name)); + entity = alloc_entity_dummy_variable(universal_scope, ast_node_token(name)); } entities[entity_count++] = entity; @@ -1821,7 +1821,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } } if (entity == nullptr) { - entity = alloc_entity_dummy_variable(c->global_scope, ast_node_token(name)); + entity = alloc_entity_dummy_variable(universal_scope, ast_node_token(name)); } entity->parent_proc_decl = c->context.curr_proc_decl; entities[entity_count++] = entity; diff --git a/src/checker.cpp b/src/checker.cpp index 429468c08..2f4a37511 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -32,7 +32,6 @@ void scope_reset(Scope *scope) { scope->first_child = nullptr; scope->last_child = nullptr; map_clear (&scope->elements); - array_clear (&scope->shared); ptr_set_clear(&scope->implicit); ptr_set_clear(&scope->imported); ptr_set_clear(&scope->exported); @@ -217,7 +216,6 @@ Scope *create_scope(Scope *parent, gbAllocator allocator) { Scope *s = gb_alloc_item(allocator, Scope); s->parent = parent; map_init(&s->elements, heap_allocator()); - array_init(&s->shared, heap_allocator()); ptr_set_init(&s->implicit, heap_allocator()); ptr_set_init(&s->imported, heap_allocator()); ptr_set_init(&s->exported, heap_allocator()); @@ -231,37 +229,24 @@ Scope *create_scope(Scope *parent, gbAllocator allocator) { return s; } -// Scope *create_scope_from_file(Checker *c, AstFile *f) { -// GB_ASSERT(f != nullptr); +Scope *create_scope_from_file(Checker *c, AstFile *f) { + GB_ASSERT(f != nullptr); + GB_ASSERT(f->package != nullptr); + GB_ASSERT(f->package->scope != nullptr); -// Scope *s = create_scope(c->global_scope, c->allocator); + Scope *s = create_scope(f->package->scope, c->allocator); + s->is_file = true; + s->file = f; + f->scope = s; -// s->file = f; -// f->scope = s; -// s->is_file = true; - -// if (f->tokenizer.fullpath == c->parser->init_fullpath) { -// s->is_init = true; -// } else { -// s->is_init = f->package->kind == ImportedPackage_Init; -// } - -// s->is_global = f->is_global_scope; -// if (s->is_global) array_add(&c->global_scope->shared, s); - - -// if (s->is_init || s->is_global) { -// s->has_been_imported = true; -// } - -// return s; -// } + return s; +} Scope *create_scope_from_package(Checker *c, AstPackage *p) { GB_ASSERT(p != nullptr); - Scope *s = create_scope(c->global_scope, c->allocator); + Scope *s = create_scope(universal_scope, c->allocator); s->is_package = true; s->package = p; @@ -274,11 +259,10 @@ Scope *create_scope_from_package(Checker *c, AstPackage *p) { } s->is_global = p->kind == ImportedPackage_Runtime; - if (s->is_global) { - array_add(&c->global_scope->shared, s); + if (p->kind == ImportedPackage_Runtime) { + universal_scope->shared = s; } - if (s->is_init || s->is_global) { s->has_been_imported = true; } @@ -303,7 +287,6 @@ void destroy_scope(Scope *scope) { } map_destroy(&scope->elements); - array_free(&scope->shared); array_free(&scope->delayed_imports); array_free(&scope->delayed_asserts); ptr_set_destroy(&scope->implicit); @@ -354,25 +337,6 @@ Entity *current_scope_lookup_entity(Scope *s, String name) { if (found) { return *found; } - for_array(i, s->shared) { - Scope *shared = s->shared[i]; - Entity **found = map_get(&shared->elements, key); - if (found) { - Entity *e = *found; - if (e->kind == Entity_Variable && - !e->scope->is_package && - !e->scope->is_global) { - continue; - } - - if (e->scope != shared) { - // Do not return imported entities even #include ones - continue; - } - - return e; - } - } return nullptr; } @@ -390,8 +354,7 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit continue; } if (e->kind == Entity_Variable && - !e->scope->is_package && - !e->scope->is_global) { + !e->scope->is_file) { continue; } } @@ -403,34 +366,28 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit if (s->is_proc) { gone_thru_proc = true; - } else { - // Check shared scopes - i.e. other files @ global scope - for_array(i, s->shared) { - Scope *shared = s->shared[i]; - Entity **found = map_get(&shared->elements, key); - if (found) { - Entity *e = *found; - if (e->kind == Entity_Variable && - !e->scope->is_package && - !e->scope->is_global) { - continue; - } - - if (e->scope != shared) { - // Do not return imported entities even #include ones - continue; - } - - if ((e->kind == Entity_ImportName || - e->kind == Entity_LibraryName) - && gone_thru_package) { - continue; - } - - if (entity_) *entity_ = e; - if (scope_) *scope_ = shared; - return; + } else if (s->shared) { + Entity **found = map_get(&s->shared->elements, key); + if (found) { + Entity *e = *found; + if (e->kind == Entity_Variable && + !e->scope->is_file) { + continue; } + + if (e->scope->parent != s->shared) { + continue; + } + + if ((e->kind == Entity_ImportName || + e->kind == Entity_LibraryName) + && gone_thru_package) { + continue; + } + + if (entity_) *entity_ = e; + if (scope_) *scope_ = s->shared; + return; } } @@ -524,7 +481,7 @@ void add_type_info_dependency(DeclInfo *d, Type *type) { void add_preload_dependency(Checker *c, char *name) { String n = make_string_c(name); - Entity *e = scope_lookup_entity(c->global_scope, n); + Entity *e = scope_lookup_entity(c->runtime_package->scope, n); GB_ASSERT(e != nullptr); ptr_set_add(&c->context.decl->deps, e); // add_type_info_type(c, e->type); @@ -682,18 +639,12 @@ void init_checker(Checker *c, Parser *parser) { // c->allocator = gb_arena_allocator(&c->arena); c->tmp_allocator = gb_arena_allocator(&c->tmp_arena); - GB_ASSERT(universal_scope != nullptr); - c->global_scope = create_scope(universal_scope, c->allocator); - - GB_ASSERT(scope_lookup_entity(c->global_scope, str_lit("ODIN_OS")) != nullptr); - - map_init(&c->package_scopes, heap_allocator()); array_init(&c->package_order, heap_allocator(), 0, c->parser->packages.count); // Init context - c->context.scope = c->global_scope; + c->context.scope = universal_scope; c->context.type_path = new_checker_type_path(); c->context.type_level = 0; @@ -703,7 +654,6 @@ void destroy_checker(Checker *c) { destroy_checker_info(&c->info); gb_mutex_destroy(&c->mutex); - destroy_scope(c->global_scope); array_free(&c->proc_stack); array_free(&c->procs); @@ -963,7 +913,20 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn GB_ASSERT(e != nullptr && d != nullptr); GB_ASSERT(identifier->Ident.token.string == e->token.string); if (e->scope != nullptr) { - add_entity(c, e->scope, identifier, e); + Scope *scope = e->scope; + if (scope->is_file) { + switch (e->kind) { + case Entity_ImportName: + case Entity_LibraryName: + // NOTE(bill): Entities local to file rather than package + break; + default: + GB_ASSERT(scope->file->package->scope == scope->parent); + scope = scope->file->package->scope; + break; + } + } + add_entity(c, scope, identifier, e); } add_entity_definition(&c->info, identifier, e); GB_ASSERT(e->decl_info == nullptr); @@ -1140,9 +1103,9 @@ void check_procedure_later(Checker *c, ProcedureInfo info) { array_add(&c->procs, info); } -void check_procedure_later(Checker *c, AstPackage *package, Token token, DeclInfo *decl, Type *type, AstNode *body, u64 tags) { +void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u64 tags) { ProcedureInfo info = {}; - info.package = package; + info.file = file; info.token = token; info.decl = decl; info.type = type; @@ -1167,14 +1130,14 @@ Type *const curr_procedure_type(Checker *c) { return nullptr; } -void add_curr_ast_package(Checker *c, AstPackage *package) { - if (package != nullptr) { +void add_curr_ast_file(Checker *c, AstFile *file) { + if (file != nullptr) { TokenPos zero_pos = {}; global_error_collector.prev = zero_pos; - c->curr_ast_package = package; - c->context.decl = package->decl_info; - c->context.scope = package->scope; - c->context.package_scope = package->scope; + c->curr_ast_file = file; + c->context.decl = file->package->decl_info; + c->context.scope = file->scope; + c->context.package_scope = file->package->scope; } } @@ -1379,7 +1342,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("Context"), }; for (isize i = 0; i < gb_count_of(required_entities); i++) { - add_dependency_to_set(c, scope_lookup_entity(c->global_scope, required_entities[i])); + add_dependency_to_set(c, scope_lookup_entity(c->runtime_package->scope, required_entities[i])); } if (!build_context.no_bounds_check) { @@ -1389,7 +1352,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("__dynamic_array_expr_error"), }; for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { - add_dependency_to_set(c, scope_lookup_entity(c->global_scope, bounds_check_entities[i])); + add_dependency_to_set(c, scope_lookup_entity(c->runtime_package->scope, bounds_check_entities[i])); } } @@ -1509,7 +1472,7 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { Entity *find_core_entity(Checker *c, String name) { - Entity *e = current_scope_lookup_entity(c->global_scope, name); + Entity *e = current_scope_lookup_entity(c->runtime_package->scope, name); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" "Is '_preload.odin' missing from the 'core' directory relative to odin.exe?", LIT(name)); @@ -1519,7 +1482,7 @@ Entity *find_core_entity(Checker *c, String name) { } Type *find_core_type(Checker *c, String name) { - Entity *e = current_scope_lookup_entity(c->global_scope, name); + Entity *e = current_scope_lookup_entity(c->runtime_package->scope, name); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" "Is '_preload.odin' missing from the 'core' directory relative to odin.exe?", LIT(name)); @@ -1568,6 +1531,9 @@ Array proc_group_entities(Checker *c, Operand o) { return procs; } + + + void init_preload(Checker *c) { if (t_type_info == nullptr) { Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info")); @@ -1958,7 +1924,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { vd->been_handled = true; if (vd->is_mutable) { - if (!c->context.scope->is_package) { + if (!c->context.scope->is_file) { // NOTE(bill): local scope -> handle later and in order return; } @@ -1976,8 +1942,6 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { di->init_expr_list = vd->values; } - - for_array(i, vd->names) { AstNode *name = vd->names[i]; AstNode *value = nullptr; @@ -2164,7 +2128,7 @@ void check_collect_entities(Checker *c, Array nodes) { case_end; case_ast_node(id, ImportDecl, decl); - if (!c->context.scope->is_package) { + if (!c->context.scope->is_file) { error(decl, "import declarations are only allowed in the file scope"); // NOTE(bill): _Should_ be caught by the parser // TODO(bill): Better error handling if it isn't @@ -2174,7 +2138,7 @@ void check_collect_entities(Checker *c, Array nodes) { case_end; case_ast_node(fl, ForeignImportDecl, decl); - if (!c->context.scope->is_package) { + if (!c->context.scope->is_file) { error(decl, "%.*s declarations are only allowed in the file scope", LIT(fl->token.string)); // NOTE(bill): _Should_ be caught by the parser // TODO(bill): Better error handling if it isn't @@ -2189,7 +2153,7 @@ void check_collect_entities(Checker *c, Array nodes) { case_ast_node(ce, CallExpr, decl); - if (c->context.scope->is_package && + if (c->context.scope->is_file && ce->proc->kind == AstNode_BasicDirective && ce->proc->BasicDirective.name == "assert") { array_add(&c->context.scope->delayed_asserts, decl); @@ -2200,7 +2164,7 @@ void check_collect_entities(Checker *c, Array nodes) { error_case: default: - if (c->context.scope->is_package) { + if (c->context.scope->is_file) { error(decl, "Only declarations are allowed at file scope"); } break; @@ -2209,7 +2173,7 @@ void check_collect_entities(Checker *c, Array nodes) { // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something // declared after this stmt in source - if (!c->context.scope->is_package) { + if (!c->context.scope->is_file) { for_array(i, nodes) { AstNode *node = nodes[i]; switch (node->kind) { @@ -2234,23 +2198,20 @@ void check_all_global_entities(Checker *c) { continue; } - if (!d->scope->has_been_imported) { - // NOTE(bill): All of these unchecked entities could mean a lot of unused allocations - // TODO(bill): Should this be worried about? - continue; - } - AstPackage *package = d->scope->package; - add_curr_ast_package(c, package); + GB_ASSERT(d->scope->is_file); + AstFile *file = d->scope->file; + add_curr_ast_file(c, file); + Scope *package_scope = file->package->scope; if (e->token.string == "main") { if (e->kind != Entity_Procedure) { - if (e->scope->is_init) { + if (package_scope->is_init) { error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); continue; } - } else if (e->scope->is_global) { + } else if (package_scope->is_global) { error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); continue; } @@ -2264,7 +2225,7 @@ void check_all_global_entities(Checker *c) { c->context = prev_context; - if (!d->scope->is_global) { + if (!package_scope->is_global) { processing_preload = false; } @@ -2547,7 +2508,7 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) { id->been_handled = true; Scope *parent_scope = c->context.scope; - GB_ASSERT(parent_scope->is_package); + GB_ASSERT(parent_scope->is_file); Token token = id->relpath; HashKey key = hash_string(id->fullpath); @@ -2599,7 +2560,7 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) { if (id->is_using) { if (parent_scope->is_global) { - error(id->import_name, "runtime package imports cannot use using"); + error(id->import_name, "'runtime' package imports cannot use using"); return; } @@ -2661,7 +2622,7 @@ void check_add_foreign_import_decl(Checker *c, AstNode *decl) { fl->been_handled = true; Scope *parent_scope = c->context.scope; - GB_ASSERT(parent_scope->is_package); + GB_ASSERT(parent_scope->is_file); String fullpath = fl->fullpath; String library_name = path_to_entity_name(fl->library_name.string, fullpath); @@ -2779,24 +2740,39 @@ void check_import_entities(Checker *c) { GB_ASSERT(node->scope->is_package); AstPackage *p = node->scope->package; - CheckerContext prev_context = c->context; - defer (c->context = prev_context); - add_curr_ast_package(c, p); + for_array(i, p->files.entries) { AstFile *f = p->files.entries[i].value; + + CheckerContext prev_context = c->context; + defer (c->context = prev_context); + add_curr_ast_file(c, f); check_collect_entities(c, f->decls); } - for_array(j, node->scope->delayed_imports) { - ast_node(id, ImportDecl, node->scope->delayed_imports[j]); - check_add_import_decl(c, id); + for_array(i, p->files.entries) { + AstFile *f = p->files.entries[i].value; + CheckerContext prev_context = c->context; + defer (c->context = prev_context); + add_curr_ast_file(c, f); + for_array(j, f->scope->delayed_imports) { + AstNode *decl = f->scope->delayed_imports[j]; + ast_node(id, ImportDecl, decl); + check_add_import_decl(c, id); + } } - for_array(j, node->scope->delayed_asserts) { - AstNode *expr = node->scope->delayed_asserts[j]; - Operand o = {}; - check_expr(c, &o, expr); + for_array(i, p->files.entries) { + AstFile *f = p->files.entries[i].value; + CheckerContext prev_context = c->context; + defer (c->context = prev_context); + add_curr_ast_file(c, f); + for_array(j, f->scope->delayed_asserts) { + AstNode *expr = f->scope->delayed_asserts[j]; + Operand o = {}; + check_expr(c, &o, expr); + } } } @@ -2963,7 +2939,7 @@ void check_parsed_files(Checker *c) { for_array(i, c->parser->packages) { AstPackage *p = c->parser->packages[i]; Scope *scope = create_scope_from_package(c, p); - p->decl_info = make_decl_info(c->allocator, p->scope, c->context.decl); + p->decl_info = make_decl_info(c->allocator, scope, c->context.decl); HashKey key = hash_string(p->fullpath); map_set(&c->package_scopes, key, scope); map_set(&c->info.packages, key, p); @@ -2971,6 +2947,10 @@ void check_parsed_files(Checker *c) { if (scope->is_init) { c->info.init_scope = scope; } + if (p->kind == ImportedPackage_Runtime) { + GB_ASSERT(c->runtime_package == nullptr); + c->runtime_package = p; + } } TIME_SECTION("collect entities"); @@ -2978,9 +2958,10 @@ void check_parsed_files(Checker *c) { for_array(i, c->parser->packages) { AstPackage *p = c->parser->packages[i]; CheckerContext prev_context = c->context; - add_curr_ast_package(c, p); for_array(j, p->files.entries) { AstFile *f = p->files.entries[j].value; + create_scope_from_file(c, f); + add_curr_ast_file(c, f); check_collect_entities(c, f->decls); } c->context = prev_context; @@ -3012,7 +2993,7 @@ void check_parsed_files(Checker *c) { GB_ASSERT_MSG(pt->is_poly_specialized, "%.*s", LIT(name)); } - add_curr_ast_package(c, pi->package); + add_curr_ast_file(c, pi->file); bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; diff --git a/src/checker.hpp b/src/checker.hpp index 337cb3b04..4265a535d 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -194,8 +194,7 @@ struct DeclInfo { // ProcedureInfo stores the information needed for checking a procedure struct ProcedureInfo { - // AstFile * file; - AstPackage * package; + AstFile * file; Token token; DeclInfo * decl; Type * type; // Type_Procedure @@ -214,8 +213,8 @@ struct Scope { Scope * last_child; Map elements; // Key: String PtrSet implicit; + Scope * shared; - Array shared; Array delayed_asserts; Array delayed_imports; PtrSet imported; @@ -223,11 +222,15 @@ struct Scope { bool is_proc; bool is_global; bool is_package; + bool is_file; bool is_init; bool is_struct; bool has_been_imported; // This is only applicable to file scopes - AstPackage * package; + union { + AstPackage *package; + AstFile * file; + }; }; @@ -321,8 +324,9 @@ struct Checker { CheckerInfo info; gbMutex mutex; - AstPackage * curr_ast_package; - Scope * global_scope; + + AstFile * curr_ast_file; + AstPackage * runtime_package; // NOTE(bill): Procedures to check Array procs; Map package_scopes; // Key: String (fullpath) diff --git a/src/parser.hpp b/src/parser.hpp index f1547847f..686f3ed61 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -41,7 +41,8 @@ struct ImportedPackage { struct AstFile { AstPackage * package; - // isize id; + Scope * scope; + String fullpath; gbArena arena; Tokenizer tokenizer; @@ -67,7 +68,6 @@ struct AstFile { AstNode * curr_proc; isize scope_level; - // Scope * scope; // NOTE(bill): Created in checker // DeclInfo * decl_info; // NOTE(bill): Created in checker