452 lines
16 KiB
C++
452 lines
16 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 = false;
|
|
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__string = {TYPE_STRING, sizeof(String), __alignof(String)};
|
|
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__int = {TYPE_INT, sizeof(int), __alignof(int)};
|
|
|
|
pctx->type_char = &pctx->type__char;
|
|
pctx->type_int = &pctx->type__int;
|
|
pctx->type_void = &pctx->type__void;
|
|
|
|
// pctx->type_any; // Needs to be inited at runtime
|
|
|
|
pctx->type_type = &pctx->type__type;
|
|
// pctx->type_string = &pctx->type__string;
|
|
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, "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, "int"_s, pctx->type_int);
|
|
insert_builtin_type_into_scope(module, "char"_s, pctx->type_char);
|
|
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_Scope *scope = ast_decl_scope(&pctx->null_token, pctx->perm, get(&module->all_loaded_files, 0));
|
|
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;
|
|
}
|