Files
corelang/core_compiler.cpp
2023-04-20 22:29:31 +02:00

483 lines
18 KiB
C++

// apifn
static void core_free_compiler() {
deallocate(pctx->heap, pctx->type_map.data);
deallocate(pctx->heap, pctx->interns.map.data);
arena_release(pctx->stage_arena);
arena_release(pctx->scratch);
arena_release(pctx->perm);
}
// apifn
static void core_init_compiler(Core_Ctx *ctx, Allocator *allocator) {
ctx->time.init_context = os_time();
pctx = ctx;
ctx->emit_type_info = true;
ctx->emit_line_directives = true;
ctx->debugger_break_on_compiler_error = true;
ctx->same_scope_token = {SAME_SCOPE};
arena_init(&ctx->perm_push_only, "Perm Push Only"_s);
arena_init(&ctx->scratch_, "Scratch"_s);
arena_init(&ctx->stage_arena_, "Stage Arena"_s);
arena_init(&ctx->token_arena, "Token Arena"_s);
ctx->scratch = &ctx->scratch_;
ctx->stage_arena = &ctx->stage_arena_;
ctx->perm = &ctx->perm_push_only;
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->interns = intern_table_make(ctx->perm, ctx->heap, 2048);
/*#import meta
for i in meta.keywords:
print(f'pctx->keyword_{i.lower()} = pctx->intern("{i}"_s);')
print(f'pctx->interns.first_keyword = pctx->keyword_{meta.keywords[0].lower()}.str;')
print(f'pctx->interns.last_keyword = pctx->keyword_{meta.keywords[-1].lower()}.str;')
for i in meta.interns:
print(f'pctx->intern_{i.lower()} = pctx->intern("{i}"_s);')
index = 0
for i in meta.token_simple_expr:
if i[1] != "SPECIAL":
print(f'pctx->op_info_table[{index}] = {{pctx->intern("{i[1]}"_s), "{i[0].upper()}"_s, TK_{i[0]}, {int(i[2]&meta.BINARY_EXPR>0)}, {int(i[2]&meta.UNARY_EXPR>0)}}};')
index += 1
*/
pctx->keyword_struct = pctx->intern("struct"_s);
pctx->keyword_union = pctx->intern("union"_s);
pctx->keyword_true = pctx->intern("true"_s);
pctx->keyword_default = pctx->intern("default"_s);
pctx->keyword_break = pctx->intern("break"_s);
pctx->keyword_false = pctx->intern("false"_s);
pctx->keyword_return = pctx->intern("return"_s);
pctx->keyword_switch = pctx->intern("switch"_s);
pctx->keyword_assert = pctx->intern("Assert"_s);
pctx->keyword_if = pctx->intern("if"_s);
pctx->keyword_elif = pctx->intern("elif"_s);
pctx->keyword_pass = pctx->intern("pass"_s);
pctx->keyword_else = pctx->intern("else"_s);
pctx->keyword_for = pctx->intern("for"_s);
pctx->keyword_enum = pctx->intern("enum"_s);
pctx->interns.first_keyword = pctx->keyword_struct.str;
pctx->interns.last_keyword = pctx->keyword_enum.str;
pctx->intern_typeof = pctx->intern("typeof"_s);
pctx->intern_sizeof = pctx->intern("sizeof"_s);
pctx->intern_len = pctx->intern("Len"_s);
pctx->intern_alignof = pctx->intern("alignof"_s);
pctx->intern_foreign = pctx->intern("foreign"_s);
pctx->intern_strict = pctx->intern("strict"_s);
pctx->intern_void = pctx->intern("void"_s);
pctx->intern_flag = pctx->intern("flag"_s);
pctx->intern_it = pctx->intern("it"_s);
pctx->intern_load = pctx->intern("load"_s);
pctx->intern_import = pctx->intern("import"_s);
pctx->intern_link = pctx->intern("link"_s);
pctx->op_info_table[0] = {pctx->intern("*"_s), "MUL"_s, TK_Mul, 1, 0};
pctx->op_info_table[1] = {pctx->intern("/"_s), "DIV"_s, TK_Div, 1, 0};
pctx->op_info_table[2] = {pctx->intern("%"_s), "MOD"_s, TK_Mod, 1, 0};
pctx->op_info_table[3] = {pctx->intern("<<"_s), "LEFTSHIFT"_s, TK_LeftShift, 1, 0};
pctx->op_info_table[4] = {pctx->intern(">>"_s), "RIGHTSHIFT"_s, TK_RightShift, 1, 0};
pctx->op_info_table[5] = {pctx->intern("+"_s), "ADD"_s, TK_Add, 1, 1};
pctx->op_info_table[6] = {pctx->intern("-"_s), "SUB"_s, TK_Sub, 1, 1};
pctx->op_info_table[7] = {pctx->intern("=="_s), "EQUALS"_s, TK_Equals, 1, 0};
pctx->op_info_table[8] = {pctx->intern("<="_s), "LESSERTHENOREQUAL"_s, TK_LesserThenOrEqual, 1, 0};
pctx->op_info_table[9] = {pctx->intern(">="_s), "GREATERTHENOREQUAL"_s, TK_GreaterThenOrEqual, 1, 0};
pctx->op_info_table[10] = {pctx->intern("<"_s), "LESSERTHEN"_s, TK_LesserThen, 1, 0};
pctx->op_info_table[11] = {pctx->intern(">"_s), "GREATERTHEN"_s, TK_GreaterThen, 1, 0};
pctx->op_info_table[12] = {pctx->intern("!="_s), "NOTEQUALS"_s, TK_NotEquals, 1, 0};
pctx->op_info_table[13] = {pctx->intern("&"_s), "BITAND"_s, TK_BitAnd, 1, 0};
pctx->op_info_table[14] = {pctx->intern("|"_s), "BITOR"_s, TK_BitOr, 1, 0};
pctx->op_info_table[15] = {pctx->intern("^"_s), "BITXOR"_s, TK_BitXor, 1, 0};
pctx->op_info_table[16] = {pctx->intern("&&"_s), "AND"_s, TK_And, 1, 0};
pctx->op_info_table[17] = {pctx->intern("||"_s), "OR"_s, TK_Or, 1, 0};
pctx->op_info_table[18] = {pctx->intern("~"_s), "NEG"_s, TK_Neg, 0, 1};
pctx->op_info_table[19] = {pctx->intern("!"_s), "NOT"_s, TK_Not, 0, 1};
/*END*/
// Init types
pctx->type__void = {TYPE_VOID};
pctx->type__bool = {TYPE_BOOL, sizeof(bool), __alignof(bool)};
pctx->type__type = {TYPE_TYPE, sizeof(S64), __alignof(S64)};
pctx->type__f32 = {TYPE_F32, sizeof(F32), __alignof(F32)};
pctx->type__f64 = {TYPE_F64, sizeof(F64), __alignof(F64)};
pctx->type__s8 = {TYPE_S8, sizeof(S8), __alignof(S8)};
pctx->type__s16 = {TYPE_S16, sizeof(S16), __alignof(S16)};
pctx->type__s32 = {TYPE_S32, sizeof(S32), __alignof(S32)};
pctx->type__s64 = {TYPE_S64, sizeof(S64), __alignof(S64)};
pctx->type__u8 = {TYPE_U8, sizeof(U8), __alignof(U8), true};
pctx->type__u16 = {TYPE_U16, sizeof(U16), __alignof(U16), true};
pctx->type__u32 = {TYPE_U32, sizeof(U32), __alignof(U32), true};
pctx->type__u64 = {TYPE_U64, sizeof(U64), __alignof(U64), true};
pctx->type__untyped_bool = {TYPE_UNTYPED_BOOL, sizeof(bool), __alignof(bool)};
pctx->type__untyped_int = {TYPE_UNTYPED_INT, sizeof(S64), __alignof(S64)};
pctx->type__untyped_string = {TYPE_UNTYPED_STRING, sizeof(String), __alignof(String)};
pctx->type__untyped_float = {TYPE_UNTYPED_FLOAT, sizeof(double), __alignof(double)};
pctx->type__char = {TYPE_CHAR, sizeof(char), __alignof(char)};
pctx->type__uchar = {TYPE_UCHAR, sizeof(unsigned char), __alignof(unsigned char), true};
pctx->type__int = {TYPE_INT, sizeof(int), __alignof(int)};
pctx->type__uint = {TYPE_UINT, sizeof(unsigned), __alignof(unsigned), true};
pctx->type__long = {TYPE_LONG, sizeof(long), __alignof(long)};
pctx->type__ulong = {TYPE_ULONG, sizeof(unsigned long), __alignof(unsigned long), true};
pctx->type__llong = {TYPE_LLONG, sizeof(long long), __alignof(long long)};
pctx->type__ullong = {TYPE_ULLONG, sizeof(unsigned long long), __alignof(unsigned long long), true};
pctx->type__short = {TYPE_SHORT, sizeof(short), __alignof(short)};
pctx->type__ushort = {TYPE_USHORT, sizeof(unsigned short), __alignof(unsigned short), true};
pctx->type_char = &pctx->type__char;
pctx->type_uchar = &pctx->type__uchar;
pctx->type_int = &pctx->type__int;
pctx->type_uint = &pctx->type__uint;
pctx->type_long = &pctx->type__long;
pctx->type_ulong = &pctx->type__ulong;
pctx->type_llong = &pctx->type__llong;
pctx->type_ullong = &pctx->type__ullong;
pctx->type_short = &pctx->type__short;
pctx->type_ushort = &pctx->type__ushort;
pctx->type_void = &pctx->type__void;
// pctx->type__string = {TYPE_STRING, sizeof(String), __alignof(String)};
// pctx->type_any; // Needs to be inited at runtime
// pctx->type_string = &pctx->type__string;
pctx->type_type = &pctx->type__type;
pctx->type_bool = &pctx->type__bool;
pctx->type_f32 = &pctx->type__f32;
pctx->type_f64 = &pctx->type__f64;
pctx->type_s8 = &pctx->type__s8;
pctx->type_s16 = &pctx->type__s16;
pctx->type_s32 = &pctx->type__s32;
pctx->type_s64 = &pctx->type__s64;
pctx->type_u8 = &pctx->type__u8;
pctx->type_u16 = &pctx->type__u16;
pctx->type_u32 = &pctx->type__u32;
pctx->type_u64 = &pctx->type__u64;
pctx->untyped_string = &pctx->type__untyped_string;
pctx->untyped_bool = &pctx->type__untyped_bool;
pctx->untyped_int = &pctx->type__untyped_int;
pctx->untyped_float = &pctx->type__untyped_float;
pctx->type__vargs = {TYPE_VARGS};
pctx->type_vargs = &pctx->type__vargs;
pctx->type_pointer_to_char = type_pointer(pctx->type_char);
pctx->type_pointer_to_void = type_pointer(pctx->type_void);
// 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->time.init_context = os_time() - ctx->time.init_context;
}
// apifn
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->time.parsing = os_time();
For2(pctx->modules, module) {
if (module->state != MODULE_REGISTERED)
continue;
For(module->all_loaded_files) {
parse_file(it);
}
if (module != pctx->language_base_module) {
add(pctx->perm, &module->implicit_imports, (Ast_Scope *)pctx->language_base_module);
}
module->state = MODULE_PARSED;
}
pctx->time.parsing = os_time() - pctx->time.parsing;
}
CORE_Static Ast_Module *
add_module(Token *pos, Intern_String filename, B32 command_line_module, bool string_only_module) {
Arena *scratch = pctx->scratch;
Scoped_Arena _scope(scratch);
String absolute_file_path = {};
String absolute_base_folder = {};
if (string_only_module) {
absolute_file_path = filename.s;
absolute_base_folder = filename.s;
}
else {
//
// 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_trace("Returning registered module: %Q\n", absolute_file_path);
return it;
}
}
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 Ast_File *
custom_parse_string(String string) {
Ast_Module *module = pctx->custom_module;
Ast_File *file = get(&module->all_loaded_files, 0);
file->filecontent = string;
parse_file(file);
return file;
}
CORE_Static void
resolve_everything_in_module(Ast_Module *module) {
if (module->state == MODULE_RESOLVED)
return;
pctx->time.typechecking = os_time();
For2(module->all_loaded_files, file) {
For2(file->decls, decl) {
if (decl->flags & AST_POLYMORPH) continue;
// @cleanup: Why I'm not calling resolve_decl here?
resolve_name(file, decl->pos, decl->name);
if (decl->kind == AST_STRUCT || decl->kind == AST_UNION) type_complete(decl->type_val);
}
}
module->state = MODULE_RESOLVED;
pctx->time.typechecking = os_time() - pctx->time.typechecking;
}
CORE_Static void
init_language_core() {
pctx->custom_module = add_module(0, pctx->intern("Custom.core"_s), false, true);
pctx->custom_module->state = MODULE_RESOLVED;
Ast_Module *module = add_module(0, pctx->intern("Language.core"_s), false, true);
get(&module->all_loaded_files, 0)->filecontent =
R"(
Any :: struct
data: *void
type: Type
String :: struct
data: *U8
len: S64
Type_Info_Kind :: enum
S64 // FIRST_NUMERIC
S32
S16
S8
INT
CHAR
U64
U32
U16
U8
F32
F64
POINTER
BOOL // LAST_NUMERIC
STRING
VOID
ARRAY
LAMBDA
STRUCT
UNION
ENUM
TYPE
SLICE
TUPLE
Type_Info_Struct_Member :: struct
name: String
type: Type
offset: S64
Type_Info :: struct
kind: Type_Info_Kind
size: S64
align: S64
is_unsigned: bool
type: Type
base_type: Type
array_size: S64
struct_members: []Type_Info_Struct_Member
lambda_arguments: []Type_Info
lambda_return: Type
type_infos_len: S64 #foreign
type_infos : *Type_Info #foreign
GetTypeInfo :: (type: Type): *Type_Info
id := type->S64
if id >= type_infos_len
return 0
return type_infos + id
)"_s;
{
insert_builtin_type_into_scope(module, "char"_s, pctx->type_char);
insert_builtin_type_into_scope(module, "uchar"_s, pctx->type_uchar);
insert_builtin_type_into_scope(module, "int"_s, pctx->type_int);
insert_builtin_type_into_scope(module, "uint"_s, pctx->type_uint);
insert_builtin_type_into_scope(module, "long"_s, pctx->type_long);
insert_builtin_type_into_scope(module, "ulong"_s, pctx->type_ulong);
insert_builtin_type_into_scope(module, "llong"_s, pctx->type_llong);
insert_builtin_type_into_scope(module, "ullong"_s, pctx->type_ullong);
insert_builtin_type_into_scope(module, "short"_s, pctx->type_short);
insert_builtin_type_into_scope(module, "ushort"_s, pctx->type_ushort);
insert_builtin_type_into_scope(module, "S64"_s, pctx->type_s64);
insert_builtin_type_into_scope(module, "S32"_s, pctx->type_s32);
insert_builtin_type_into_scope(module, "S16"_s, pctx->type_s16);
insert_builtin_type_into_scope(module, "S8"_s, pctx->type_s8);
insert_builtin_type_into_scope(module, "U64"_s, pctx->type_u64);
insert_builtin_type_into_scope(module, "U32"_s, pctx->type_u32);
insert_builtin_type_into_scope(module, "U16"_s, pctx->type_u16);
insert_builtin_type_into_scope(module, "U8"_s, pctx->type_u8);
insert_builtin_type_into_scope(module, "F64"_s, pctx->type_f64);
insert_builtin_type_into_scope(module, "F32"_s, pctx->type_f32);
insert_builtin_type_into_scope(module, "void"_s, pctx->type_void);
insert_builtin_type_into_scope(module, "bool"_s, pctx->type_bool);
// insert_builtin_type_into_scope(module, "String"_s, pctx->type_string);
insert_builtin_type_into_scope(module, "Type"_s, pctx->type_type);
}
{
Ast_File *file = get(&module->all_loaded_files, 0);
Ast_Scope *scope = ast_decl_scope(&pctx->null_token, pctx->perm, file);
scope->parent_scope = file;
scope->module = module;
Ast_Decl *decl = ast_namespace(&pctx->null_token, scope, pctx->intern("Const"_s));
decl->state = DECL_RESOLVED;
Value v1 = {};
v1.type = pctx->untyped_string;
v1.intern_val = pctx->intern(OS_NAME);
Ast_Decl *const_os1 = ast_const(&pctx->null_token, pctx->intern("OSName"_s), v1);
const_os1->state = DECL_RESOLVED;
insert_into_scope(scope, const_os1);
Value v2 = {};
v1.type = pctx->untyped_string;
v1.intern_val = pctx->intern(OS_NAME_LOWER);
Ast_Decl *const_os2 = ast_const(&pctx->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 == pctx->type_type);
pctx->type_any = any_decl->type_val;
Ast_Decl *string_decl = search_for_single_decl(module, pctx->intern("String"_s));
assert(string_decl->type == pctx->type_type);
pctx->type_string = string_decl->type_val;
}
CORE_Static String
compile_file_to_string(Allocator *allocator, String filename) {
F64 total_time = os_time();
core_bootstrap_compiler(allocator);
pctx->time.total = total_time;
pctx->time.start = total_time;
init_language_core();
Ast_Module *module = add_module(0, pctx->intern(filename), true);
parse_all_modules();
assert(module);
resolve_everything_in_module(module);
String result = compile_to_c_code();
pctx->time.total = os_time() - pctx->time.total;
return result;
}