global F64 generating_time_begin; global F64 generating_time_end; global F64 resolving_time_begin; global F64 resolving_time_end; global F64 total_time; global F64 init_ctx_time_begin; global F64 init_ctx_time_end; function void begin_compilation(){ init_ctx_time_begin = os_time(); OS_Heap *heap = exp_alloc_type(&pernament_arena, OS_Heap, AF_ZeroMemory); *heap = win32_os_heap_create(false, mib(4), 0); Parse_Ctx *ctx = exp_alloc_type(&pernament_arena, Parse_Ctx, AF_ZeroMemory); parse_init(ctx, &pernament_arena, heap); init_ctx_time_end = os_time(); } function void destroy_compiler(){ exp_destroy(pctx->heap); exp_free_all(pctx->perm); } function void parse_file(Ast_File *file){ assert(file); Scratch scratch; file->filecontent = os_read_file(pctx->perm, file->absolute_file_path); if(file->filecontent.len == 0){ compiler_error(file->pos, "Failed to open file \"%Q\"", file->absolute_file_path); } pctx->currently_parsed_file = file; pctx->currently_parsed_scope = file; lex_restream(pctx, file->filecontent, file->absolute_file_path); while(token_expect(SAME_SCOPE)){ if(token_match_pound(pctx->intern("load"_s))){ parse_load(true); continue; } else if(token_match_pound(pctx->intern("import"_s))){ parse_import(true); continue; } Ast_Decl *decl = parse_decl(true); if(!decl) break; set_flag(decl->flags, AST_GLOBAL); if(decl->kind == AST_STRUCT){ decl->type = type_type; decl->type_val = type_incomplete(decl); decl->state = DECL_RESOLVED; } insert_into_scope(file, decl); } pctx->currently_parsed_scope = 0; pctx->currently_parsed_file = 0; } function void insert_builtin_into_scope(Ast_Scope *p, String name, Ast_Type *type){ Intern_String string = pctx->intern(name); Ast_Decl *decl = ast_type(0, string, type); type->type_id = pctx->type_ids++; decl->parent_scope = p; decl->state = DECL_RESOLVED; insert_into_scope(p, decl); pctx->all_types.add(type); } function void insert_builtin_types_into_scope(Ast_Scope *p){ insert_builtin_into_scope(p, "S64"_s, type_s64); insert_builtin_into_scope(p, "S32"_s, type_s32); insert_builtin_into_scope(p, "S16"_s, type_s16); insert_builtin_into_scope(p, "S8"_s, type_s8); insert_builtin_into_scope(p, "int"_s, type_int); insert_builtin_into_scope(p, "char"_s, type_char); insert_builtin_into_scope(p, "U64"_s, type_u64); insert_builtin_into_scope(p, "U32"_s, type_u32); insert_builtin_into_scope(p, "U16"_s, type_u16); insert_builtin_into_scope(p, "U8"_s, type_u8); insert_builtin_into_scope(p, "F64"_s, type_f64); insert_builtin_into_scope(p, "F32"_s, type_f32); insert_builtin_into_scope(p, "void"_s , type_void); insert_builtin_into_scope(p, "Bool"_s , type_bool); insert_builtin_into_scope(p, "String"_s, type_string); insert_builtin_into_scope(p, "Type"_s, type_type); } global F64 parsing_time_begin; global F64 parsing_time_end; function void parse_all_modules(){ parsing_time_begin = os_time(); for(S64 i = 0; i < pctx->modules.len; i++){ Ast_Module *module = pctx->modules[i]; if(module->state != MODULE_REGISTERED) continue; for(S64 j = 0; j < module->all_loaded_files.len; j++){ Ast_File *file = module->all_loaded_files.data[j]; parse_file(file); } if(module != pctx->language_base_module) module->implicit_imports.add(pctx->language_base_module); module->state = MODULE_PARSED; } parsing_time_end = os_time(); } function Ast_Module * add_module(Token *pos, Intern_String filename, B32 command_line_module){ Scratch scratch; String absolute_file_path = {}; String absolute_base_folder = {}; // // Find in working directory // if(command_line_module){ if(os_does_file_exist(filename.s)){ String path = os_get_absolute_path(scratch, filename.s); string_path_normalize(path); absolute_file_path = string_copy(scratch, path); absolute_base_folder = string_chop_last_slash(path); } } // // Find in module folder // else{ For(pctx->module_folders){ String path = string_fmt(scratch, "%Q/%Q", it, filename); if(os_does_file_exist(path)){ absolute_file_path = path; absolute_base_folder = string_chop_last_slash(path); break; } } } if(absolute_file_path.len == 0){ compiler_error(pos, "Couldn't find the module with name %Q", filename); } For(pctx->modules){ if(string_compare(it->absolute_file_path, absolute_file_path)){ // log_info("Returning registered module: %Q\n", absolute_file_path); return it; } } Ast_Module *result = ast_new(Ast_Module, AST_MODULE, pos, 0); result->absolute_file_path = string_copy(pctx->perm, absolute_file_path); result->absolute_base_folder = string_copy(pctx->perm, absolute_base_folder); // log_info("Adding module: %Q\n", filename); result->module = result; // @warning: self referential result->file = result; // @warning: self referential result->all_loaded_files = {pctx->heap}; result->implicit_imports = {pctx->heap}; result->decls = {pctx->heap}; result->parent_scope = 0; result->scope_id = pctx->scope_ids++; register_ast_file(pos, result->absolute_file_path, result, GLOBAL_IMPLICIT_LOAD); pctx->modules.add(result); return result; } function void resolve_everything_in_module(Ast_Module *module){ if(module->state == MODULE_RESOLVED) return; resolving_time_begin = os_time(); for(S64 i = 0; i < module->all_loaded_files.len; i++){ Ast_File *file = module->all_loaded_files[i]; For(file->decls){ resolve_name(file, it->pos, it->name); if(it->kind == AST_STRUCT){ type_complete(it->type_val); } } } module->state = MODULE_RESOLVED; resolving_time_end = os_time(); } function String compile_to_c_code(); function String compile_file_to_string(String filename){ total_time = os_time(); begin_compilation(); { Ast_Module *module = add_module(0, pctx->intern("language.kl"_s)); insert_builtin_types_into_scope(module); pctx->language_base_module = module; parse_all_modules(); resolve_everything_in_module(module); // @note: language stuff needs to be declared before type_info data // so we mark where it ends pctx->base_language_ordered_decl_len = pctx->ordered_decls.len; Ast_Decl *any_decl = search_for_decl(module, pctx->intern("Any"_s)); assert(any_decl->type == type_type); type_any = any_decl->type_val; } Ast_Module *module = add_module(0, pctx->intern(filename), true); parse_all_modules(); assert(module); resolve_everything_in_module(module); arena_clear(&pctx->stage_arena); String result = compile_to_c_code(); return result; } const U32 COMPILE_NULL = 0x0; const U32 COMPILE_PRINT_STATS = 0x1; function void compile_file(String filename, U32 compile_flags = COMPILE_NULL){ String result = compile_file_to_string(filename); assert(os_write_file("program.c"_s, result)); Scratch scratch; F64 begin = os_time(); String compiler_call = string_fmt(scratch, "clang.exe program.c -Wall -Wno-parentheses-equality -g -o a.exe -lgdi32 -luser32 -lwinmm"); system((const char *)compiler_call.str); F64 end = os_time(); if(compile_flags & COMPILE_PRINT_STATS){ printf("\ntotal = %f", os_time() - total_time); printf("\nclang = %f", end - begin); printf("\nparsing = %f", parsing_time_end - parsing_time_begin); printf("\nresolving = %f", resolving_time_end - resolving_time_begin); printf("\ngeneratin = %f", generating_time_end - generating_time_begin); } destroy_compiler(); }