From 76e724718c7711cc5bcc942178d5955991759589 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 4 Dec 2016 00:49:06 +0000 Subject: [PATCH] Fix preload initialization ordering --- build.bat | 2 +- code/demo.odin | 7 ++- core/_preload.odin | 8 ++- src/build.c | 93 +++++++++++++++++++++++++++++++++- src/checker/checker.c | 114 ++++++++++++++++++------------------------ src/checker/entity.c | 2 +- src/checker/expr.c | 13 ++++- src/checker/types.c | 6 +-- src/common.c | 16 ------ src/parser.c | 64 +++--------------------- src/string.c | 13 ----- 11 files changed, 177 insertions(+), 161 deletions(-) diff --git a/build.bat b/build.bat index ef66ca729..84b99c3a2 100644 --- a/build.bat +++ b/build.bat @@ -16,7 +16,7 @@ if %release_mode% EQU 0 ( rem Debug ) set compiler_warnings= ^ - -we4013 -we4706 -we4002 -we4133 -we4047 -we4024 ^ + -we4002 -we4013 -we4024 -we4047 -we4133 -we4706 ^ -wd4100 -wd4101 -wd4127 -wd4189 ^ -wd4201 -wd4204 -wd4244 ^ -wd4306 ^ diff --git a/code/demo.odin b/code/demo.odin index 3bd1588e6..88b5c5064 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,6 +1,9 @@ -#import "game.odin"; +// #import "game.odin"; +#import "fmt.odin"; + +x := type_info(int); main :: proc() { - game.run(); + fmt.println(123); } diff --git a/core/_preload.odin b/core/_preload.odin index 37bb89189..103187096 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -4,10 +4,16 @@ #import "fmt.odin"; #import "mem.odin"; +// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a +// #shared_global_scope due to the internals of the compiler. +// This could change at a later date if the all these data structures are +// implemented within the compiler rather than in this "preload" file + + // IMPORTANT NOTE(bill): Do not change the order of any of this data // The compiler relies upon this _exact_ order Type_Info :: union { - Member :: struct #ordered { + Member :: type struct #ordered { name: string; // can be empty if tuple type_info: ^Type_Info; offset: int; // offsets are not used in tuples diff --git a/src/build.c b/src/build.c index 84d3c26d6..7b40fde8f 100644 --- a/src/build.c +++ b/src/build.c @@ -11,6 +11,16 @@ typedef struct BuildContext { String link_flags; } BuildContext; +// TODO(bill): OS dependent versions for the BuildContext +// join_path +// is_dir +// is_file +// is_abs_path +// has_subdir + +String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; +String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; + String odin_root_dir(void) { String path = global_module_path; Array(wchar_t) path_buf; @@ -60,14 +70,93 @@ String odin_root_dir(void) { return path; } +String path_to_fullpath(gbAllocator a, String s) { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); + String16 string16 = string_to_string16(string_buffer_allocator, s); + String result = {0}; + + DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL); + if (len != 0) { + wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); + GetFullPathNameW(string16.text, len, text, NULL); + text[len] = 0; + result = string16_to_string(a, make_string16(text, len)); + } + gb_temp_arena_memory_end(tmp); + return result; +} + + +String get_fullpath_relative(gbAllocator a, String base_dir, String path) { + String res = {0}; + isize str_len = base_dir.len+path.len; + + u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); + + isize i = 0; + gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len; + gb_memmove(str+i, path.text, path.len); + str[str_len] = '\0'; + res = path_to_fullpath(a, make_string(str, str_len)); + gb_free(heap_allocator(), str); + return res; +} + +String get_fullpath_core(gbAllocator a, String path) { + String module_dir = odin_root_dir(); + String res = {0}; + + char core[] = "core/"; + isize core_len = gb_size_of(core)-1; + + isize str_len = module_dir.len + core_len + path.len; + u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); + + gb_memmove(str, module_dir.text, module_dir.len); + gb_memmove(str+module_dir.len, core, core_len); + gb_memmove(str+module_dir.len+core_len, path.text, path.len); + str[str_len] = '\0'; + + res = path_to_fullpath(a, make_string(str, str_len)); + gb_free(heap_allocator(), str); + return res; +} + + +String get_filepath_extension(String path) { + isize dot = 0; + bool seen_slash = false; + for (isize i = path.len-1; i >= 0; i--) { + u8 c = path.text[i]; + if (c == '/' || c == '\\') { + seen_slash = true; + } + + if (c == '.') { + if (seen_slash) { + return str_lit(""); + } + + dot = i; + break; + } + } + return make_string(path.text, dot); +} + + void init_build_context(BuildContext *bc) { - bc->ODIN_OS = str_lit("windows"); - bc->ODIN_ARCH = str_lit("amd64"); bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = str_lit("0.0.3d"); bc->ODIN_ROOT = odin_root_dir(); +#if defined(GB_SYSTEM_WINDOWS) + bc->ODIN_OS = str_lit("windows"); + bc->ODIN_ARCH = str_lit("amd64"); +#else +#error Implement system +#endif if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) { bc->word_size = 8; diff --git a/src/checker/checker.c b/src/checker/checker.c index 3b1716bfa..60dea3be0 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -266,6 +266,7 @@ typedef struct Checker { Array(Type *) proc_stack; bool in_defer; // TODO(bill): Actually handle correctly + bool done_preload; } Checker; typedef struct CycleChecker { @@ -570,6 +571,7 @@ void init_universal_scope(BuildContext *bc) { add_global_entity(entity); } + t_u8_ptr = make_type_pointer(a, t_u8); t_int_ptr = make_type_pointer(a, t_int); } @@ -986,11 +988,21 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { } -#include "expr.c" -#include "decl.c" -#include "stmt.c" +void add_implicit_value(Checker *c, ImplicitValueId id, String name, String backing_name, Type *type) { + ImplicitValueInfo info = {name, backing_name, type}; + Entity *value = make_entity_implicit_value(c->allocator, info.name, info.type, id); + Entity *prev = scope_insert_entity(c->global_scope, value); + GB_ASSERT(prev == NULL); + implicit_value_infos[id] = info; + c->info.implicit_values[id] = value; +} + + +void init_preload(Checker *c) { + if (c->done_preload) { + return; + } -void init_preload_types(Checker *c) { if (t_type_info == NULL) { Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info")); if (e == NULL) { @@ -1045,54 +1057,22 @@ void init_preload_types(Checker *c) { } t_context = e->type; t_context_ptr = make_type_pointer(c->allocator, t_context); - } -} - -void add_implicit_value(Checker *c, ImplicitValueId id, String name, String backing_name, Type *type) { - ImplicitValueInfo info = {name, backing_name, type}; - Entity *value = make_entity_implicit_value(c->allocator, info.name, info.type, id); - Entity *prev = scope_insert_entity(c->global_scope, value); - GB_ASSERT(prev == NULL); - implicit_value_infos[id] = info; - c->info.implicit_values[id] = value; + c->done_preload = true; } -void check_global_entities_by_kind(Checker *c, EntityKind kind) { - for_array(i, c->info.entities.entries) { - MapDeclInfoEntry *entry = &c->info.entities.entries.e[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; - DeclInfo *d = entry->value; - - if (e->kind != kind) { - continue; - } - if (d->scope != e->scope) { - continue; - } - - add_curr_ast_file(c, d->scope->file); - if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) { - if (e->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 && str_eq(e->token.string, str_lit("main"))) { - error(e->token, "`main` is reserved as the entry point procedure in the initial scope"); - continue; - } - - Scope *prev_scope = c->context.scope; - c->context.scope = d->scope; - check_entity_decl(c, e, d, NULL, NULL); - } -} +#include "expr.c" +#include "decl.c" +#include "stmt.c" + void check_all_global_entities(Checker *c) { + Scope *prev_file = {0}; + for_array(i, c->info.entities.entries) { MapDeclInfoEntry *entry = &c->info.entities.entries.e[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; @@ -1101,8 +1081,8 @@ void check_all_global_entities(Checker *c) { if (d->scope != e->scope) { continue; } - add_curr_ast_file(c, d->scope->file); + if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) { if (e->scope->is_init) { error(e->token, "`main` is reserved as the entry point procedure in the initial scope"); @@ -1116,10 +1096,15 @@ void check_all_global_entities(Checker *c) { Scope *prev_scope = c->context.scope; c->context.scope = d->scope; check_entity_decl(c, e, d, NULL, NULL); + + + if (d->scope->is_init && !c->done_preload) { + init_preload(c); + } } } -void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) { +void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) { for_array(decl_index, nodes) { AstNode *decl = nodes.e[decl_index]; if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) { @@ -1179,6 +1164,7 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray continue; } + // NOTE(bill): You need to store the entity information here unline a constant declaration isize entity_count = vd->names.count; isize entity_index = 0; Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); @@ -1351,6 +1337,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } if (import_name.len > 0) { + GB_ASSERT(id->import_name.pos.line != 0); id->import_name.string = import_name; Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid, id->fullpath, id->import_name.string, @@ -1399,9 +1386,7 @@ void check_parsed_files(Checker *c) { scope->is_global = f->is_global_scope; scope->is_file = true; scope->file = f; - if (i == 0) { - // NOTE(bill): First file is always the initial file - // thus it must contain main + if (str_eq(f->tokenizer.fullpath, c->parser->init_fullpath)) { scope->is_init = true; } @@ -1420,26 +1405,23 @@ void check_parsed_files(Checker *c) { for_array(i, c->parser->files) { AstFile *f = &c->parser->files.e[i]; add_curr_ast_file(c, f); - check_global_collect_entities(c, f->scope, f->decls, &file_scopes); + check_global_collect_entities_from_file(c, f->scope, f->decls, &file_scopes); } check_import_entities(c, &file_scopes); -#if 0 - check_global_entities_by_kind(c, Entity_TypeName); - check_global_entities_by_kind(c, Entity_Constant); - init_preload_types(c); - add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context); - check_global_entities_by_kind(c, Entity_Procedure); - check_global_entities_by_kind(c, Entity_Variable); -#else - check_all_global_entities(c); - init_preload_types(c); - add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context); -#endif + map_scope_destroy(&file_scopes); + check_all_global_entities(c); + init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)` + // NOTE(bill): Nothing is the global scope _should_ depend on this implicit value as implicit + // values are only useful within procedures + add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context); + + // Initialize implicit values with backing variables + // TODO(bill): Are implicit values "too implicit"? for (isize i = 1; i < ImplicitValue_Count; i++) { - // NOTE(bill): First is invalid + // NOTE(bill): 0th is invalid Entity *e = c->info.implicit_values[i]; GB_ASSERT(e->kind == Entity_ImplicitValue); @@ -1451,6 +1433,7 @@ void check_parsed_files(Checker *c) { // Check procedure bodies + // NOTE(bill): Nested procedures bodies will be added to this "queue" for_array(i, c->procs) { ProcedureInfo *pi = &c->procs.e[i]; add_curr_ast_file(c, pi->file); @@ -1487,6 +1470,11 @@ void check_parsed_files(Checker *c) { } } + // TODO(bill): Check for unused imports (and remove) or even warn/err + // TODO(bill): Any other checks? + + + // Add "Basic" type information for (isize i = 0; i < gb_count_of(basic_types)-1; i++) { Type *t = &basic_types[i]; if (t->Basic.size > 0) { @@ -1500,8 +1488,6 @@ void check_parsed_files(Checker *c) { add_type_info_type(c, t); } } - - map_scope_destroy(&file_scopes); } diff --git a/src/checker/entity.c b/src/checker/entity.c index df1ecf28d..e2d1cff57 100644 --- a/src/checker/entity.c +++ b/src/checker/entity.c @@ -67,7 +67,7 @@ struct Entity { String path; String name; Scope *scope; - bool used; + bool used; } ImportName; i32 Nil; struct { diff --git a/src/checker/expr.c b/src/checker/expr.c index d93ae762d..501ccaa64 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -2939,6 +2939,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_type_info: { // type_info :: proc(Type) -> ^Type_Info + if (c->context.scope->is_global) { + compiler_error("`type_info` Cannot be declared within a #shared_global_scope due to how the internals of the compiler works"); + } + + // NOTE(bill): The type information may not be setup yet + init_preload(c); AstNode *expr = ce->args.e[0]; Type *type = check_type(c, expr); if (type == NULL || type == t_invalid) { @@ -2954,8 +2960,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_type_info_of_val: { // type_info_of_val :: proc(val: Type) -> ^Type_Info - AstNode *expr = ce->args.e[0]; + if (c->context.scope->is_global) { + compiler_error("`type_info` Cannot be declared within a #shared_global_scope due to how the internals of the compiler works"); + } + // NOTE(bill): The type information may not be setup yet + init_preload(c); + AstNode *expr = ce->args.e[0]; check_assignment(c, operand, NULL, str_lit("argument of `type_info_of_val`")); if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin) return false; diff --git a/src/checker/types.c b/src/checker/types.c index dc18984e5..1d7ce2067 100644 --- a/src/checker/types.c +++ b/src/checker/types.c @@ -87,9 +87,9 @@ typedef struct TypeRecord { }; struct { // struct only i64 * struct_offsets; - bool struct_are_offsets_set; - bool struct_is_packed; - bool struct_is_ordered; + bool struct_are_offsets_set; + bool struct_is_packed; + bool struct_is_ordered; Entity **fields_in_src_order; // Entity_Variable }; }; diff --git a/src/common.c b/src/common.c index 8c04db896..a43ee9d32 100644 --- a/src/common.c +++ b/src/common.c @@ -13,22 +13,6 @@ gb_global String global_module_path = {0}; gb_global bool global_module_path_set = false; -String path_to_fullpath(gbAllocator a, String s) { - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); - String16 string16 = string_to_string16(string_buffer_allocator, s); - String result = {0}; - - DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL); - if (len != 0) { - wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); - GetFullPathNameW(string16.text, len, text, NULL); - text[len] = 0; - result = string16_to_string(a, make_string16(text, len)); - } - gb_temp_arena_memory_end(tmp); - return result; -} - i64 next_pow2(i64 n) { if (n <= 0) { return 0; diff --git a/src/parser.c b/src/parser.c index d224545f3..28925fb57 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2869,6 +2869,9 @@ AstNode *parse_stmt(AstFile *f) { import_name = f->curr_token; next_token(f); break; + default: + import_name.pos = hash_token.pos; + break; } if (str_eq(import_name.string, str_lit("_"))) { @@ -3068,40 +3071,6 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) return true; } -String get_fullpath_relative(gbAllocator a, String base_dir, String path) { - String res = {0}; - isize str_len = base_dir.len+path.len; - - u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); - - isize i = 0; - gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len; - gb_memmove(str+i, path.text, path.len); - str[str_len] = '\0'; - res = path_to_fullpath(a, make_string(str, str_len)); - gb_free(heap_allocator(), str); - return res; -} - -String get_fullpath_core(gbAllocator a, String path) { - String module_dir = odin_root_dir(); - String res = {0}; - - char core[] = "core/"; - isize core_len = gb_size_of(core)-1; - - isize str_len = module_dir.len + core_len + path.len; - u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); - - gb_memmove(str, module_dir.text, module_dir.len); - gb_memmove(str+module_dir.len, core, core_len); - gb_memmove(str+module_dir.len+core_len, path.text, path.len); - str[str_len] = '\0'; - - res = path_to_fullpath(a, make_string(str, str_len)); - gb_free(heap_allocator(), str); - return res; -} // // NOTE(bill): Returns true if it's added // bool try_add_foreign_library_path(Parser *p, String import_file) { @@ -3157,27 +3126,6 @@ bool is_import_path_valid(String path) { return false; } -String get_filepath_extension(String path) { - isize dot = 0; - bool seen_slash = false; - for (isize i = path.len-1; i >= 0; i--) { - u8 c = path.text[i]; - if (c == '/' || c == '\\') { - seen_slash = true; - } - - if (c == '.') { - if (seen_slash) { - return str_lit(""); - } - - dot = i; - break; - } - } - return make_string(path.text, dot); -} - void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray decls) { for_array(i, decls) { AstNode *node = decls.e[i]; @@ -3261,8 +3209,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) { String init_fullpath = make_string_c(fullpath_str); TokenPos init_pos = {0}; ImportedFile init_imported_file = {init_fullpath, init_fullpath, init_pos}; - array_add(&p->imports, init_imported_file); - p->init_fullpath = init_fullpath; + { String s = get_fullpath_core(heap_allocator(), str_lit("_preload.odin")); @@ -3275,6 +3222,9 @@ ParseFileError parse_files(Parser *p, char *init_filename) { array_add(&p->imports, runtime_file); } + array_add(&p->imports, init_imported_file); + p->init_fullpath = init_fullpath; + for_array(i, p->imports) { ImportedFile imported_file = p->imports.e[i]; String import_path = imported_file.path; diff --git a/src/string.c b/src/string.c index 75a2e50b7..1198af7d1 100644 --- a/src/string.c +++ b/src/string.c @@ -108,19 +108,6 @@ GB_COMPARE_PROC(string_cmp_proc) { return string_compare(x, y); } - -// gb_inline bool operator ==(String a, String b) { return are_strings_equal(a, b) != 0; } -// gb_inline bool operator !=(String a, String b) { return !operator==(a, b); } -// gb_inline bool operator < (String a, String b) { return string_compare(a, b) < 0; } -// gb_inline bool operator > (String a, String b) { return string_compare(a, b) > 0; } -// gb_inline bool operator <=(String a, String b) { return string_compare(a, b) <= 0; } -// gb_inline bool operator >=(String a, String b) { return string_compare(a, b) >= 0; } - -// template gb_inline bool operator ==(String a, char const (&b)[N]) { return a == make_string(cast(u8 *)b, N-1); } -// template gb_inline bool operator !=(String a, char const (&b)[N]) { return a != make_string(cast(u8 *)b, N-1); } -// template gb_inline bool operator ==(char const (&a)[N], String b) { return make_string(cast(u8 *)a, N-1) == b; } -// template gb_inline bool operator !=(char const (&a)[N], String b) { return make_string(cast(u8 *)a, N-1) != b; } - gb_inline bool str_eq(String a, String b) { return a.len == b.len ? gb_memcompare(a.text, b.text, a.len) == 0 : false; } gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); } gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; }