Restructuring

This commit is contained in:
Krzosa Karol
2022-09-29 12:41:04 +02:00
parent 5f11a11f0f
commit cbf6ca8480
5 changed files with 379 additions and 365 deletions

View File

@@ -6,6 +6,72 @@ global F64 total_time;
global F64 init_ctx_time_begin;
global F64 init_ctx_time_end;
//-----------------------------------------------------------------------------
// Constructors
//-----------------------------------------------------------------------------
function void
lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
l->arena = token_string_arena;
l->tokens = array_make<Token>(token_string_arena, 1024*2);
l->interns= intern_table_make(token_string_arena, map_allocator, 1024);
keyword_struct= l->intern("struct"_s);
keyword_union = l->intern("union"_s);
keyword_true = l->intern("true"_s);
keyword_default = l->intern("default"_s);
keyword_break = l->intern("break"_s);
keyword_false = l->intern("false"_s);
keyword_return = l->intern("return"_s);
keyword_switch = l->intern("switch"_s);
keyword_assert = l->intern("Assert"_s);
keyword_if = l->intern("if"_s);
keyword_elif = l->intern("elif"_s);
keyword_pass = l->intern("pass"_s);
keyword_else = l->intern("else"_s);
keyword_for = l->intern("for"_s);
keyword_enum = intern_string(&l->interns, "enum"_s);
l->interns.first_keyword = keyword_struct.str;
l->interns.last_keyword = keyword_enum.str;
intern_sizeof = l->intern("SizeOf"_s);
intern_lengthof = l->intern("Length"_s);
intern_alignof = l->intern("AlignOf"_s);
intern_foreign = intern_string(&l->interns, "foreign"_s);
intern_strict = intern_string(&l->interns, "strict"_s);
intern_void = intern_string(&l->interns, "void"_s);
intern_flag = intern_string(&l->interns, "flag"_s);
intern_it = intern_string(&l->interns, "it"_s);
}
function void
parse_init(Parse_Ctx *ctx, Allocator *perm_allocator, Allocator *heap_allocator){
pctx = ctx;
ctx->perm = perm_allocator;
ctx->heap = heap_allocator;
ctx->gen = {ctx->heap};
ctx->ordered_decls = {ctx->heap};
ctx->type_map = {ctx->heap};
ctx->modules = {ctx->heap};
ctx->all_types = {ctx->heap};
ctx->helper_builder= {ctx->heap};
ctx->files = {ctx->heap};
ctx->scope_ids = 1;
bigint_allocator = ctx->perm;
arena_init(&ctx->stage_arena, "Compiler stage arena"_s);
lex_init(ctx->perm, ctx->heap, ctx);
init_type();
// Init paths
ctx->exe_folder = os_get_exe_dir(ctx->perm);
ctx->working_folder = os_get_working_dir(ctx->perm);
ctx->module_folders = {ctx->heap};
String main_module = string_fmt(ctx->perm, "%Q/modules", ctx->exe_folder);
ctx->module_folders.add(main_module);
}
function void
begin_compilation(){
init_ctx_time_begin = os_time();
@@ -155,8 +221,6 @@ resolve_everything_in_module(Ast_Module *module){
resolving_time_end = os_time();
}
function String compile_to_c_code();
function String
compile_file_to_string(String filename){
total_time = os_time();

View File

@@ -212,72 +212,9 @@ struct Parse_Ctx:Lexer{
String_Builder gen;
String_Builder helper_builder;
};
thread_local Parse_Ctx *pctx;
global B32 emit_line_directives;
function void init_type();
//-----------------------------------------------------------------------------
// Constructors
//-----------------------------------------------------------------------------
thread_local Parse_Ctx *pctx;
function void
lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
l->arena = token_string_arena;
l->tokens = array_make<Token>(token_string_arena, 1024*2);
l->interns= intern_table_make(token_string_arena, map_allocator, 1024);
keyword_struct= l->intern("struct"_s);
keyword_union = l->intern("union"_s);
keyword_true = l->intern("true"_s);
keyword_default = l->intern("default"_s);
keyword_break = l->intern("break"_s);
keyword_false = l->intern("false"_s);
keyword_return = l->intern("return"_s);
keyword_switch = l->intern("switch"_s);
keyword_assert = l->intern("Assert"_s);
keyword_if = l->intern("if"_s);
keyword_elif = l->intern("elif"_s);
keyword_pass = l->intern("pass"_s);
keyword_else = l->intern("else"_s);
keyword_for = l->intern("for"_s);
keyword_enum = intern_string(&l->interns, "enum"_s);
l->interns.first_keyword = keyword_struct.str;
l->interns.last_keyword = keyword_enum.str;
intern_sizeof = l->intern("SizeOf"_s);
intern_lengthof = l->intern("Length"_s);
intern_alignof = l->intern("AlignOf"_s);
intern_foreign = intern_string(&l->interns, "foreign"_s);
intern_strict = intern_string(&l->interns, "strict"_s);
intern_void = intern_string(&l->interns, "void"_s);
intern_flag = intern_string(&l->interns, "flag"_s);
intern_it = intern_string(&l->interns, "it"_s);
}
function void
parse_init(Parse_Ctx *ctx, Allocator *perm_allocator, Allocator *heap_allocator){
pctx = ctx;
ctx->perm = perm_allocator;
ctx->heap = heap_allocator;
ctx->gen = {ctx->heap};
ctx->ordered_decls = {ctx->heap};
ctx->type_map = {ctx->heap};
ctx->modules = {ctx->heap};
ctx->all_types = {ctx->heap};
ctx->helper_builder= {ctx->heap};
ctx->files = {ctx->heap};
ctx->scope_ids = 1;
bigint_allocator = ctx->perm;
arena_init(&ctx->stage_arena, "Compiler stage arena"_s);
lex_init(ctx->perm, ctx->heap, ctx);
init_type();
// Init paths
ctx->exe_folder = os_get_exe_dir(ctx->perm);
ctx->working_folder = os_get_working_dir(ctx->perm);
ctx->module_folders = {ctx->heap};
String main_module = string_fmt(ctx->perm, "%Q/modules", ctx->exe_folder);
ctx->module_folders.add(main_module);
}
function void lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l);
function String compile_to_c_code();

