358 lines
13 KiB
C++
358 lines
13 KiB
C++
|
|
CORE_Static void
|
|
core_init_compiler(Core_Ctx *ctx, Allocator *allocator) {
|
|
ctx->init_ctx_time_begin = os_time();
|
|
pctx = ctx;
|
|
ctx->perm_push_only = make_push_arena(allocator);
|
|
ctx->perm = &ctx->perm_push_only;
|
|
ctx->scratch = allocate_scratch_arena(ctx->perm, mib(1));
|
|
ctx->stage_arena = allocate_scratch_arena(ctx->perm, mib(1));
|
|
ctx->heap = allocator;
|
|
ctx->type_map = map_make(ctx->heap, 2048);
|
|
ctx->gen = {ctx->perm};
|
|
ctx->helper_builder = {ctx->perm};
|
|
ctx->scope_ids = 1;
|
|
bigint_allocator = ctx->perm;
|
|
|
|
ctx->tokens = array_make<Token>(ctx->heap, 4096 * 4);
|
|
ctx->interns = intern_table_make(ctx->perm, ctx->heap, 2048);
|
|
|
|
/*#import meta
|
|
for i in meta.keywords:
|
|
print(f'keyword_{i.lower()} = ctx->intern("{i}"_s);')
|
|
print(f'ctx->interns.first_keyword = keyword_{meta.keywords[0].lower()}.str;')
|
|
print(f'ctx->interns.last_keyword = keyword_{meta.keywords[-1].lower()}.str;')
|
|
|
|
for i in meta.interns:
|
|
print(f'intern_{i.lower()} = ctx->intern("{i}"_s);')
|
|
|
|
index = 0
|
|
for i in meta.token_simple_expr:
|
|
if i[1] != "SPECIAL":
|
|
print(f'op_info_table[{index}].op = ctx->intern("{i[1]}"_s);')
|
|
index += 1
|
|
|
|
*/
|
|
keyword_struct = ctx->intern("struct"_s);
|
|
keyword_union = ctx->intern("union"_s);
|
|
keyword_true = ctx->intern("true"_s);
|
|
keyword_default = ctx->intern("default"_s);
|
|
keyword_break = ctx->intern("break"_s);
|
|
keyword_false = ctx->intern("false"_s);
|
|
keyword_return = ctx->intern("return"_s);
|
|
keyword_switch = ctx->intern("switch"_s);
|
|
keyword_assert = ctx->intern("Assert"_s);
|
|
keyword_if = ctx->intern("if"_s);
|
|
keyword_elif = ctx->intern("elif"_s);
|
|
keyword_pass = ctx->intern("pass"_s);
|
|
keyword_else = ctx->intern("else"_s);
|
|
keyword_for = ctx->intern("for"_s);
|
|
keyword_enum = ctx->intern("enum"_s);
|
|
ctx->interns.first_keyword = keyword_struct.str;
|
|
ctx->interns.last_keyword = keyword_enum.str;
|
|
intern_typeof = ctx->intern("TypeOf"_s);
|
|
intern_sizeof = ctx->intern("SizeOf"_s);
|
|
intern_len = ctx->intern("Len"_s);
|
|
intern_alignof = ctx->intern("AlignOf"_s);
|
|
intern_foreign = ctx->intern("foreign"_s);
|
|
intern_strict = ctx->intern("strict"_s);
|
|
intern_void = ctx->intern("void"_s);
|
|
intern_flag = ctx->intern("flag"_s);
|
|
intern_it = ctx->intern("it"_s);
|
|
intern_load = ctx->intern("load"_s);
|
|
intern_import = ctx->intern("import"_s);
|
|
intern_link = ctx->intern("link"_s);
|
|
op_info_table[0].op = ctx->intern("*"_s);
|
|
op_info_table[1].op = ctx->intern("/"_s);
|
|
op_info_table[2].op = ctx->intern("%"_s);
|
|
op_info_table[3].op = ctx->intern("<<"_s);
|
|
op_info_table[4].op = ctx->intern(">>"_s);
|
|
op_info_table[5].op = ctx->intern("+"_s);
|
|
op_info_table[6].op = ctx->intern("-"_s);
|
|
op_info_table[7].op = ctx->intern("=="_s);
|
|
op_info_table[8].op = ctx->intern("<="_s);
|
|
op_info_table[9].op = ctx->intern(">="_s);
|
|
op_info_table[10].op = ctx->intern("<"_s);
|
|
op_info_table[11].op = ctx->intern(">"_s);
|
|
op_info_table[12].op = ctx->intern("!="_s);
|
|
op_info_table[13].op = ctx->intern("&"_s);
|
|
op_info_table[14].op = ctx->intern("|"_s);
|
|
op_info_table[15].op = ctx->intern("^"_s);
|
|
op_info_table[16].op = ctx->intern("&&"_s);
|
|
op_info_table[17].op = ctx->intern("||"_s);
|
|
op_info_table[18].op = ctx->intern("~"_s);
|
|
op_info_table[19].op = ctx->intern("!"_s);
|
|
/*END*/
|
|
|
|
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);
|
|
ctx->init_ctx_time_end = os_time();
|
|
}
|
|
|
|
CORE_Static void
|
|
core_bootstrap_compiler(Allocator *allocator) {
|
|
Core_Ctx *ctx = allocate_struct(allocator, Core_Ctx);
|
|
core_init_compiler(ctx, allocator);
|
|
}
|
|
|
|
CORE_Static void
|
|
insert_builtin_type_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);
|
|
}
|
|
|
|
CORE_Static void
|
|
parse_all_modules() {
|
|
pctx->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;
|
|
}
|
|
pctx->parsing_time_end = os_time();
|
|
}
|
|
|
|
CORE_Static Ast_Module *
|
|
add_module(Token *pos, Intern_String filename, B32 command_line_module) {
|
|
Scratch_Arena *scratch = pctx->scratch;
|
|
Scratch_Scope _scope(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->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;
|
|
}
|
|
|
|
CORE_Static void
|
|
resolve_everything_in_module(Ast_Module *module) {
|
|
if (module->state == MODULE_RESOLVED)
|
|
return;
|
|
pctx->resolving_time_begin = os_time();
|
|
Iter_Named(&module->all_loaded_files, file) {
|
|
Iter(&file.item[0]->decls) {
|
|
Ast_Decl *decl = it.item[0];
|
|
resolve_name(file.item[0], decl->pos, decl->name);
|
|
|
|
if (decl->kind == AST_STRUCT) {
|
|
type_complete(decl->type_val);
|
|
}
|
|
}
|
|
}
|
|
module->state = MODULE_RESOLVED;
|
|
pctx->resolving_time_end = os_time();
|
|
}
|
|
|
|
CORE_Static String
|
|
compile_file_to_string(Allocator *allocator, String filename) {
|
|
F64 total_time = os_time();
|
|
core_bootstrap_compiler(allocator);
|
|
pctx->total_time = total_time;
|
|
{
|
|
Ast_Module *module = add_module(0, pctx->intern("Language.core"_s));
|
|
{
|
|
insert_builtin_type_into_scope(module, "S64"_s, type_s64);
|
|
insert_builtin_type_into_scope(module, "S32"_s, type_s32);
|
|
insert_builtin_type_into_scope(module, "S16"_s, type_s16);
|
|
insert_builtin_type_into_scope(module, "S8"_s, type_s8);
|
|
insert_builtin_type_into_scope(module, "int"_s, type_int);
|
|
insert_builtin_type_into_scope(module, "char"_s, type_char);
|
|
insert_builtin_type_into_scope(module, "U64"_s, type_u64);
|
|
insert_builtin_type_into_scope(module, "U32"_s, type_u32);
|
|
insert_builtin_type_into_scope(module, "U16"_s, type_u16);
|
|
insert_builtin_type_into_scope(module, "U8"_s, type_u8);
|
|
insert_builtin_type_into_scope(module, "F64"_s, type_f64);
|
|
insert_builtin_type_into_scope(module, "F32"_s, type_f32);
|
|
insert_builtin_type_into_scope(module, "void"_s, type_void);
|
|
insert_builtin_type_into_scope(module, "Bool"_s, type_bool);
|
|
insert_builtin_type_into_scope(module, "String"_s, type_string);
|
|
insert_builtin_type_into_scope(module, "Type"_s, type_type);
|
|
}
|
|
|
|
{
|
|
Ast_Scope *scope = ast_decl_scope(&null_token, pctx->perm, get(&module->all_loaded_files, 0));
|
|
Ast_Decl * decl = ast_namespace(&null_token, scope, pctx->intern("Const"_s));
|
|
decl->state = DECL_RESOLVED;
|
|
|
|
Value v1 = {};
|
|
v1.type = untyped_string;
|
|
v1.intern_val = pctx->intern(OS_NAME);
|
|
Ast_Decl *const_os1 = ast_const(&null_token, pctx->intern("OSName"_s), v1);
|
|
const_os1->state = DECL_RESOLVED;
|
|
insert_into_scope(scope, const_os1);
|
|
|
|
Value v2 = {};
|
|
v1.type = untyped_string;
|
|
v1.intern_val = pctx->intern(OS_NAME_LOWER);
|
|
Ast_Decl *const_os2 = ast_const(&null_token, pctx->intern("OSNameLower"_s), v2);
|
|
const_os2->state = DECL_RESOLVED;
|
|
insert_into_scope(scope, const_os2);
|
|
|
|
insert_into_scope(module, decl);
|
|
}
|
|
|
|
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);
|
|
|
|
|
|
pctx->stage_arena->len = 0;
|
|
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;
|
|
|
|
CORE_Static void
|
|
compile_file(Allocator *allocator, String filename, U32 compile_flags = COMPILE_NULL) {
|
|
String result = compile_file_to_string(allocator, filename);
|
|
if (is_flag_set(compile_flags, COMPILE_AND_RUN)) {
|
|
log_info_no_nl("%Q - ", filename);
|
|
}
|
|
|
|
B32 r = os_write_file("program.c"_s, result);
|
|
assert(r);
|
|
F64 total_compiler_time = os_time() - pctx->total_time;
|
|
log_info_no_nl("%f - ", total_compiler_time);
|
|
|
|
Scratch_Arena *scratch = pctx->scratch;
|
|
Scratch_Scope _scope(scratch);
|
|
|
|
F64 begin = os_time();
|
|
String_Builder builder = {scratch};
|
|
builder.addf("clang program.c -Wall -Wno-unused-function -Wno-parentheses-equality -g -o a" OS_EXE " ");
|
|
Iter(&pctx->files_to_link) {
|
|
builder.addf("-l%Q ", it.item[0]->intern_val);
|
|
}
|
|
String compiler_call = string_flatten(scratch, &builder);
|
|
|
|
log_trace("%Q", compiler_call);
|
|
system((const char *)compiler_call.str);
|
|
F64 end = os_time();
|
|
|
|
if (is_flag_set(compile_flags, COMPILE_PRINT_STATS)) {
|
|
log_info("total = %f", os_time() - pctx->total_time);
|
|
log_info("clang = %f", end - begin);
|
|
log_info("parsing = %f", pctx->parsing_time_end - pctx->parsing_time_begin);
|
|
log_info("resolving = %f", pctx->resolving_time_end - pctx->resolving_time_begin);
|
|
log_info("generatin = %f", pctx->generating_time_end - pctx->generating_time_begin);
|
|
}
|
|
|
|
if (is_flag_set(compile_flags, COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY)) {
|
|
// @! allocator stats
|
|
//Arena *p = (Arena *)pctx->perm;
|
|
//Arena *stage = (Arena *)&pctx->stage_arena;
|
|
//log_info("Pernament arena len: %llu commit: %llu", pct, p->memory.commit);
|
|
//log_info("Stage arena len: %llu commit: %llu", stage->len, stage->memory.commit);
|
|
//log_info("Scratch1 len: %llu commit: %llu", thread_ctx.scratch[0].len, thread_ctx.scratch[0].memory.commit);
|
|
//log_info("Scratch2 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;
|
|
#if OS_WINDOWS
|
|
String sys = string_fmt(scratch, "a.exe %Q", testing);
|
|
#else
|
|
String sys = string_fmt(scratch, "./a.out %Q", testing);
|
|
#endif
|
|
int result = system((char *)sys.str);
|
|
assert(result != -1);
|
|
if (result == 0) {
|
|
log_info_no_nl(PRINTF_GREEN "OK!" PRINTF_RESET);
|
|
}
|
|
if (result != 0) {
|
|
log_info_no_nl(PRINTF_RED "ERROR!" PRINTF_RESET);
|
|
}
|
|
log_info("");
|
|
}
|
|
|
|
}
|