Compiler restructure, now can call compiler to compile files, fix error where strict type
was equal it's original type, working on examples
This commit is contained in:
@@ -689,194 +689,8 @@ gen_ast(Ast *ast){
|
||||
}
|
||||
}
|
||||
|
||||
function void
|
||||
parse_file(Ast_File *file){
|
||||
assert(file);
|
||||
|
||||
Scratch scratch;
|
||||
file->filecontent = os_read_file(pctx->perm, file->absolute_file_path);
|
||||
if(file->filecontent.len == 0){
|
||||
compiler_error(file->pos, "Failed to open file \"%Q\"", file->absolute_file_path);
|
||||
}
|
||||
|
||||
|
||||
pctx->currently_parsed_file = file;
|
||||
pctx->currently_parsed_scope = file;
|
||||
lex_restream(pctx, file->filecontent, file->absolute_file_path);
|
||||
while(token_expect(SAME_SCOPE)){
|
||||
if(token_match_pound(pctx->intern("load"_s))){
|
||||
parse_load(true);
|
||||
continue;
|
||||
} else if(token_match_pound(pctx->intern("import"_s))){
|
||||
parse_import(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
Ast_Decl *decl = parse_decl(true);
|
||||
if(!decl) break;
|
||||
|
||||
set_flag(decl->flags, AST_GLOBAL);
|
||||
if(decl->kind == AST_STRUCT){
|
||||
decl->type = type_type;
|
||||
decl->type_val = type_incomplete(decl);
|
||||
decl->state = DECL_RESOLVED;
|
||||
}
|
||||
|
||||
insert_into_scope(file, decl);
|
||||
}
|
||||
pctx->currently_parsed_scope = 0;
|
||||
pctx->currently_parsed_file = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
pctx->all_types.add(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();
|
||||
for(S64 i = 0; i < pctx->modules.len; i++){
|
||||
Ast_Module *module = pctx->modules[i];
|
||||
if(module->state != MODULE_REGISTERED) continue;
|
||||
|
||||
for(S64 j = 0; j < module->all_loaded_files.len; j++){
|
||||
Ast_File *file = module->all_loaded_files.data[j];
|
||||
parse_file(file);
|
||||
}
|
||||
|
||||
if(module != 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{
|
||||
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_info("Returning registered module: %Q\n", absolute_file_path);
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
log_info("Adding module: %Q\n", filename);
|
||||
result->module = result; // @warning: self referential
|
||||
result->file = result; // @warning: self referential
|
||||
result->all_loaded_files = {pctx->heap};
|
||||
result->implicit_imports = {pctx->heap};
|
||||
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);
|
||||
pctx->modules.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
global F64 resolving_time_begin;
|
||||
global F64 resolving_time_end;
|
||||
function void
|
||||
resolve_everything_in_module(Ast_Module *module){
|
||||
if(module->state == MODULE_RESOLVED) return;
|
||||
resolving_time_begin = os_time();
|
||||
for(S64 i = 0; i < module->all_loaded_files.len; i++){
|
||||
Ast_File *file = module->all_loaded_files[i];
|
||||
For(file->decls){
|
||||
resolve_name(file, it->pos, it->name);
|
||||
if(it->kind == AST_STRUCT){
|
||||
type_complete(it->type_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
module->state = MODULE_RESOLVED;
|
||||
resolving_time_end = os_time();
|
||||
}
|
||||
|
||||
global F64 init_ctx_time_begin;
|
||||
global F64 init_ctx_time_end;
|
||||
function void
|
||||
begin_compilation(){
|
||||
init_ctx_time_begin = os_time();
|
||||
OS_Heap *heap = exp_alloc_type(&pernament_arena, OS_Heap);
|
||||
*heap = win32_os_heap_create(false, mib(4), 0);
|
||||
Parse_Ctx *ctx = exp_alloc_type(&pernament_arena, Parse_Ctx);
|
||||
parse_init(ctx, &pernament_arena, heap);
|
||||
init_ctx_time_end = os_time();
|
||||
}
|
||||
|
||||
global F64 generating_time_begin;
|
||||
global F64 generating_time_end;
|
||||
function String
|
||||
get_compilation_result(){
|
||||
compile_to_c_code(){
|
||||
generating_time_begin = os_time();
|
||||
|
||||
gen(R"==(
|
||||
@@ -1017,8 +831,3 @@ typedef struct String{
|
||||
generating_time_end = os_time();
|
||||
return string_result;
|
||||
}
|
||||
|
||||
function void
|
||||
compiler_cleanup(){
|
||||
exp_destroy(pctx->heap);
|
||||
}
|
||||
|
||||
249
compiler.cpp
Normal file
249
compiler.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
global F64 generating_time_begin;
|
||||
global F64 generating_time_end;
|
||||
global F64 resolving_time_begin;
|
||||
global F64 resolving_time_end;
|
||||
global F64 total_time;
|
||||
global F64 init_ctx_time_begin;
|
||||
global F64 init_ctx_time_end;
|
||||
|
||||
function void
|
||||
begin_compilation(){
|
||||
init_ctx_time_begin = os_time();
|
||||
OS_Heap *heap = exp_alloc_type(&pernament_arena, OS_Heap);
|
||||
*heap = win32_os_heap_create(false, mib(4), 0);
|
||||
Parse_Ctx *ctx = exp_alloc_type(&pernament_arena, Parse_Ctx);
|
||||
parse_init(ctx, &pernament_arena, heap);
|
||||
init_ctx_time_end = os_time();
|
||||
}
|
||||
|
||||
function void
|
||||
compiler_cleanup(){
|
||||
exp_destroy(pctx->heap);
|
||||
exp_free_all(pctx->perm);
|
||||
}
|
||||
|
||||
function void
|
||||
parse_file(Ast_File *file){
|
||||
assert(file);
|
||||
|
||||
Scratch scratch;
|
||||
file->filecontent = os_read_file(pctx->perm, file->absolute_file_path);
|
||||
if(file->filecontent.len == 0){
|
||||
compiler_error(file->pos, "Failed to open file \"%Q\"", file->absolute_file_path);
|
||||
}
|
||||
|
||||
|
||||
pctx->currently_parsed_file = file;
|
||||
pctx->currently_parsed_scope = file;
|
||||
lex_restream(pctx, file->filecontent, file->absolute_file_path);
|
||||
while(token_expect(SAME_SCOPE)){
|
||||
if(token_match_pound(pctx->intern("load"_s))){
|
||||
parse_load(true);
|
||||
continue;
|
||||
} else if(token_match_pound(pctx->intern("import"_s))){
|
||||
parse_import(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
Ast_Decl *decl = parse_decl(true);
|
||||
if(!decl) break;
|
||||
|
||||
set_flag(decl->flags, AST_GLOBAL);
|
||||
if(decl->kind == AST_STRUCT){
|
||||
decl->type = type_type;
|
||||
decl->type_val = type_incomplete(decl);
|
||||
decl->state = DECL_RESOLVED;
|
||||
}
|
||||
|
||||
insert_into_scope(file, decl);
|
||||
}
|
||||
pctx->currently_parsed_scope = 0;
|
||||
pctx->currently_parsed_file = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
pctx->all_types.add(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();
|
||||
for(S64 i = 0; i < pctx->modules.len; i++){
|
||||
Ast_Module *module = pctx->modules[i];
|
||||
if(module->state != MODULE_REGISTERED) continue;
|
||||
|
||||
for(S64 j = 0; j < module->all_loaded_files.len; j++){
|
||||
Ast_File *file = module->all_loaded_files.data[j];
|
||||
parse_file(file);
|
||||
}
|
||||
|
||||
if(module != 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{
|
||||
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_info("Returning registered module: %Q\n", absolute_file_path);
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// log_info("Adding module: %Q\n", filename);
|
||||
result->module = result; // @warning: self referential
|
||||
result->file = result; // @warning: self referential
|
||||
result->all_loaded_files = {pctx->heap};
|
||||
result->implicit_imports = {pctx->heap};
|
||||
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);
|
||||
pctx->modules.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function void
|
||||
resolve_everything_in_module(Ast_Module *module){
|
||||
if(module->state == MODULE_RESOLVED) return;
|
||||
resolving_time_begin = os_time();
|
||||
for(S64 i = 0; i < module->all_loaded_files.len; i++){
|
||||
Ast_File *file = module->all_loaded_files[i];
|
||||
For(file->decls){
|
||||
resolve_name(file, 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_to_c_code();
|
||||
|
||||
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 = pctx->ordered_decls.len;
|
||||
Ast_Decl *any_decl = search_for_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;
|
||||
|
||||
function void
|
||||
compile_file(String filename, U32 compile_flags = COMPILE_NULL){
|
||||
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(compile_flags & COMPILE_PRINT_STATS){
|
||||
printf("\ntotal = %f", os_time() - total_time);
|
||||
printf("\nclang = %f", end - begin);
|
||||
printf("\nparsing = %f", parsing_time_end - parsing_time_begin);
|
||||
printf("\nresolving = %f", resolving_time_end - resolving_time_begin);
|
||||
printf("\ngeneratin = %f", generating_time_end - generating_time_begin);
|
||||
}
|
||||
}
|
||||
@@ -213,6 +213,7 @@ struct Parse_Ctx:Lexer{
|
||||
|
||||
global B32 emit_line_directives;
|
||||
function void init_type();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructors
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -277,5 +278,4 @@ parse_init(Parse_Ctx *ctx, Allocator *perm_allocator, Allocator *heap_allocator)
|
||||
ctx->module_folders = {ctx->heap};
|
||||
String main_module = string_fmt(ctx->perm, "%Q/modules", ctx->exe_folder);
|
||||
ctx->module_folders.add(main_module);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#import "kernel32.kl"
|
||||
|
||||
|
||||
main :: (): int
|
||||
// Let's say we have a type
|
||||
some_type := int
|
||||
|
||||
// this function call allows us to get extensive type information
|
||||
// about this type. For example this information allows us to walk
|
||||
// the type tree, pretty print all values in that type, along with their sizes.
|
||||
// Other use cases allow us to do a type safe printf
|
||||
type_info: *Type_Info = get_type_info(some_type)
|
||||
|
||||
// It can be null, requiring the type information would be a bit unwise
|
||||
// this is a lot of data
|
||||
if !type_info
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
_gcvt :: #foreign (value: F64, digits: int, buffer: *char): *char
|
||||
print_float :: (value: F64)
|
||||
buff: [100]char
|
||||
_gcvt(value, 10, &buff[0])
|
||||
OutputDebugStringA(&buff[0])
|
||||
|
||||
print_type :: (t: Type)
|
||||
type_info := get_type_info(t)
|
||||
if !type_info
|
||||
return
|
||||
|
||||
switch type_info.kind
|
||||
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
|
||||
OutputDebugStringA("Integer")
|
||||
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
|
||||
OutputDebugStringA("Unsigned")
|
||||
Type_Info_Kind.F64, Type_Info_Kind.F32
|
||||
OutputDebugStringA("Float")
|
||||
Type_Info_Kind.POINTER
|
||||
OutputDebugStringA("*")
|
||||
print_type(type_info.base_type)
|
||||
default;; OutputDebugStringA("Unknown")
|
||||
|
||||
print :: (a: Any)
|
||||
type_info := get_type_info(a.type)
|
||||
if !type_info
|
||||
return
|
||||
|
||||
print_type(a.type)
|
||||
OutputDebugStringA(" - ")
|
||||
// @todo check for types here
|
||||
switch type_info.kind
|
||||
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
|
||||
OutputDebugStringA("Integer")
|
||||
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
|
||||
OutputDebugStringA("Unsigned")
|
||||
Type_Info_Kind.F64
|
||||
data := a.data->*F64
|
||||
print_float(*data)
|
||||
Type_Info_Kind.POINTER
|
||||
OutputDebugStringA("Pointer")
|
||||
default;; OutputDebugStringA("Unknown")
|
||||
|
||||
|
||||
little_untyped_test :: ()
|
||||
if true == false;; pass
|
||||
if true;; pass
|
||||
cast_value1 := 32->S64
|
||||
cast_value2 := true->Bool
|
||||
value3 := !true
|
||||
value4 := !325252
|
||||
value5 := !42.42
|
||||
some_constant :: 10
|
||||
value6 := !some_constant
|
||||
var_not_const := 0
|
||||
value7 := some_constant + - -some_constant + +-32 + -var_not_const
|
||||
|
||||
|
||||
value3 = value3 + value4 + value5 + cast_value2 + value6
|
||||
cast_value1 += 1 + value7
|
||||
|
||||
|
||||
// switch 4
|
||||
// 4;; OutputDebugStringA("4")
|
||||
// 3;; OutputDebugStringA("3")
|
||||
|
||||
// some_type: Type = Vec2
|
||||
// char_info := get_type_info(char)
|
||||
// val := 4232.23
|
||||
// thing: Any = val
|
||||
// print(val)
|
||||
// print(some_type)
|
||||
// // print_array({125.23, 32})
|
||||
|
||||
// assert(char_info.kind == Type_Info_Kind.CHAR)
|
||||
|
||||
|
||||
43
examples/types_as_first_class_values.kl
Normal file
43
examples/types_as_first_class_values.kl
Normal file
@@ -0,0 +1,43 @@
|
||||
main :: (): int
|
||||
// Types can be evaluated at compile time for equality
|
||||
#assert(int == int)
|
||||
#assert(int != char)
|
||||
#assert(*char == *char)
|
||||
|
||||
// They can also be evaluated at runtime, they basically get
|
||||
// replaced with type ids, which are just unique integers assigned
|
||||
// to each type
|
||||
assert(int == int)
|
||||
assert(int != char)
|
||||
assert(*char == *char)
|
||||
|
||||
// We can assign types to compile time variable constants
|
||||
New_Type :: int
|
||||
|
||||
// This is a loose association
|
||||
thing: int = 10
|
||||
new_type_thing: New_Type = thing
|
||||
|
||||
|
||||
// to force typechecker to treat
|
||||
// both of these types as different we need to add a #strict directive
|
||||
Strict_Type :: #strict int
|
||||
// new_strict_type_thing: Strict_Type = thing // This produces a compile time type error
|
||||
// But this works
|
||||
strict_thing: Strict_Type = 10
|
||||
#assert(New_Type != Strict_Type)
|
||||
#assert(New_Type == int)
|
||||
|
||||
// We can also assign types to runtime variables, there is a special type for that
|
||||
some_type: Type = int
|
||||
some_type_implicit := char
|
||||
|
||||
// These can be checked for equality using ifs and switches
|
||||
if some_type == char
|
||||
pass
|
||||
|
||||
elif some_type_implicit == char
|
||||
pass
|
||||
|
||||
|
||||
|
||||
44
main.cpp
44
main.cpp
@@ -184,6 +184,7 @@ For modules it's a bit different cause they should be distributed as valid.
|
||||
#include "parsing.cpp"
|
||||
#include "typechecking.h"
|
||||
#include "typechecking.cpp"
|
||||
#include "compiler.cpp"
|
||||
|
||||
#include "c_language_codegen.cpp"
|
||||
#include "intermediate_representation.cpp"
|
||||
@@ -222,50 +223,11 @@ int main(int argument_count, char **arguments){
|
||||
test_bucket_arrays();
|
||||
|
||||
emit_line_directives = true;
|
||||
String program_name = "programs/main.kl"_s;
|
||||
String program_name = "examples/types_as_first_class_values.kl"_s;
|
||||
if(argument_count > 1){
|
||||
program_name = string_from_cstring(arguments[1]);
|
||||
}
|
||||
|
||||
F64 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 = pctx->ordered_decls.len;
|
||||
Ast_Decl *any_decl = search_for_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(program_name), true);
|
||||
parse_all_modules();
|
||||
assert(module);
|
||||
resolve_everything_in_module(module);
|
||||
|
||||
|
||||
arena_clear(&pctx->stage_arena);
|
||||
String result = get_compilation_result();
|
||||
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);
|
||||
printf("\nclang = %f", os_time() - begin);
|
||||
}
|
||||
|
||||
printf("\ntotal = %f", os_time() - total_time);
|
||||
printf("\nparsing = %f", parsing_time_end - parsing_time_begin);
|
||||
printf("\nresolving = %f", resolving_time_end - resolving_time_begin);
|
||||
printf("\ngeneratin = %f", generating_time_end - generating_time_begin);
|
||||
compile_file(program_name);
|
||||
__debugbreak();
|
||||
}
|
||||
|
||||
@@ -721,7 +721,7 @@ register_ast_file(Token *pos, String absolute_file_path, Ast_Module *module, B32
|
||||
For(pctx->files){
|
||||
if(string_compare(it->absolute_file_path, absolute_file_path)){
|
||||
if(module == it->module){
|
||||
log_info("%Q :: Returning registered file: %Q\n", module->absolute_file_path, absolute_file_path);
|
||||
// log_info("%Q :: Returning registered file: %Q\n", module->absolute_file_path, absolute_file_path);
|
||||
file = it;
|
||||
break;
|
||||
}
|
||||
@@ -732,7 +732,7 @@ register_ast_file(Token *pos, String absolute_file_path, Ast_Module *module, B32
|
||||
}
|
||||
|
||||
if(!file){
|
||||
log_info("%Q :: Registering file: %Q\n", module->absolute_file_path, absolute_file_path);
|
||||
// log_info("%Q :: Registering file: %Q\n", module->absolute_file_path, absolute_file_path);
|
||||
AST_NEW(File, FILE, 0, 0);
|
||||
file = result;
|
||||
file->absolute_file_path = absolute_file_path;
|
||||
|
||||
@@ -41,93 +41,9 @@ create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
|
||||
result.hdc = CreateCompatibleDC(hdc)
|
||||
return result
|
||||
|
||||
_gcvt :: #foreign (value: F64, digits: int, buffer: *char): *char
|
||||
print_float :: (value: F64)
|
||||
buff: [100]char
|
||||
_gcvt(value, 10, &buff[0])
|
||||
OutputDebugStringA(&buff[0])
|
||||
|
||||
print_type :: (t: Type)
|
||||
type_info := get_type_info(t)
|
||||
if !type_info
|
||||
return
|
||||
|
||||
switch type_info.kind
|
||||
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
|
||||
OutputDebugStringA("Integer")
|
||||
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
|
||||
OutputDebugStringA("Unsigned")
|
||||
Type_Info_Kind.F64, Type_Info_Kind.F32
|
||||
OutputDebugStringA("Float")
|
||||
Type_Info_Kind.POINTER
|
||||
OutputDebugStringA("*")
|
||||
print_type(type_info.base_type)
|
||||
default;; OutputDebugStringA("Unknown")
|
||||
|
||||
print :: (a: Any)
|
||||
type_info := get_type_info(a.type)
|
||||
if !type_info
|
||||
return
|
||||
|
||||
print_type(a.type)
|
||||
OutputDebugStringA(" - ")
|
||||
// @todo check for types here
|
||||
switch type_info.kind
|
||||
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
|
||||
OutputDebugStringA("Integer")
|
||||
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
|
||||
OutputDebugStringA("Unsigned")
|
||||
Type_Info_Kind.F64
|
||||
data := a.data->*F64
|
||||
print_float(*data)
|
||||
Type_Info_Kind.POINTER
|
||||
OutputDebugStringA("Pointer")
|
||||
default;; OutputDebugStringA("Unknown")
|
||||
|
||||
// print_array :: (a: []Any)
|
||||
// for i := 0, i < length_of(a), i+=1
|
||||
// print(a[i])
|
||||
|
||||
|
||||
little_untyped_test :: ()
|
||||
if true == false;; pass
|
||||
if true;; pass
|
||||
cast_value1 := 32->S64
|
||||
cast_value2 := true->Bool
|
||||
value3 := !true
|
||||
value4 := !325252
|
||||
value5 := !42.42
|
||||
some_constant :: 10
|
||||
value6 := !some_constant
|
||||
var_not_const := 0
|
||||
value7 := some_constant + - -some_constant + +-32 + -var_not_const
|
||||
|
||||
|
||||
value3 = value3 + value4 + value5 + cast_value2 + value6
|
||||
cast_value1 += 1 + value7
|
||||
|
||||
|
||||
switch 4
|
||||
4;; OutputDebugStringA("4")
|
||||
3;; OutputDebugStringA("3")
|
||||
|
||||
some_type: Type = Vec2
|
||||
char_info := get_type_info(char)
|
||||
val := 4232.23
|
||||
thing: Any = val
|
||||
print(val)
|
||||
print(some_type)
|
||||
// print_array({125.23, 32})
|
||||
|
||||
assert(char_info.kind == Type_Info_Kind.CHAR)
|
||||
#assert(int == int)
|
||||
#assert(int != char)
|
||||
#assert(*char == *char)
|
||||
|
||||
|
||||
app_is_running := true
|
||||
window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
|
||||
little_untyped_test()
|
||||
if msg == WM_DESTROY
|
||||
PostQuitMessage(0)
|
||||
app_is_running = false
|
||||
@@ -140,7 +56,6 @@ WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nS
|
||||
|
||||
arena: Arena
|
||||
|
||||
data: *int = arena_push_type(&arena, int)
|
||||
window_name := string_to_string16(&arena, "Have a wonderful day! 豈 更 車 賈 滑 串 句 龜 ")
|
||||
w := WNDCLASSW{
|
||||
lpfnWndProc = window_procedure,
|
||||
|
||||
@@ -125,8 +125,10 @@ type_new(Allocator *allocator, Ast_Type_Kind kind, SizeU size, SizeU align){
|
||||
|
||||
function Ast_Type *
|
||||
type_copy(Allocator *a, Ast_Type *type){
|
||||
// @warning: This changes type id !!!!
|
||||
Ast_Type *result = exp_alloc_type(a, Ast_Type);
|
||||
memory_copy(result, type, sizeof(Ast_Type));
|
||||
result->type_id = pctx->type_ids++;
|
||||
pctx->all_types.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user