/* Features - Labeled blocks / gotos :LabeledBlock - Add := for default arguments in lambda. (a := false, b := false) - Add struct default values. - Add for loop: - for i: int = 0, i < 10, i+=1 - for diff: array - iterator how to do this without function poly ? for it := iter_begin(), iter_valid(), iter_advance() - Defer - Expand macros - Using directive to bring symbols into local scope - Other kinds of casts, a cast from structs of same layout, a cast without conversion - Inject symbols into a declaration / namespace ?? - Optionally pass size and alignment calculations to C ? Cleanup - Look into unifying lambda expressions and lambda declarations - Ast_Module shouldn't require Ast_File to hold declarations etc. I think - Look into a different way of passing arguments in typechecking - Separate out the codegen stage cause that can change - Robust c declaration generation - Nicer / more readable expression generation - Detecting if return was called - Look into String_Builders in Core_Ctx - Look into stage allocator and perhaps use it more often to reduce scenarios with 2 allocators, and simplify stuff - Clean way to free all memory and reset the compiler - Bring the table? - Nice way of creating valid declarations programatically core_create_namespace("memes", { core_basic_type( }, 4); Robustness - Test suite that expects test to error out - Fix and decide what to do when initializing global variable using not constants C:/AProgramming/cparse/compiler/modules/Language.core:180:28: error: initializer element is not a compile-time constant - Test and bulletproof any, slices - This error is valid error case when someone creates a compound out of basic type C:/AProgramming/cparse/compiler/examples/arms_race/arms_race.core:137 Internal compiler error: Invalid type was passed to the compound expression, should have been an array, struct or slice result := String{data, filesize} Bytecode interpreter - Ir - Interpreter - Code generation Fun - Inject stack traces into the program - Inject instrumentation into the program Ideas - Constant arrays that evaluate fully at compile time - Rust like enum where you associate values(other structs) with key */ #include "core_compiler_includes.cpp" 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; const U32 DONT_USE_C_COMPILER = 0x10; static void compile_file(Allocator *allocator, String filename, U32 compile_flags = COMPILE_NULL) { if (is_flag_set(compile_flags, COMPILE_AND_RUN)) { printf("%s - ", filename.str); } String result = compile_file_to_string(allocator, filename); B32 r = os_write_file("generated_main.c"_s, result); assert(r); F64 total_compiler_time = os_time() - pctx->time.start; printf("%f - ", total_compiler_time); Scoped_Arena scratch(pctx->scratch); F64 begin = os_time(); if (!is_flag_set(compile_flags, DONT_USE_C_COMPILER)) { String_Builder builder = {scratch.arena}; builder.addf("clang generated_main.c -Wall -Wno-unused-function -Wno-parentheses-equality -g -o a" OS_EXE " "); For(pctx->files_to_link) { builder.addf("-l%Q ", it->intern_val); } String compiler_call = string_flatten(scratch.arena, &builder); system((const char *)compiler_call.str); printf("%s\n", compiler_call.str); } F64 end = os_time(); if (is_flag_set(compile_flags, COMPILE_PRINT_STATS)) { printf("total = %f\n", os_time() - pctx->time.start); printf("core_total = %f\n", pctx->time.total); if (!is_flag_set(compile_flags, DONT_USE_C_COMPILER)) printf("clang = %f\n", end - begin); printf("parsing = %f\n", pctx->time.parsing); printf("typecheck = %f\n", pctx->time.typechecking); printf("generatin = %f\n", pctx->time.code_generation); printf("lines lexed= %d\n", pctx->lines_lexed); } if (is_flag_set(compile_flags, COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY)) { // @! Allocator stats } if (is_flag_set(compile_flags, COMPILE_AND_RUN)) { String testing = compile_flags & COMPILE_TESTING ? "testing"_s : ""_s; #if OS_WINDOWS String sys = string_fmt(scratch.arena, "a.exe %Q", testing); #else String sys = string_fmt(scratch.arena, "./a.out %Q", testing); #endif int result = system((char *)sys.str); assert(result != -1); if (result == 0) { printf(PRINTF_GREEN "OK!" PRINTF_RESET); } if (result != 0) { printf(PRINTF_RED "ERROR!" PRINTF_RESET); } printf("\n"); } } int main(int argument_count, char **arguments) { os_enable_console_colors(); Arena arena = {}; Arena scratch = {}; arena_init(&arena, "Pernament arena"_s); arena_init(&scratch, "Pernament scratch arena"_s); Array args = {&scratch}; for (int i = 1; i < argument_count; i += 1) { String arg = string_from_cstring(arguments[i]); args.add(arg); } if (!args.len) { printf("Please specify a file to compile!"); return 0; } For(args) { if (it == "-testing"_s) { Scoped_Arena _scope(&scratch); Array examples = os_list_dir(&scratch, &scratch, "examples"_s); Array tests = os_list_dir(&scratch, &scratch, "tests"_s); For(examples) { if (it.is_directory) continue; String filename = string_skip_to_last_slash(it.relative_path); if (filename.len && filename.str[0] == '_') continue; compile_file(&arena, it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING); } For(tests) { if (it.is_directory) continue; compile_file(&arena, it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING); } } else { String program_name = string_from_cstring(arguments[1]); compile_file(&arena, program_name, COMPILE_PRINT_STATS | DONT_USE_C_COMPILER); } } printf("End of program\n"); #if 1 if (IsDebuggerPresent()) { Breakpoint; } #endif return 0; }