Restructuring
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
@@ -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.
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user