function void lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){ l->arena = token_string_arena; l->tokens = array_make(token_string_arena, 1024*2); l->interns= intern_table_make(token_string_arena, map_allocator, 1024); /*#import meta for i in meta.keywords: print(f'keyword_{i.lower()} = l->intern("{i}"_s);') print(f'l->interns.first_keyword = keyword_{meta.keywords[0].lower()}.str;') print(f'l->interns.last_keyword = keyword_{meta.keywords[-1].lower()}.str;') for i in meta.interns: print(f'intern_{i.lower()} = l->intern("{i}"_s);') for i in meta.token_simple_expr: if i[1] != "SPECIAL": print("op_" + meta.pascal_to_snake(i[0]) + f' = l->intern("{i[1]}"_s);') first = "op_" + meta.pascal_to_snake(meta.token_simple_expr[0][0]) last = "op_" + meta.pascal_to_snake(meta.token_simple_expr[-1][0]) print(f"l->first_op = {first};") print(f"l->last_op = {last};") */ keyword_struct = l->intern("struct"_s); keyword_union = l->intern("union"_s); keyword_true = l->intern("true"_s); keyword_default = l->intern("default"_s); keyword_break = l->intern("break"_s); keyword_false = l->intern("false"_s); keyword_return = l->intern("return"_s); keyword_switch = l->intern("switch"_s); keyword_assert = l->intern("Assert"_s); keyword_if = l->intern("if"_s); keyword_elif = l->intern("elif"_s); keyword_pass = l->intern("pass"_s); keyword_else = l->intern("else"_s); keyword_for = l->intern("for"_s); keyword_enum = l->intern("enum"_s); l->interns.first_keyword = keyword_struct.str; l->interns.last_keyword = keyword_enum.str; intern_sizeof = l->intern("SizeOf"_s); intern_length = l->intern("Length"_s); intern_alignof = l->intern("AlignOf"_s); intern_foreign = l->intern("foreign"_s); intern_strict = l->intern("strict"_s); intern_void = l->intern("void"_s); intern_flag = l->intern("flag"_s); intern_it = l->intern("it"_s); op_mul = l->intern("*"_s); op_div = l->intern("/"_s); op_mod = l->intern("%"_s); op_left_shift = l->intern("<<"_s); op_right_shift = l->intern(">>"_s); op_add = l->intern("+"_s); op_sub = l->intern("-"_s); op_equals = l->intern("=="_s); op_lesser_then_or_equal = l->intern("<="_s); op_greater_then_or_equal = l->intern(">="_s); op_lesser_then = l->intern("<"_s); op_greater_then = l->intern(">"_s); op_not_equals = l->intern("!="_s); op_bit_and = l->intern("&"_s); op_bit_or = l->intern("|"_s); op_bit_xor = l->intern("^"_s); op_and = l->intern("&&"_s); op_or = l->intern("||"_s); op_neg = l->intern("~"_s); op_not = l->intern("!"_s); op_decrement = l->intern("--"_s); op_increment = l->intern("++"_s); op_post_decrement = l->intern("--"_s); op_post_increment = l->intern("++"_s); l->first_op = op_mul; l->last_op = op_post_increment; /*END*/ } function void parse_init(Parse_Ctx *ctx, Arena *perm_allocator, Allocator *heap_allocator){ pctx = ctx; ctx->perm = perm_allocator; ctx->heap = heap_allocator; ctx->type_map = {ctx->heap}; ctx->gen = {ctx->perm}; ctx->helper_builder= {ctx->perm}; ctx->scope_ids = 1; bigint_allocator = ctx->perm; arena_init(&ctx->stage_arena, "Compiler stage arena"_s); lex_init(ctx->perm, ctx->heap, ctx); init_type(); // Init paths ctx->exe_folder = os_get_exe_dir(ctx->perm); ctx->working_folder = os_get_working_dir(ctx->perm); String main_module = string_fmt(ctx->perm, "%Q/modules", ctx->exe_folder); add(ctx->perm, &ctx->module_folders, main_module); } 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, "Compiler heap"_s); 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); exp_destroy(&pctx->stage_arena); } 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); add(pctx->perm, &pctx->all_types, 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(); Iter_Named(&pctx->modules, mod_it){ Ast_Module *module = mod_it.item[0]; if(module->state != MODULE_REGISTERED) continue; Iter(&module->all_loaded_files){ parse_file(*it.item); } if(module != pctx->language_base_module){ add(pctx->perm, &module->implicit_imports, (Ast_Scope *)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{ Iter(&pctx->module_folders){ String path = string_fmt(scratch, "%Q/%Q", it.item[0], 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); } Iter(&pctx->modules){ if(string_compare(it.item[0]->absolute_file_path, absolute_file_path)){ log_trace("Returning registered module: %Q\n", absolute_file_path); return it.item[0]; } } log_trace("Adding module: %Q\n", filename); 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); result->debug_name = string_skip_to_last_slash(result->absolute_file_path); result->module = result; // @warning: self referential result->file = result; // @warning: self referential 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); add(pctx->perm, &pctx->modules, result); return result; } function void resolve_everything_in_module(Ast_Module *module){ if(module->state == MODULE_RESOLVED) return; resolving_time_begin = os_time(); Iter_Named(&module->all_loaded_files, file){ For(file.item[0]->decls){ resolve_name(file.item[0], 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_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 = length(&pctx->ordered_decls); Ast_Decl *any_decl = search_for_single_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; const U32 COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY = 0x2; const U32 COMPILE_AND_RUN = 0x4; const U32 COMPILE_TESTING = 0x8; function void compile_file(String filename, U32 compile_flags = COMPILE_NULL){ if(is_flag_set(compile_flags, COMPILE_AND_RUN)){ log_info("\n%Q - ", filename); } 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(is_flag_set(compile_flags, COMPILE_PRINT_STATS)){ log_info("\ntotal = %f", os_time() - total_time); log_info("\nclang = %f", end - begin); log_info("\nparsing = %f", parsing_time_end - parsing_time_begin); log_info("\nresolving = %f", resolving_time_end - resolving_time_begin); log_info("\ngeneratin = %f", generating_time_end - generating_time_begin); } if(is_flag_set(compile_flags, COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY)){ Arena *p = (Arena *)pctx->perm; Arena *stage = (Arena *)&pctx->stage_arena; log_info("\nPernament arena len: %llu commit: %llu", p->len, p->memory.commit); log_info("\nStage arena len: %llu commit: %llu", stage->len, stage->memory.commit); log_info("\nScratch1 len: %llu commit: %llu", thread_ctx.scratch[0].len, thread_ctx.scratch[0].memory.commit); log_info("\nScratch2 len: %llu commit: %llu", thread_ctx.scratch[1].len, thread_ctx.scratch[1].memory.commit); } if(is_flag_set(compile_flags, COMPILE_AND_RUN)){ String testing = compile_flags&COMPILE_TESTING ? "testing"_s : ""_s; String sys = string_fmt(scratch, "a.exe %Q", testing); int result = system((char *)sys.str); assert(result != -1); if(result == 0){ log_info(PRINTF_GREEN "OK!" PRINTF_RESET); } if(result != 0){ log_info(PRINTF_RED "ERROR!" PRINTF_RESET); } } destroy_compiler(); }