Small changes fixing stuff
This commit is contained in:
4
base.cpp
4
base.cpp
@@ -62,12 +62,10 @@ typedef double F64;
|
|||||||
#define kib(x) ((x)*1024llu)
|
#define kib(x) ((x)*1024llu)
|
||||||
#define mib(x) (kib(x)*1024llu)
|
#define mib(x) (kib(x)*1024llu)
|
||||||
#define gib(x) (mib(x)*1024llu)
|
#define gib(x) (mib(x)*1024llu)
|
||||||
#define JOIN1(X,Y) X##Y // helper macro
|
#define JOIN1(X,Y) X##Y
|
||||||
#define JOIN(X,Y) JOIN1(X,Y)
|
#define JOIN(X,Y) JOIN1(X,Y)
|
||||||
#define string_expand(x) (int)x.len, x.str
|
#define string_expand(x) (int)x.len, x.str
|
||||||
|
|
||||||
#define FLAG32(x) typedef U32 x; enum
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
# define COMPILER_CLANG 1
|
# define COMPILER_CLANG 1
|
||||||
# if defined(_WIN32)
|
# if defined(_WIN32)
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ typedef U32 Ast_Call_Item_Flag;
|
|||||||
enum{
|
enum{
|
||||||
CALL_INDEX = bit_flag(1),
|
CALL_INDEX = bit_flag(1),
|
||||||
CALL_NAME = bit_flag(2),
|
CALL_NAME = bit_flag(2),
|
||||||
CALL_DOT_ANY = bit_flag(3),
|
|
||||||
CALL_INCLUDED= bit_flag(4),
|
CALL_INCLUDED= bit_flag(4),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ compile_file(String filename, U32 compile_flags = COMPILE_NULL){
|
|||||||
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
F64 begin = os_time();
|
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");
|
String compiler_call = string_fmt(scratch, "clang.exe program.c -Wall -Wno-unused-function -Wno-parentheses-equality -g -o a.exe -lgdi32 -luser32 -lwinmm");
|
||||||
system((const char *)compiler_call.str);
|
system((const char *)compiler_call.str);
|
||||||
F64 end = os_time();
|
F64 end = os_time();
|
||||||
|
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ For modules it's a bit different cause they should be distributed as valid.
|
|||||||
#include "core_ast.cpp"
|
#include "core_ast.cpp"
|
||||||
#include "core_parsing.cpp"
|
#include "core_parsing.cpp"
|
||||||
#include "core_typechecking.h"
|
#include "core_typechecking.h"
|
||||||
|
#include "core_types.cpp"
|
||||||
#include "core_typechecking.cpp"
|
#include "core_typechecking.cpp"
|
||||||
#include "core_compiler.cpp"
|
#include "core_compiler.cpp"
|
||||||
#include "core_codegen_c_language.cpp"
|
#include "core_codegen_c_language.cpp"
|
||||||
|
|||||||
@@ -1,59 +1,4 @@
|
|||||||
|
|
||||||
function const char *
|
|
||||||
get_name_of_type(Ast_Type *type){
|
|
||||||
switch(type->kind){
|
|
||||||
case TYPE_VOID: return "void";
|
|
||||||
case TYPE_BOOL: return "Bool";
|
|
||||||
case TYPE_STRING: return "String";
|
|
||||||
case TYPE_CHAR: return "char";
|
|
||||||
case TYPE_F32: return "F32";
|
|
||||||
case TYPE_F64: return "F64";
|
|
||||||
case TYPE_S8: return "S8";
|
|
||||||
case TYPE_INT: return "int";
|
|
||||||
case TYPE_S16: return "S16";
|
|
||||||
case TYPE_S32: return "S32";
|
|
||||||
case TYPE_S64: return "S64";
|
|
||||||
case TYPE_U8: return "U8";
|
|
||||||
case TYPE_U16: return "U16";
|
|
||||||
case TYPE_U32: return "U32";
|
|
||||||
case TYPE_U64: return "U64";
|
|
||||||
case TYPE_TUPLE: return "Tuple";
|
|
||||||
case TYPE_TYPE: return "Type";
|
|
||||||
invalid_default_case;
|
|
||||||
}
|
|
||||||
return "<unknown_type>";
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Type constructors and utillities
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
force_inline B32 is_any(Ast_Type *a){return a == type_any;}
|
|
||||||
force_inline B32 is_struct(Ast_Type *a){return a->kind == TYPE_STRUCT;}
|
|
||||||
force_inline B32 is_lambda(Ast_Type *a){return a->kind == TYPE_LAMBDA;}
|
|
||||||
force_inline B32 is_array(Ast_Type *a){return a->kind == TYPE_ARRAY;}
|
|
||||||
force_inline B32 is_slice(Ast_Type *a){return a->kind == TYPE_SLICE;}
|
|
||||||
force_inline B32 is_tuple(Ast_Type *a){return a->kind == TYPE_TUPLE;}
|
|
||||||
force_inline B32 is_enum(Ast_Type *a){return a->kind == TYPE_ENUM;}
|
|
||||||
force_inline B32 is_pointer(Ast_Type *a){return a->kind == TYPE_POINTER;}
|
|
||||||
force_inline B32 is_void(Ast_Type *a){return a->kind == TYPE_VOID;}
|
|
||||||
force_inline B32 is_void_pointer(Ast_Type *a){return a == type_pointer_to_void;}
|
|
||||||
force_inline B32 is_string(Ast_Type *a){return a->kind == TYPE_STRING || a->kind == TYPE_UNTYPED_STRING || a == type_pointer_to_char;}
|
|
||||||
force_inline B32 is_untyped_int(Ast_Type *a){return a->kind == TYPE_UNTYPED_INT;}
|
|
||||||
force_inline B32 is_typed_int(Ast_Type *a){return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8);}
|
|
||||||
force_inline B32 is_int(Ast_Type *a){return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8) || a->kind == TYPE_UNTYPED_INT;}
|
|
||||||
force_inline B32 is_signed_int(Ast_Type *a){return !a->is_unsigned;}
|
|
||||||
force_inline B32 is_unsigned_int(Ast_Type *a){return a->is_unsigned;}
|
|
||||||
force_inline B32 is_float(Ast_Type *a){return a->kind == TYPE_F32 || a->kind == TYPE_F64 || a->kind == TYPE_UNTYPED_FLOAT;}
|
|
||||||
force_inline B32 is_f32(Ast_Type *a){return a->kind == TYPE_F32;}
|
|
||||||
force_inline B32 is_f64(Ast_Type *a){return a->kind == TYPE_F64;}
|
|
||||||
force_inline B32 is_bool(Ast_Type *a){return a->kind == TYPE_BOOL || a->kind == TYPE_UNTYPED_BOOL;}
|
|
||||||
force_inline B32 is_untyped(Ast_Type *a){return a->kind >= TYPE_UNTYPED_FIRST && a->kind <= TYPE_UNTYPED_LAST;}
|
|
||||||
force_inline B32 is_typed(Ast_Type *a){return !is_untyped(a);}
|
|
||||||
force_inline B32 is_numeric(Ast_Type *type){
|
|
||||||
return (type->kind >= TYPE_UNTYPED_FIRST_NUMERIC && type->kind <= TYPE_UNTYPED_LAST_NUMERIC) ||
|
|
||||||
(type->kind >= TYPE_FIRST_NUMERIC && type->kind <= TYPE_LAST_NUMERIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Resolve_Flag
|
function Resolve_Flag
|
||||||
inherit_flag(Resolve_Flag flag, B32 ast_can_be_null){
|
inherit_flag(Resolve_Flag flag, B32 ast_can_be_null){
|
||||||
unset_flag(flag, AST_CAN_BE_NULL);
|
unset_flag(flag, AST_CAN_BE_NULL);
|
||||||
@@ -140,287 +85,6 @@ operand_rvalue(Ast_Type *type){
|
|||||||
return result;
|
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++;
|
|
||||||
add(pctx->perm, &pctx->all_types, 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++;
|
|
||||||
add(pctx->perm, &pctx->all_types, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline U64
|
|
||||||
calculate_hash_for_arguments(Ast_Type *a, Ast_Type *b){
|
|
||||||
U64 result = 13;
|
|
||||||
result = hash_mix(result, hash_ptr(a));
|
|
||||||
result = hash_mix(result, hash_ptr(b));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline U64
|
|
||||||
calculate_hash_for_arguments(Ast_Type *a){
|
|
||||||
U64 result = 13;
|
|
||||||
result = hash_mix(result, hash_ptr(a));
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
node->unique_name = pctx->intern(string_fmt(scratch, "%Q%Q", symbol_prefix, node->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
add(pctx->perm, &pctx->ordered_decls, (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){
|
|
||||||
switch(type->kind){
|
|
||||||
case TYPE_INCOMPLETE: sb->addf("INCOMPLETE"); break;
|
|
||||||
case TYPE_COMPLETING: sb->addf("COMPLETING"); break;
|
|
||||||
case TYPE_TYPE: sb->addf("TYPE"); break;
|
|
||||||
case TYPE_POINTER:
|
|
||||||
sb->addf("*");
|
|
||||||
typename_base(sb, type->base);
|
|
||||||
break;
|
|
||||||
case TYPE_LAMBDA:
|
|
||||||
sb->addf("(");
|
|
||||||
For(type->func.args) {
|
|
||||||
typename_base(sb, it);
|
|
||||||
if(!type->func.args.is_last(&it)) sb->addf(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb->addf("):");
|
|
||||||
typename_base(sb, type->func.ret);
|
|
||||||
break;
|
|
||||||
case TYPE_ARRAY:
|
|
||||||
sb->addf("[%d]", (int)type->arr.size);
|
|
||||||
typename_base(sb, type->arr.base);
|
|
||||||
break;
|
|
||||||
case TYPE_SLICE:
|
|
||||||
sb->addf("[]");
|
|
||||||
typename_base(sb, type->base);
|
|
||||||
break;
|
|
||||||
case TYPE_STRUCT:
|
|
||||||
case TYPE_ENUM:{
|
|
||||||
// @todo direct access
|
|
||||||
auto constant = (Ast_Decl *)type->ast;
|
|
||||||
auto name = constant->name;
|
|
||||||
sb->addf("%Q", name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TYPE_UNTYPED_BOOL: sb->addf("Untyped_Bool"); break;
|
|
||||||
case TYPE_UNTYPED_INT: sb->addf("Untyped_Int"); break;
|
|
||||||
case TYPE_UNTYPED_FLOAT: sb->addf("Untyped_Float"); break;
|
|
||||||
case TYPE_UNTYPED_STRING: sb->addf("Untyped_String"); break;
|
|
||||||
default: {
|
|
||||||
sb->addf("%s", get_name_of_type(type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function String
|
|
||||||
get_typename(Allocator *a, Ast_Type *type){
|
|
||||||
pctx->helper_builder.addf("[");
|
|
||||||
typename_base(&pctx->helper_builder, type);
|
|
||||||
pctx->helper_builder.addf("]");
|
|
||||||
String result = string_flatten(a, &pctx->helper_builder);
|
|
||||||
pctx->helper_builder.reset();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function String
|
|
||||||
typestring(Ast_Type *type){
|
|
||||||
return get_typename(&pctx->stage_arena, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
function void
|
||||||
check_value_bounds(Token *pos, Value *a){
|
check_value_bounds(Token *pos, Value *a){
|
||||||
if(!is_int(a->type)) return;
|
if(!is_int(a->type)) return;
|
||||||
|
|||||||
336
core_types.cpp
Normal file
336
core_types.cpp
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
|
||||||
|
function const char *
|
||||||
|
get_name_of_type(Ast_Type *type){
|
||||||
|
switch(type->kind){
|
||||||
|
case TYPE_VOID: return "void";
|
||||||
|
case TYPE_BOOL: return "Bool";
|
||||||
|
case TYPE_STRING: return "String";
|
||||||
|
case TYPE_CHAR: return "char";
|
||||||
|
case TYPE_F32: return "F32";
|
||||||
|
case TYPE_F64: return "F64";
|
||||||
|
case TYPE_S8: return "S8";
|
||||||
|
case TYPE_INT: return "int";
|
||||||
|
case TYPE_S16: return "S16";
|
||||||
|
case TYPE_S32: return "S32";
|
||||||
|
case TYPE_S64: return "S64";
|
||||||
|
case TYPE_U8: return "U8";
|
||||||
|
case TYPE_U16: return "U16";
|
||||||
|
case TYPE_U32: return "U32";
|
||||||
|
case TYPE_U64: return "U64";
|
||||||
|
case TYPE_TUPLE: return "Tuple";
|
||||||
|
case TYPE_TYPE: return "Type";
|
||||||
|
invalid_default_case;
|
||||||
|
}
|
||||||
|
return "<unknown_type>";
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Type constructors and utillities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
force_inline B32 is_any(Ast_Type *a){return a == type_any;}
|
||||||
|
force_inline B32 is_struct(Ast_Type *a){return a->kind == TYPE_STRUCT;}
|
||||||
|
force_inline B32 is_lambda(Ast_Type *a){return a->kind == TYPE_LAMBDA;}
|
||||||
|
force_inline B32 is_array(Ast_Type *a){return a->kind == TYPE_ARRAY;}
|
||||||
|
force_inline B32 is_slice(Ast_Type *a){return a->kind == TYPE_SLICE;}
|
||||||
|
force_inline B32 is_tuple(Ast_Type *a){return a->kind == TYPE_TUPLE;}
|
||||||
|
force_inline B32 is_enum(Ast_Type *a){return a->kind == TYPE_ENUM;}
|
||||||
|
force_inline B32 is_pointer(Ast_Type *a){return a->kind == TYPE_POINTER;}
|
||||||
|
force_inline B32 is_void(Ast_Type *a){return a->kind == TYPE_VOID;}
|
||||||
|
force_inline B32 is_void_pointer(Ast_Type *a){return a == type_pointer_to_void;}
|
||||||
|
force_inline B32 is_string(Ast_Type *a){return a->kind == TYPE_STRING || a->kind == TYPE_UNTYPED_STRING || a == type_pointer_to_char;}
|
||||||
|
force_inline B32 is_untyped_int(Ast_Type *a){return a->kind == TYPE_UNTYPED_INT;}
|
||||||
|
force_inline B32 is_typed_int(Ast_Type *a){return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8);}
|
||||||
|
force_inline B32 is_int(Ast_Type *a){return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8) || a->kind == TYPE_UNTYPED_INT;}
|
||||||
|
force_inline B32 is_signed_int(Ast_Type *a){return !a->is_unsigned;}
|
||||||
|
force_inline B32 is_unsigned_int(Ast_Type *a){return a->is_unsigned;}
|
||||||
|
force_inline B32 is_float(Ast_Type *a){return a->kind == TYPE_F32 || a->kind == TYPE_F64 || a->kind == TYPE_UNTYPED_FLOAT;}
|
||||||
|
force_inline B32 is_f32(Ast_Type *a){return a->kind == TYPE_F32;}
|
||||||
|
force_inline B32 is_f64(Ast_Type *a){return a->kind == TYPE_F64;}
|
||||||
|
force_inline B32 is_bool(Ast_Type *a){return a->kind == TYPE_BOOL || a->kind == TYPE_UNTYPED_BOOL;}
|
||||||
|
force_inline B32 is_untyped(Ast_Type *a){return a->kind >= TYPE_UNTYPED_FIRST && a->kind <= TYPE_UNTYPED_LAST;}
|
||||||
|
force_inline B32 is_typed(Ast_Type *a){return !is_untyped(a);}
|
||||||
|
force_inline B32 is_numeric(Ast_Type *type){
|
||||||
|
return (type->kind >= TYPE_UNTYPED_FIRST_NUMERIC && type->kind <= TYPE_UNTYPED_LAST_NUMERIC) ||
|
||||||
|
(type->kind >= TYPE_FIRST_NUMERIC && type->kind <= TYPE_LAST_NUMERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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++;
|
||||||
|
add(pctx->perm, &pctx->all_types, 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++;
|
||||||
|
add(pctx->perm, &pctx->all_types, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U64
|
||||||
|
calculate_hash_for_arguments(Ast_Type *a, Ast_Type *b){
|
||||||
|
U64 result = 13;
|
||||||
|
result = hash_mix(result, hash_ptr(a));
|
||||||
|
result = hash_mix(result, hash_ptr(b));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U64
|
||||||
|
calculate_hash_for_arguments(Ast_Type *a){
|
||||||
|
U64 result = 13;
|
||||||
|
result = hash_mix(result, hash_ptr(a));
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
node->unique_name = pctx->intern(string_fmt(scratch, "%Q%Q", symbol_prefix, node->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
add(pctx->perm, &pctx->ordered_decls, (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){
|
||||||
|
switch(type->kind){
|
||||||
|
case TYPE_INCOMPLETE: sb->addf("INCOMPLETE"); break;
|
||||||
|
case TYPE_COMPLETING: sb->addf("COMPLETING"); break;
|
||||||
|
case TYPE_TYPE: sb->addf("TYPE"); break;
|
||||||
|
case TYPE_POINTER:
|
||||||
|
sb->addf("*");
|
||||||
|
typename_base(sb, type->base);
|
||||||
|
break;
|
||||||
|
case TYPE_LAMBDA:
|
||||||
|
sb->addf("(");
|
||||||
|
For(type->func.args) {
|
||||||
|
typename_base(sb, it);
|
||||||
|
if(!type->func.args.is_last(&it)) sb->addf(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->addf("):");
|
||||||
|
typename_base(sb, type->func.ret);
|
||||||
|
break;
|
||||||
|
case TYPE_ARRAY:
|
||||||
|
sb->addf("[%d]", (int)type->arr.size);
|
||||||
|
typename_base(sb, type->arr.base);
|
||||||
|
break;
|
||||||
|
case TYPE_SLICE:
|
||||||
|
sb->addf("[]");
|
||||||
|
typename_base(sb, type->base);
|
||||||
|
break;
|
||||||
|
case TYPE_STRUCT:
|
||||||
|
case TYPE_ENUM:{
|
||||||
|
// @todo direct access
|
||||||
|
auto constant = (Ast_Decl *)type->ast;
|
||||||
|
auto name = constant->name;
|
||||||
|
sb->addf("%Q", name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_UNTYPED_BOOL: sb->addf("Untyped_Bool"); break;
|
||||||
|
case TYPE_UNTYPED_INT: sb->addf("Untyped_Int"); break;
|
||||||
|
case TYPE_UNTYPED_FLOAT: sb->addf("Untyped_Float"); break;
|
||||||
|
case TYPE_UNTYPED_STRING: sb->addf("Untyped_String"); break;
|
||||||
|
default: {
|
||||||
|
sb->addf("%s", get_name_of_type(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function String
|
||||||
|
get_typename(Allocator *a, Ast_Type *type){
|
||||||
|
pctx->helper_builder.addf("[");
|
||||||
|
typename_base(&pctx->helper_builder, type);
|
||||||
|
pctx->helper_builder.addf("]");
|
||||||
|
String result = string_flatten(a, &pctx->helper_builder);
|
||||||
|
pctx->helper_builder.reset();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function String
|
||||||
|
typestring(Ast_Type *type){
|
||||||
|
return get_typename(&pctx->stage_arena, type);
|
||||||
|
}
|
||||||
@@ -102,7 +102,7 @@ struct Ast_Type{
|
|||||||
struct{
|
struct{
|
||||||
Ast_Type * ret;
|
Ast_Type * ret;
|
||||||
Array<Ast_Type *> args;
|
Array<Ast_Type *> args;
|
||||||
U64 hash_without_ret; // @function_overloading scrap this if we changed course
|
U64 hash_without_ret;
|
||||||
}func;
|
}func;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nS
|
|||||||
|
|
||||||
for y := 0, y < Mu.window.y, y+=1
|
for y := 0, y < Mu.window.y, y+=1
|
||||||
for x := 0, x < Mu.window.x, x+=1
|
for x := 0, x < Mu.window.x, x+=1
|
||||||
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
|
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
|
||||||
|
|
||||||
|
return 0
|
||||||
Reference in New Issue
Block a user