View File

@@ -42,6 +42,19 @@ Maybe later
-------------------------------------------------------------------------------
2022.09.29 - Function overloads, operator overloads, namespaces idea
I thought about adding function overloading but I'm not sure if that's
actually good. It seems pretty hard to implement and there are many problems
with it. It's probably better to implement descent namespacing mechanism.
Currently I'm thinking of something like this: operator overloads are this special
additional thing. They can be overloaded cause they are handled differently.
You are not looking up names, you are looking into an array of operators
during resolution of binary expressions etc. It shouldn't complicate things, hopefully.
-------------------------------------------------------------------------------
2022.05.28 - On lambda expressions
I think it's not wise to add the multiline lambda expressions
As is the case with python it would require new alternative syntax.

View File

@@ -1,6 +1,297 @@
#define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast;
#define BREAK() } break
function String gen_string_simple_decl(Allocator *a, Ast_Type *ast, String name = {}, Ast_Scope *scope = 0, bool scope_names = true);
function Resolve_Flag
inherit_flag(Resolve_Flag flag, B32 ast_can_be_null){
unset_flag(flag, AST_CAN_BE_NULL);
set_flag(flag, ast_can_be_null);
return flag;
}
//-----------------------------------------------------------------------------
// Operands
//-----------------------------------------------------------------------------
function Operand
operand(Ast_Decl *decl){
Operand result = {};
result.type = decl->type;
result.is_const = decl->kind != AST_VAR ? true : false;
result.is_lvalue= decl->kind == AST_CONST ? false : true; // Cant assign to const values
result.value = decl->value;
result.resolved_decl = decl;
if(decl->kind == AST_LAMBDA){
result.is_const = false;
}
return result;
}
function Operand
operand_type(Ast_Type *type){
Operand result = {};
result.type = type_type;
result.is_const = true;
result.is_lvalue = false;
result.type_val = type;
return result;
}
function Operand
operand_int(BigInt big_int){
Operand result = {};
result.type = untyped_int;
result.big_int_val = bigint_copy(pctx->perm, &big_int);
result.is_const = true;
result.is_lvalue = false;
return result;
}
function Operand
operand_str(Intern_String intern_val){
Operand result = {};
result.type = type_string;
result.intern_val = intern_val;
result.is_const = true;
result.is_lvalue = false;
return result;
}
function Operand
operand_lambda(Ast_Type *type){
Operand result = {};
result.type = type;
result.is_const = true;
result.is_lvalue = false;
return result;
}
function Operand
operand_const_rvalue(Value value){
Operand result = {};
result.is_const = true;
result.value = value;
return result;
}
function Operand
operand_lvalue(Ast_Type *type){
Operand result = {};
result.type = type;
result.is_const = false;
result.is_lvalue = true;
return result;
}
function Operand
operand_rvalue(Ast_Type *type){
Operand result = {};
result.type = type;
result.is_const = false;
result.is_lvalue = false;
return result;
}
//-----------------------------------------------------------------------------
// Hash consed types
//-----------------------------------------------------------------------------
function Ast_Type *
type_new(Allocator *allocator, Ast_Type_Kind kind, SizeU size, SizeU align){
Ast_Type *result = exp_alloc_type(allocator, Ast_Type, AF_ZeroMemory);
result->kind = kind;
result->size = size;
result->align = align;
result->type_id = pctx->type_ids++;
pctx->all_types.add(result);
return result;
}
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;
}
function Ast_Type *
type_pointer(Ast_Type *base){
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, (void *)base);
if(!result){
result = type_new(pctx->perm, TYPE_POINTER, pointer_size, pointer_align);
result->base = base;
result->is_unsigned = true;
map_insert(&pctx->type_map, base, result);
}
assert(result->kind == TYPE_POINTER);
return result;
}
function Ast_Type *
type_slice(Ast_Type *base, Ast *ast){
U64 hash_base = hash_ptr(base);
U64 hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_SLICE);
assert(result->arr.base == base);
return result;
}
struct Slice{void *p; S64 len;};
result = type_new(pctx->perm, TYPE_SLICE, sizeof(Slice), alignof(Slice));
result->arr.base = base;
result->arr.slice_hash = hash;
result->ast = ast;
map_insert(&pctx->type_map, hash, result);
return result;
}
function Ast_Type *
type_try_tupling(Array<Ast_Type *> types, Ast *ast){
if(types.len == 0) return type_void;
if(types.len == 1) return types[0];
U64 hash = 13;
For(types) hash = hash_mix(hash, hash_ptr(it));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_TUPLE);
assert(result->agg.members.len == types.len);
assert(result->agg.members.len > 1);
return result;
}
// @todo alignment, offsets
result = type_new(pctx->perm, TYPE_TUPLE, 0, pointer_align);
result->agg.members = array_make<Ast_Resolved_Member>(pctx->perm, types.len);
For(types){
Ast_Resolved_Member m = {};
m.type = it;
m.offset = 0; // @todo
result->size += it->size;
result->agg.members.add(m);
}
map_insert(&pctx->type_map, hash, result);
assert(result->agg.members.len > 1);
return result;
}
function Ast_Type *
type_array(Ast_Type *base, S64 size){
U64 hash_base = hash_ptr(base);
U64 hash = hash_mix(hash_base, hash_u64(size));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_ARRAY);
assert(result->arr.size == size);
assert(result->arr.base == base);
return result;
}
result = type_new(pctx->perm, TYPE_ARRAY, size*base->size, pointer_align);
result->arr.base = base;
result->arr.size = size;
result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
map_insert(&pctx->type_map, hash, result);
return result;
}
function Ast_Type *
type_lambda(Ast *ast, Array<Ast_Type *> return_vals, Array<Ast_Type *> args){
Ast_Type *ret = type_try_tupling(return_vals, ast);
U64 hash_without_ret = 13; // @function_overloading scrap this if we changed course
For(args) hash_without_ret = hash_mix(hash_without_ret, hash_ptr(it));
U64 hash = hash_mix(hash_ptr(ret), hash_without_ret);
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_LAMBDA);
assert(result->func.args.len == args.len);
return result;
}
result = type_new(pctx->perm, TYPE_LAMBDA, pointer_size, pointer_align);
result->ast = ast;
result->func.ret = ret;
result->func.args = args.tight_copy(pctx->perm);
result->func.hash_without_ret = hash_without_ret; // @function_overloading scrap this if we changed course
map_insert(&pctx->type_map, hash, result);
return result;
}
function Ast_Type *
type_enum(Ast_Decl *ast, Ast_Type *type){
if(!type){
type = type_s64;
}
Ast_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align);
result->base = type;
result->ast = ast;
return result;
}
function Ast_Type *
type_incomplete(Ast *ast){
Ast_Type *result = type_new(pctx->perm, TYPE_INCOMPLETE, 0, 0);
result->ast = ast;
return result;
}
function void type_complete(Ast_Type *type);
function void
type_struct_complete(Ast_Type *type, Ast_Decl *node){
assert(node->kind == AST_STRUCT);
// @todo: compute size, alignement, offset !!!
// @note: resolve all the struct members first
Scratch scratch;
Array<Ast_Resolved_Member> members = {scratch};
type->kind = TYPE_COMPLETING;
size_t members_size = 0;
For(node->scope->decls){
resolve_decl(it);
assert(it->type->kind != TYPE_INCOMPLETE);
assert(is_pow2(it->type->align));
Ast_Resolved_Member m = {};
m.offset = type->size;
members_size += it->type->size;
type->align = max(type->align, it->type->align);
type->size = it->type->size + align_up(type->size, it->type->align);
m.name = it->name;
m.value = it->value;
members.add(m);
}
type->size = align_up(type->size, type->align);
type->padding = type->size - members_size;
type->agg.members = members.tight_copy(pctx->perm);
type->kind = TYPE_STRUCT;
}
function void
type_complete(Ast_Type *type){
if(!type) {
return;
}
if(type->kind == TYPE_COMPLETING){
compiler_error(type->ast->pos, "Cyclic type dependency");
}
else if(type->kind != TYPE_INCOMPLETE){
return;
}
type_struct_complete(type, (Ast_Decl *)type->ast);
pctx->ordered_decls.add((Ast_Decl *)type->ast);
}
function void
init_type(){
type_pointer_to_char = type_pointer(type_char);
type_pointer_to_void = type_pointer(type_void);
}
function void
typename_base(String_Builder *sb, Ast_Type *type){

View File

@@ -23,297 +23,6 @@ enum{
function Operand resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context = 0);
function void resolve_decl(Ast_Decl *ast);
function Ast_Decl *resolve_name(Ast_Scope *parent_scope, Token *pos, Intern_String name, Search_Flag search_flags = 0);
function Resolve_Flag
inherit_flag(Resolve_Flag flag, B32 ast_can_be_null){
unset_flag(flag, AST_CAN_BE_NULL);
set_flag(flag, ast_can_be_null);
return flag;
}
//-----------------------------------------------------------------------------
// Operands
//-----------------------------------------------------------------------------
function Operand
operand(Ast_Decl *decl){
Operand result = {};
result.type = decl->type;
result.is_const = decl->kind != AST_VAR ? true : false;
result.is_lvalue= decl->kind == AST_CONST ? false : true; // Cant assign to const values
result.value = decl->value;
result.resolved_decl = decl;
if(decl->kind == AST_LAMBDA){
result.is_const = false;
}
return result;
}
function Operand
operand_type(Ast_Type *type){
Operand result = {};
result.type = type_type;
result.is_const = true;
result.is_lvalue = false;
result.type_val = type;
return result;
}
function Operand
operand_int(BigInt big_int){
Operand result = {};
result.type = untyped_int;
result.big_int_val = bigint_copy(pctx->perm, &big_int);
result.is_const = true;
result.is_lvalue = false;
return result;
}
function Operand
operand_str(Intern_String intern_val){
Operand result = {};
result.type = type_string;
result.intern_val = intern_val;
result.is_const = true;
result.is_lvalue = false;
return result;
}
function Operand
operand_lambda(Ast_Type *type){
Operand result = {};
result.type = type;
result.is_const = true;
result.is_lvalue = false;
return result;
}
function Operand
operand_const_rvalue(Value value){
Operand result = {};
result.is_const = true;
result.value = value;
return result;
}
function Operand
operand_lvalue(Ast_Type *type){
Operand result = {};
result.type = type;
result.is_const = false;
result.is_lvalue = true;
return result;
}
function Operand
operand_rvalue(Ast_Type *type){
Operand result = {};
result.type = type;
result.is_const = false;
result.is_lvalue = false;
return result;
}
//-----------------------------------------------------------------------------
// Hash consed types
//-----------------------------------------------------------------------------
function Ast_Type *
type_new(Allocator *allocator, Ast_Type_Kind kind, SizeU size, SizeU align){
Ast_Type *result = exp_alloc_type(allocator, Ast_Type, AF_ZeroMemory);
result->kind = kind;
result->size = size;
result->align = align;
result->type_id = pctx->type_ids++;
pctx->all_types.add(result);
return result;
}
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;
}
function Ast_Type *
type_pointer(Ast_Type *base){
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, (void *)base);
if(!result){
result = type_new(pctx->perm, TYPE_POINTER, pointer_size, pointer_align);
result->base = base;
result->is_unsigned = true;
map_insert(&pctx->type_map, base, result);
}
assert(result->kind == TYPE_POINTER);
return result;
}
function Ast_Type *
type_slice(Ast_Type *base, Ast *ast){
U64 hash_base = hash_ptr(base);
U64 hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_SLICE);
assert(result->arr.base == base);
return result;
}
struct Slice{void *p; S64 len;};
result = type_new(pctx->perm, TYPE_SLICE, sizeof(Slice), alignof(Slice));
result->arr.base = base;
result->arr.slice_hash = hash;
result->ast = ast;
map_insert(&pctx->type_map, hash, result);
return result;
}
function Ast_Type *
type_try_tupling(Array<Ast_Type *> types, Ast *ast){
if(types.len == 0) return type_void;
if(types.len == 1) return types[0];
U64 hash = 13;
For(types) hash = hash_mix(hash, hash_ptr(it));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_TUPLE);
assert(result->agg.members.len == types.len);
assert(result->agg.members.len > 1);
return result;
}
// @todo alignment, offsets
result = type_new(pctx->perm, TYPE_TUPLE, 0, pointer_align);
result->agg.members = array_make<Ast_Resolved_Member>(pctx->perm, types.len);
For(types){
Ast_Resolved_Member m = {};
m.type = it;
m.offset = 0; // @todo
result->size += it->size;
result->agg.members.add(m);
}
map_insert(&pctx->type_map, hash, result);
assert(result->agg.members.len > 1);
return result;
}
function Ast_Type *
type_array(Ast_Type *base, S64 size){
U64 hash_base = hash_ptr(base);
U64 hash = hash_mix(hash_base, hash_u64(size));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_ARRAY);
assert(result->arr.size == size);
assert(result->arr.base == base);
return result;
}
result = type_new(pctx->perm, TYPE_ARRAY, size*base->size, pointer_align);
result->arr.base = base;
result->arr.size = size;
result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
map_insert(&pctx->type_map, hash, result);
return result;
}
function Ast_Type *
type_lambda(Ast *ast, Array<Ast_Type *> return_vals, Array<Ast_Type *> args){
Ast_Type *ret = type_try_tupling(return_vals, ast);
U64 hash_without_ret = 13; // @function_overloading scrap this if we changed course
For(args) hash_without_ret = hash_mix(hash_without_ret, hash_ptr(it));
U64 hash = hash_mix(hash_ptr(ret), hash_without_ret);
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){
assert(result->kind == TYPE_LAMBDA);
assert(result->func.args.len == args.len);
return result;
}
result = type_new(pctx->perm, TYPE_LAMBDA, pointer_size, pointer_align);
result->ast = ast;
result->func.ret = ret;
result->func.args = args.tight_copy(pctx->perm);
result->func.hash_without_ret = hash_without_ret; // @function_overloading scrap this if we changed course
map_insert(&pctx->type_map, hash, result);
return result;
}
function Ast_Type *
type_enum(Ast_Decl *ast, Ast_Type *type){
if(!type){
type = type_s64;
}
Ast_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align);
result->base = type;
result->ast = ast;
return result;
}
function Ast_Type *
type_incomplete(Ast *ast){
Ast_Type *result = type_new(pctx->perm, TYPE_INCOMPLETE, 0, 0);
result->ast = ast;
return result;
}
function void type_complete(Ast_Type *type);
function void
type_struct_complete(Ast_Type *type, Ast_Decl *node){
assert(node->kind == AST_STRUCT);
// @todo: compute size, alignement, offset !!!
// @note: resolve all the struct members first
Scratch scratch;
Array<Ast_Resolved_Member> members = {scratch};
type->kind = TYPE_COMPLETING;
size_t members_size = 0;
For(node->scope->decls){
resolve_decl(it);
assert(it->type->kind != TYPE_INCOMPLETE);
assert(is_pow2(it->type->align));
Ast_Resolved_Member m = {};
m.offset = type->size;
members_size += it->type->size;
type->align = max(type->align, it->type->align);
type->size = it->type->size + align_up(type->size, it->type->align);
m.name = it->name;
m.value = it->value;
members.add(m);
}
type->size = align_up(type->size, type->align);
type->padding = type->size - members_size;
type->agg.members = members.tight_copy(pctx->perm);
type->kind = TYPE_STRUCT;
}
function void
type_complete(Ast_Type *type){
if(!type) {
return;
}
if(type->kind == TYPE_COMPLETING){
compiler_error(type->ast->pos, "Cyclic type dependency");
}
else if(type->kind != TYPE_INCOMPLETE){
return;
}
type_struct_complete(type, (Ast_Decl *)type->ast);
pctx->ordered_decls.add((Ast_Decl *)type->ast);
}
function void
init_type(){
type_pointer_to_char = type_pointer(type_char);
type_pointer_to_void = type_pointer(type_void);
}
function String gen_string_simple_decl(Allocator *a, Ast_Type *ast, String name = {}, Ast_Scope *scope = 0, bool scope_names = true);
#define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast;
#define BREAK() } break