From: Brendan Hansen Date: Sun, 10 Jan 2021 22:16:17 +0000 (-0600) Subject: code cleanup making new ast nodes X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=96187b11bc1fbaee7a5b699987e7104034eef4ef;p=onyx.git code cleanup making new ast nodes --- diff --git a/bin/onyx b/bin/onyx index 31d17195..23dd19cd 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/build.bat b/build.bat index 95974355..b41ee9b5 100644 --- a/build.bat +++ b/build.bat @@ -1,6 +1,6 @@ @echo off -set SOURCE_FILES=src/onyx.c src/onyxbuiltins.c src/onyxchecker.c src/onyxclone.c src/onyxdoc.c src/onyxentities.c src/onyxerrors.c src/onyxlex.c src/onyxparser.c src/onyxsempass.c src/onyxsymres.c src/onyxtypes.c src/onyxutils.c src/onyxwasm.c +set SOURCE_FILES=src/onyx.c src/onyxastnodes.c src/onyxbuiltins.c src/onyxchecker.c src/onyxclone.c src/onyxdoc.c src/onyxentities.c src/onyxerrors.c src/onyxlex.c src/onyxparser.c src/onyxsempass.c src/onyxsymres.c src/onyxtypes.c src/onyxutils.c src/onyxwasm.c if "%1" == "1" ( set FLAGS=/O2 /MT /Z7 diff --git a/build.sh b/build.sh index ffa05712..cdf69ed8 100644 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/sh -C_FILES="onyx onyxbuiltins onyxchecker onyxclone onyxdoc onyxentities onyxerrors onyxlex onyxparser onyxsempass onyxsymres onyxtypes onyxutils onyxwasm" +C_FILES="onyx onyxastnodes onyxbuiltins onyxchecker onyxclone onyxdoc onyxentities onyxerrors onyxlex onyxparser onyxsempass onyxsymres onyxtypes onyxutils onyxwasm" TARGET='./bin/onyx' CC='gcc' diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index b29e9a2a..113f9232 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -796,6 +796,8 @@ struct AstPackage { Package* package; }; +extern AstNode empty_node; + typedef enum EntityState { Entity_State_Error, @@ -953,13 +955,18 @@ void initialize_builtins(bh_allocator a, ProgramInfo* prog); AstTyped* ast_reduce(bh_allocator a, AstTyped* node); AstNode* ast_clone(bh_allocator a, void* n); void promote_numlit_to_larger(AstNumLit* num); -AstNumLit* make_int_literal(bh_allocator, i64 value); b32 convert_numlit_to_type(AstNumLit* num, Type* type); b32 type_check_or_auto_cast(AstTyped** pnode, Type* type); Type* resolve_expression_type(AstTyped* node); b32 cast_is_legal(Type* from_, Type* to_, char** err_msg); char* get_function_name(AstFunction* func); +AstNumLit* make_int_literal(bh_allocator a, i64 value); +AstNumLit* make_float_literal(bh_allocator a, f64 value); +AstBinaryOp* make_binary_op(bh_allocator a, BinaryOp operation, AstTyped* left, AstTyped* right); +AstArgument* make_argument(bh_allocator a, AstTyped* value); +AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field); + typedef enum PolyProcLookupMethod { PPLM_By_Call, PPLM_By_Function_Type, diff --git a/onyx.exe b/onyx.exe index b74bf61e..d9206455 100644 Binary files a/onyx.exe and b/onyx.exe differ diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c new file mode 100644 index 00000000..c90dc282 --- /dev/null +++ b/src/onyxastnodes.c @@ -0,0 +1,616 @@ +#include "onyxastnodes.h" +#include "onyxsempass.h" +#include "onyxparser.h" +#include "onyxutils.h" + +AstNode empty_node = { Ast_Kind_Error, 0, NULL, NULL }; + +static const char* ast_node_names[] = { + "ERROR", + "PROGRAM", + "PACKAGE", + "INCLUDE FILE", + "INCLUDE FOLDER", + "USE PACKAGE", + "ALIAS", + "MEMORY RESERVATION", + + "BINDING", + "FUNCTION", + "OVERLOADED_FUNCTION", + "POLYMORPHIC PROC", + "BLOCK", + "LOCAL GROUP", + "LOCAL", + "GLOBAL", + "SYMBOL", + + "UN_OP", + "BIN_OP", + + "TYPE_START (BAD)", + "TYPE", + "BASIC_TYPE", + "POINTER_TYPE", + "FUNCTION_TYPE", + "ARRAY TYPE", + "SLICE TYPE", + "DYNARR TYPE", + "VARARG TYPE", + "STRUCT TYPE", + "POLYMORPHIC STRUCT TYPE", + "POLYMORPHIC STRUCT CALL TYPE", + "ENUM TYPE", + "TYPE_ALIAS", + "TYPE RAW ALIAS", + "TYPE_END (BAD)", + + "STRUCT MEMBER", + "ENUM VALUE", + + "NUMERIC LITERAL", + "STRING LITERAL", + "PARAM", + "ARGUMENT", + "CALL", + "INTRINSIC CALL", + "RETURN", + "ADDRESS OF", + "DEREFERENCE", + "ARRAY_ACCESS", + "SLICE", + "FIELD_ACCESS", + "PIPE", + "RANGE", + "SIZE OF", + "ALIGN OF", + "FILE CONTENTS", + "STRUCT LITERAL", + "ARRAY LITERAL", + + "IF", + "FOR", + "WHILE", + "JUMP", + "USE", + "DEFER", + "SWITCH", + "SWITCH CASE", + + "AST_NODE_KIND_COUNT", +}; + +const char* onyx_ast_node_kind_string(AstKind kind) { + return ast_node_names[kind]; +} + +const char *binaryop_string[Binary_Op_Count] = { + "+", "-", "*", "/", "%", + "==", "!=", "<", "<=", ">", ">=", + "&", "|", "^", "<<", ">>", ">>>", + "&&", "||", + + "NONE", + "=", "+=", "-=", "*=", "/=", "%=", + "&=", "|=", "^=", "<<=", ">>=", ">>>=", + "NONE", + + "|>", "..", +}; + +const char* entity_state_strings[Entity_State_Count] = { + "Error", + "Parse Builtin", + "Parse", + "Resolve_Symbols", + "Check_Types", + "Code_Gen", + "Finalized", +}; + +const char* entity_type_strings[Entity_Type_Count] = { + "Unknown", + "Add to Load Path", + "Load File", + "Use Package", + "String Literal", + "File Contents", + "Enum", + "Type Alias", + "Memory Reservation Type", + "Use", + "Polymorphic Proc", + "Foreign_Function Header", + "Foreign_Global Header", + "Function Header", + "Global Header", + "Struct Member Default", + "Memory Reservation", + "Expression", + "Global", + "Overloaded_Function", + "Function", +}; + +#define REDUCE_BINOP_ALL(op) \ + if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \ + res->value.i = left->value.i op right->value.i; \ + } else if (type_is_integer(res->type) \ + || res->type->Basic.kind == Basic_Kind_Int_Unsized \ + || res->type->kind == Type_Kind_Enum) { \ + res->value.l = left->value.l op right->value.l; \ + } else if (res->type->Basic.kind == Basic_Kind_F32) { \ + res->value.f = left->value.f op right->value.f; \ + } else if (res->type->Basic.kind == Basic_Kind_F64 || res->type->Basic.kind == Basic_Kind_Float_Unsized) { \ + res->value.d = left->value.d op right->value.d; \ + } \ + break; + +#define REDUCE_BINOP_INT(op) \ + if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \ + res->value.i = left->value.i op right->value.i; \ + } else if (type_is_integer(res->type) \ + || res->type->Basic.kind == Basic_Kind_Int_Unsized \ + || res->type->kind == Type_Kind_Enum) { \ + res->value.l = left->value.l op right->value.l; \ + } \ + break; + +#define REDUCE_BINOP_BOOL(op) \ + if (type_is_bool(res->type)) { \ + res->value.i = left->value.i op right->value.i; \ + } \ + break; + +AstNumLit* ast_reduce_binop(bh_allocator a, AstBinaryOp* node) { + AstNumLit* left = (AstNumLit *) ast_reduce(a, node->left); + AstNumLit* right = (AstNumLit *) ast_reduce(a, node->right); + + if (left->kind != Ast_Kind_NumLit || right->kind != Ast_Kind_NumLit) { + node->left = (AstTyped *) left; + node->right = (AstTyped *) right; + return (AstNumLit *) node; + } + + AstNumLit* res = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); + res->token = node->token; + res->flags |= Ast_Flag_Comptime; + res->type_node = node->type_node; + res->type = node->type; + + switch (node->operation) { + case Binary_Op_Add: REDUCE_BINOP_ALL(+); + case Binary_Op_Minus: REDUCE_BINOP_ALL(-); + case Binary_Op_Multiply: REDUCE_BINOP_ALL(*); + case Binary_Op_Divide: REDUCE_BINOP_ALL(/); + case Binary_Op_Modulus: REDUCE_BINOP_INT(%); + + case Binary_Op_Equal: REDUCE_BINOP_ALL(==); + case Binary_Op_Not_Equal: REDUCE_BINOP_ALL(!=); + case Binary_Op_Less: REDUCE_BINOP_ALL(<); + case Binary_Op_Less_Equal: REDUCE_BINOP_ALL(<=); + case Binary_Op_Greater: REDUCE_BINOP_ALL(>); + case Binary_Op_Greater_Equal: REDUCE_BINOP_ALL(>=); + + case Binary_Op_And: REDUCE_BINOP_INT(&); + case Binary_Op_Or: REDUCE_BINOP_INT(|); + case Binary_Op_Xor: REDUCE_BINOP_INT(^); + case Binary_Op_Shl: REDUCE_BINOP_INT(<<); + case Binary_Op_Shr: REDUCE_BINOP_INT(>>); + case Binary_Op_Sar: REDUCE_BINOP_INT(>>); + + case Binary_Op_Bool_And: REDUCE_BINOP_BOOL(&&); + case Binary_Op_Bool_Or: REDUCE_BINOP_BOOL(||); + + default: break; + } + + return res; +} + +#define REDUCE_UNOP(op) \ + if (type_is_small_integer(unop->type) || type_is_bool(unop->type)) { \ + res->value.i = op ((AstNumLit *) unop->expr)->value.i; \ + } else if (type_is_integer(unop->type) || unop->type->Basic.kind == Basic_Kind_Int_Unsized) { \ + res->value.l = op ((AstNumLit *) unop->expr)->value.l; \ + } else if (unop->type->Basic.kind == Basic_Kind_F32) { \ + res->value.f = op ((AstNumLit *) unop->expr)->value.f; \ + } else if (unop->type->Basic.kind == Basic_Kind_F64 || unop->type->Basic.kind == Basic_Kind_Float_Unsized) { \ + res->value.d = op ((AstNumLit *) unop->expr)->value.d; \ + } \ + break; + +#define REDUCE_UNOP_INT(op) \ + if (type_is_small_integer(unop->type) || type_is_bool(unop->type)) { \ + res->value.i = op ((AstNumLit *) unop->expr)->value.i; \ + } else if (type_is_integer(unop->type)) { \ + res->value.l = op ((AstNumLit *) unop->expr)->value.l; \ + } + +AstTyped* ast_reduce_unaryop(bh_allocator a, AstUnaryOp* unop) { + unop->expr = ast_reduce(a, unop->expr); + + if (unop->expr->kind != Ast_Kind_NumLit) { + return (AstTyped *) unop; + } + + AstNumLit* res = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); + res->token = unop->token; + res->flags |= Ast_Flag_Comptime; + res->type_node = unop->type_node; + res->type = unop->type; + + switch (unop->operation) { + case Unary_Op_Negate: REDUCE_UNOP(-); + case Unary_Op_Not: { + if (type_is_bool(res->type)) res->value.i = ! ((AstNumLit *) unop->expr)->value.i; + break; + } + case Unary_Op_Bitwise_Not: REDUCE_UNOP_INT(~); + + default: return (AstTyped *) unop; + } + + return (AstTyped *) res; +} + +AstTyped* ast_reduce(bh_allocator a, AstTyped* node) { + assert(node->flags & Ast_Flag_Comptime); + + switch (node->kind) { + case Ast_Kind_Binary_Op: return (AstTyped *) ast_reduce_binop(a, (AstBinaryOp *) node); + case Ast_Kind_Unary_Op: return (AstTyped *) ast_reduce_unaryop(a, (AstUnaryOp *) node); + case Ast_Kind_NumLit: return node; + case Ast_Kind_Enum_Value: return (AstTyped *) ((AstEnumValue *) node)->value; + default: return NULL; + } +} + +void promote_numlit_to_larger(AstNumLit* num) { + assert(num->type != NULL); + + if (type_is_integer(num->type) && num->type->Basic.size <= 4) { + // NOTE: Int32, Int16, Int8 + i64 val = (i64) num->value.i; + num->value.l = val; + num->type = &basic_types[Basic_Kind_I64]; + } else if (num->type->Basic.size <= 4) { + // NOTE: Float32 + f64 val = (f64) num->value.f; + num->value.d = val; + num->type = &basic_types[Basic_Kind_F64]; + } +} + +// NOTE: Returns 1 if the conversion was successful. +b32 convert_numlit_to_type(AstNumLit* num, Type* type) { + if (num->type == NULL) + num->type = type_build_from_ast(semstate.allocator, num->type_node); + assert(num->type); + + if (types_are_compatible(num->type, type)) return 1; + if (!type_is_numeric(type)) return 0; + + if (num->type->Basic.kind == Basic_Kind_Int_Unsized) { + + // + // Integer literal auto cast rules: + // - Up in size always works + // - Down in size only works if value is in range of smaller type. + // - Cast to float only works if value is less than the maximum precise value for float size. + // + + if (type->Basic.flags & Basic_Flag_Integer) { + if (type->Basic.flags & Basic_Flag_Unsigned) { + u64 value = (u64) num->value.l; + if (type->Basic.size == 8) { + num->type = type; + return 1; + } + switch (type->Basic.size) { + case 1: if (value <= 255) { + num->type = type; + return 1; + } + case 2: if (value <= 65535) { + num->type = type; + return 1; + } + case 4: if (value <= 4294967295) { + num->type = type; + return 1; + } + } + + onyx_report_error(num->token->pos, "Unsigned integer constant with value '%l' does not fit into %d-bits.", + num->value.l, + type->Basic.size * 8); + + } else { + i64 value = (i64) num->value.l; + switch (type->Basic.size) { + case 1: if (-128ll <= value && value <= 127ll) { + num->value.i = (i32) value; + num->type = type; + return 1; + } break; + case 2: if (-32768ll <= value && value <= 32767ll) { + num->value.i = (i32) value; + num->type = type; + return 1; + } break; + case 4: if (-2147483648ll <= value && value <= 2147483647ll) { + num->value.i = (i32) value; + num->type = type; + return 1; + } break; + case 8: { num->type = type; + return 1; + } break; + } + + onyx_report_error(num->token->pos, "Integer constant with value '%l' does not fit into %d-bits.", + num->value.l, + type->Basic.size * 8); + } + } + + else if (type->Basic.flags & Basic_Flag_Float) { + if (type->Basic.size == 4) { + // TODO(Brendan): Check these boundary conditions + if (bh_abs(num->value.l) >= (1 << 23)) { + onyx_report_error(num->token->pos, "Integer '%l' does not fit in 32-bit float exactly.", num->value.l); + return 0; + } + + num->type = type; + num->value.f = (f32) num->value.l; + return 1; + } + if (type->Basic.size == 8) { + // TODO(Brendan): Check these boundary conditions + if (bh_abs(num->value.l) >= (1ull << 52)) { + onyx_report_error(num->token->pos, "Integer '%l' does not fit in 64-bit float exactly.", num->value.l); + return 0; + } + + num->type = type; + num->value.d = (f64) num->value.l; + return 1; + } + } + } + else if (num->type->Basic.kind == Basic_Kind_Float_Unsized) { + // NOTE: Floats don't cast to integers implicitly. + if ((type->Basic.flags & Basic_Flag_Float) == 0) return 0; + + if (type->Basic.kind == Basic_Kind_F32) { + num->value.f = (f32) num->value.d; + } + + num->type = type; + return 1; + } + else if (num->type->Basic.kind == Basic_Kind_F32) { + // NOTE: Floats don't cast to integers implicitly. + if ((type->Basic.flags & Basic_Flag_Float) == 0) return 0; + + if (type->Basic.kind == Basic_Kind_F64) { + num->value.d = (f64) num->value.f; + num->type = type; + return 1; + } + } + + return 0; +} + +// NOTE: Returns 0 if it was not possible to make the types compatible. +b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) { + AstTyped* node = *pnode; + assert(type != NULL); + assert(node != NULL); + + if (node->kind == Ast_Kind_Polymorphic_Proc) { + AstFunction* func = polymorphic_proc_lookup((AstPolyProc *) node, PPLM_By_Function_Type, type, node->token->pos); + if (func == NULL) return 0; + + *pnode = (AstTyped *) func; + node = *pnode; + } + + // HACK: NullProcHack + if (type->kind == Type_Kind_Function && (node->flags & Ast_Flag_Proc_Is_Null) != 0) return 1; + + if (types_are_compatible(node->type, type)) return 1; + if (node_is_auto_cast((AstNode *) node)) { + char* dummy; + if (!cast_is_legal(((AstUnaryOp *) node)->expr->type, type, &dummy)) { + return 0; + + } else { + ((AstUnaryOp *) node)->type = type; + return 1; + } + } + else if (node->kind == Ast_Kind_NumLit) { + if (convert_numlit_to_type((AstNumLit *) node, type)) return 1; + } + + return 0; +} + +Type* resolve_expression_type(AstTyped* node) { + if (node->type == NULL) + node->type = type_build_from_ast(semstate.allocator, node->type_node); + + if (node->kind == Ast_Kind_NumLit && node->type->kind == Type_Kind_Basic) { + if (node->type->Basic.kind == Basic_Kind_Int_Unsized) { + if ((((u64) ((AstNumLit *) node)->value.l) >> 32) > 0) + convert_numlit_to_type((AstNumLit *) node, &basic_types[Basic_Kind_I64]); + else + convert_numlit_to_type((AstNumLit *) node, &basic_types[Basic_Kind_I32]); + } + else if (node->type->Basic.kind == Basic_Kind_Float_Unsized) { + convert_numlit_to_type((AstNumLit *) node, &basic_types[Basic_Kind_F64]); + } + } + + return node->type; +} + +static const b32 cast_legality[][11] = { + /* I8 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* U8 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* I16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* U16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* I32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* U32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* I64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* U64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* F32 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, + /* F64 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, + /* PTR */ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1 }, +}; + +b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) { + Type* from = from_; + Type* to = to_; + + if (from->kind == Type_Kind_Enum) from = from->Enum.backing; + if (to->kind == Type_Kind_Enum) to = to->Enum.backing; + + if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) { + *err_msg = "Cannot cast to or from a struct."; + return 0; + } + + if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) { + *err_msg = "Cannot cast to or from a slice."; + return 0; + } + + if (from->kind == Type_Kind_DynArray || to->kind == Type_Kind_DynArray) { + *err_msg = "Cannot cast to or from a dynamic array."; + return 0; + } + + if (to->kind == Type_Kind_Function) { + *err_msg = "Cannot cast to a function."; + return 0; + } + + if ( (type_is_simd(to) && !type_is_simd(from)) + || (!type_is_simd(to) && type_is_simd(from))) { + *err_msg = "Can only perform a SIMD cast between SIMD types."; + return 0; + } + + if (from->kind == Type_Kind_Basic && from->Basic.kind == Basic_Kind_Void) { + *err_msg = "Cannot cast from void."; + return 0; + } + i32 fromidx = -1, toidx = -1; + if (from->Basic.flags & Basic_Flag_Pointer || from->kind == Type_Kind_Array) { + fromidx = 10; + } + else if (from->Basic.flags & Basic_Flag_Integer) { + b32 unsign = (from->Basic.flags & Basic_Flag_Unsigned) != 0; + + fromidx = log2_dumb(from->Basic.size) * 2 + unsign; + } + else if (from->Basic.flags & Basic_Flag_Float) { + if (from->Basic.size == 4) fromidx = 8; + else if (from->Basic.size == 8) fromidx = 9; + } + + if (to->Basic.flags & Basic_Flag_Pointer || to->kind == Type_Kind_Array) { + toidx = 10; + } + else if (to->Basic.flags & Basic_Flag_Integer) { + b32 unsign = (to->Basic.flags & Basic_Flag_Unsigned) != 0; + + toidx = log2_dumb(to->Basic.size) * 2 + unsign; + } + else if (to->Basic.flags & Basic_Flag_Float) { + if (to->Basic.size == 4) toidx = 8; + else if (to->Basic.size == 8) toidx = 9; + } + + if (fromidx != -1 && toidx != -1) { + if (!cast_legality[fromidx][toidx]) { + *err_msg = bh_aprintf(global_heap_allocator, "Cast from '%s' to '%s' is not allowed.", type_get_name(from_), type_get_name(to_)); + return 0; + } + } + + *err_msg = NULL; + return 1; +} + +char* get_function_name(AstFunction* func) { + if (func->name != NULL) { + return bh_aprintf(global_scratch_allocator, "%b", func->name->text, func->name->length); + } + + if (func->exported_name != NULL) { + return bh_aprintf(global_scratch_allocator, + "EXPORTED:%b", + func->exported_name->text, + func->exported_name->length); + } + + return ""; +} + + + +AstNumLit* make_int_literal(bh_allocator a, i64 i) { + AstNumLit* num = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); + num->flags |= Ast_Flag_Comptime; + + if (bh_abs(i) >= ((u64) 1 << 32)) + num->type_node = (AstType *) &basic_type_i64; + else + num->type_node = (AstType *) &basic_type_i32; + + num->value.l = i; + return num; +} + +AstNumLit* make_float_literal(bh_allocator a, f64 d) { + // NOTE: Use convert_numlit_to_type to make this a concrete float + AstNumLit* num = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); + num->flags |= Ast_Flag_Comptime; + num->type_node = (AstType *) &basic_type_float_unsized; + num->value.d = d; + return num; +} + +AstBinaryOp* make_binary_op(bh_allocator a, BinaryOp operation, AstTyped* left, AstTyped* right) { + AstBinaryOp* binop_node = onyx_ast_node_new(a, sizeof(AstBinaryOp), Ast_Kind_Binary_Op); + binop_node->left = left; + binop_node->right = right; + binop_node->operation = operation; + return binop_node; +} + +AstArgument* make_argument(bh_allocator a, AstTyped* value) { + AstArgument* arg = onyx_ast_node_new(a, sizeof(AstArgument), Ast_Kind_Argument); + if (value->token) arg->token = value->token; + arg->value = value; + arg->type = value->type; + arg->next = NULL; + arg->va_kind = VA_Kind_Not_VA; + return arg; +} + +AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field) { + AstFieldAccess* fa = onyx_ast_node_new(a, sizeof(AstFieldAccess), Ast_Kind_Field_Access); + if (node->token) fa->token = node->token; + fa->field = field; + fa->expr = node; + + return fa; +} + diff --git a/src/onyxchecker.c b/src/onyxchecker.c index cd0147ca..90d7b607 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -418,15 +418,10 @@ CheckStatus check_call(AstCall* call) { if (callee->kind == Ast_Kind_Function) { if (bh_arr_length(arg_arr) < bh_arr_length(callee->params)) { - while (bh_arr_length(arg_arr) < bh_arr_length(callee->params) - && callee->params[call->arg_count].default_value != NULL) { + while (bh_arr_length(arg_arr) < bh_arr_length(callee->params) && callee->params[call->arg_count].default_value != NULL) { AstTyped* dv = callee->params[call->arg_count].default_value; - AstArgument* new_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); - new_arg->token = dv->token; - new_arg->value = dv; - new_arg->next = NULL; - + AstArgument* new_arg = make_argument(semstate.node_allocator, dv); bh_arr_push(arg_arr, new_arg); } } @@ -586,30 +581,24 @@ CheckStatus check_binop_assignment(AstBinaryOp* binop, b32 assignment_is_ok) { } else { // NOTE: +=, -=, ... - AstBinaryOp* binop_node = onyx_ast_node_new( - semstate.node_allocator, - sizeof(AstBinaryOp), - Ast_Kind_Binary_Op); - - binop_node->token = binop->token; - binop_node->left = binop->left; - binop_node->right = binop->right; - - if (binop->operation == Binary_Op_Assign_Add) binop_node->operation = Binary_Op_Add; - else if (binop->operation == Binary_Op_Assign_Minus) binop_node->operation = Binary_Op_Minus; - else if (binop->operation == Binary_Op_Assign_Multiply) binop_node->operation = Binary_Op_Multiply; - else if (binop->operation == Binary_Op_Assign_Divide) binop_node->operation = Binary_Op_Divide; - else if (binop->operation == Binary_Op_Assign_Modulus) binop_node->operation = Binary_Op_Modulus; - else if (binop->operation == Binary_Op_Assign_And) binop_node->operation = Binary_Op_And; - else if (binop->operation == Binary_Op_Assign_Or) binop_node->operation = Binary_Op_Or; - else if (binop->operation == Binary_Op_Assign_Xor) binop_node->operation = Binary_Op_Xor; - else if (binop->operation == Binary_Op_Assign_Shl) binop_node->operation = Binary_Op_Shl; - else if (binop->operation == Binary_Op_Assign_Shr) binop_node->operation = Binary_Op_Shr; - else if (binop->operation == Binary_Op_Assign_Sar) binop_node->operation = Binary_Op_Sar; - - CHECK(binaryop, &binop_node, 0); - - binop->right = (AstTyped *) binop_node; + BinaryOp operation = -1; + if (binop->operation == Binary_Op_Assign_Add) operation = Binary_Op_Add; + else if (binop->operation == Binary_Op_Assign_Minus) operation = Binary_Op_Minus; + else if (binop->operation == Binary_Op_Assign_Multiply) operation = Binary_Op_Multiply; + else if (binop->operation == Binary_Op_Assign_Divide) operation = Binary_Op_Divide; + else if (binop->operation == Binary_Op_Assign_Modulus) operation = Binary_Op_Modulus; + else if (binop->operation == Binary_Op_Assign_And) operation = Binary_Op_And; + else if (binop->operation == Binary_Op_Assign_Or) operation = Binary_Op_Or; + else if (binop->operation == Binary_Op_Assign_Xor) operation = Binary_Op_Xor; + else if (binop->operation == Binary_Op_Assign_Shl) operation = Binary_Op_Shl; + else if (binop->operation == Binary_Op_Assign_Shr) operation = Binary_Op_Shr; + else if (binop->operation == Binary_Op_Assign_Sar) operation = Binary_Op_Sar; + + AstBinaryOp* new_right = make_binary_op(semstate.node_allocator, operation, binop->left, binop->right); + new_right->token = binop->token; + CHECK(binaryop, &new_right, 0); + + binop->right = (AstTyped *) new_right; binop->operation = Binary_Op_Assign; } @@ -713,15 +702,8 @@ static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop) { implicit_call->callee = overload; implicit_call->va_kind = VA_Kind_Not_VA; - bh_arr_each(AstTyped *, arg, args) { - AstArgument* new_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); - new_arg->token = (*arg)->token; - new_arg->type = (*arg)->type; - new_arg->value = *arg; - new_arg->va_kind = VA_Kind_Not_VA; - - *arg = (AstTyped *) new_arg; - } + bh_arr_each(AstTyped *, arg, args) + *arg = (AstTyped *) make_argument(semstate.node_allocator, *arg); implicit_call->arg_arr = (AstArgument **) args; return implicit_call; @@ -787,22 +769,14 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop, b32 assignment_is_ok) { if (binop->operation != Binary_Op_Add && binop->operation != Binary_Op_Minus) goto bad_binaryop; resolve_expression_type(binop->right); - if (!type_is_integer(binop->right->type)) { - onyx_report_error(binop->right->token->pos, "Expected integer type."); - return Check_Error; - } + if (!type_is_integer(binop->right->type)) goto bad_binaryop; - AstNumLit* numlit = onyx_ast_node_new(semstate.node_allocator, sizeof(AstNumLit), Ast_Kind_NumLit); + AstNumLit* numlit = make_int_literal(semstate.node_allocator, type_size_of(binop->left->type->Pointer.elem)); numlit->token = binop->right->token; numlit->type = binop->right->type; - numlit->value.i = type_size_of(binop->left->type->Pointer.elem); - AstBinaryOp* binop_node = onyx_ast_node_new(semstate.node_allocator, sizeof(AstBinaryOp), Ast_Kind_Binary_Op); + AstBinaryOp* binop_node = make_binary_op(semstate.node_allocator, Binary_Op_Multiply, binop->right, (AstTyped *) numlit); binop_node->token = binop->token; - binop_node->left = binop->right; - binop_node->right = (AstTyped *) numlit; - binop_node->operation = Binary_Op_Multiply; - CHECK(binaryop, &binop_node, 0); binop->right = (AstTyped *) binop_node; @@ -1211,13 +1185,11 @@ CheckStatus check_array_access(AstArrayAccess* aa) { StructMember smem; type_lookup_member(aa->addr->type, "data", &smem); - AstFieldAccess* fa = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access); - fa->token = aa->addr->token; - fa->type = smem.type; + + AstFieldAccess* fa = make_field_access(semstate.node_allocator, aa->addr, "data"); + fa->type = smem.type; fa->offset = smem.offset; - fa->idx = smem.idx; - fa->expr = aa->addr; - fa->field = "data"; + fa->idx = smem.idx; aa->addr = (AstTyped *) fa; aa->type = aa->addr->type->Pointer.elem; diff --git a/src/onyxparser.c b/src/onyxparser.c index 1bfe4f01..022e4a44 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -114,17 +114,6 @@ static void add_node_to_process(OnyxParser* parser, AstNode* node) { } -AstNumLit* make_int_literal(bh_allocator a, i64 i) { - AstNumLit* num = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); - if (bh_abs(i) >= ((u64) 1 << 32)) - num->type_node = (AstType *) &basic_type_i64; - else - num->type_node = (AstType *) &basic_type_i32; - - num->value.l = i; - return num; -} - static AstNumLit* parse_int_literal(OnyxParser* parser) { AstNumLit* int_node = make_node(AstNumLit, Ast_Kind_NumLit); int_node->token = expect_token(parser, Token_Type_Literal_Integer); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 746f967c..77edbbeb 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -35,14 +35,6 @@ static void symres_memres_type(AstMemRes** memres); static void symres_memres(AstMemRes** memres); static void symres_struct_defaults(AstType* st); -static AstFieldAccess* make_field_access(AstTyped* node, char* field) { - AstFieldAccess* fa = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access); - fa->field = field; - fa->expr = node; - - return fa; -} - static void scope_enter(Scope* new_scope) { semstate.curr_scope = new_scope; } @@ -291,14 +283,8 @@ static void symres_pipe(AstBinaryOp** pipe) { if ((*pipe)->left == NULL) return; - AstArgument* implicit_arg = onyx_ast_node_new(semstate.node_allocator, - sizeof(AstArgument), - Ast_Kind_Argument); - implicit_arg->token = (*pipe)->left->token; - implicit_arg->value = (*pipe)->left; - bh_arr_insertn(call_node->arg_arr, 0, 1); - call_node->arg_arr[0] = implicit_arg; + call_node->arg_arr[0] = make_argument(semstate.node_allocator, (*pipe)->left); call_node->arg_count++; call_node->next = (*pipe)->next; @@ -533,7 +519,7 @@ static void symres_use(AstUse* use) { st = st->Pointer.elem; bh_table_each_start(StructMember, st->Struct.members); - AstFieldAccess* fa = make_field_access(use->expr, value.name); + AstFieldAccess* fa = make_field_access(semstate.node_allocator, use->expr, value.name); symbol_raw_introduce(semstate.curr_scope, value.name, use->token->pos, (AstNode *) fa); bh_table_each_end; @@ -697,7 +683,7 @@ void symres_function_header(AstFunction* func) { } bh_table_each_start(StructMember, st->Struct.members); - AstFieldAccess* fa = make_field_access((AstTyped *) param->local, value.name); + AstFieldAccess* fa = make_field_access(semstate.node_allocator, (AstTyped *) param->local, value.name); symbol_raw_introduce(semstate.curr_scope, value.name, param->local->token->pos, (AstNode *) fa); bh_table_each_end; @@ -806,9 +792,7 @@ static void symres_enum(AstEnumType* enum_node) { (*value)->value->type = enum_node->etcache; } else { - AstNumLit* num = onyx_ast_node_new(semstate.node_allocator, sizeof(AstNumLit), Ast_Kind_NumLit); - num->value.l = next_assign_value; - num->flags |= Ast_Flag_Comptime; + AstNumLit* num = make_int_literal(semstate.node_allocator, next_assign_value); num->type = enum_node->etcache; (*value)->value = num; diff --git a/src/onyxutils.c b/src/onyxutils.c index bc845ebb..f6eab9bb 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -8,143 +8,12 @@ #include "onyxastnodes.h" #include "onyxsempass.h" - bh_scratch global_scratch; bh_allocator global_scratch_allocator; bh_managed_heap global_heap; bh_allocator global_heap_allocator; -static AstNode empty_node = { Ast_Kind_Error, 0, NULL, NULL }; - -static const char* ast_node_names[] = { - "ERROR", - "PROGRAM", - "PACKAGE", - "INCLUDE FILE", - "INCLUDE FOLDER", - "USE PACKAGE", - "ALIAS", - "MEMORY RESERVATION", - - "BINDING", - "FUNCTION", - "OVERLOADED_FUNCTION", - "POLYMORPHIC PROC", - "BLOCK", - "LOCAL GROUP", - "LOCAL", - "GLOBAL", - "SYMBOL", - - "UN_OP", - "BIN_OP", - - "TYPE_START (BAD)", - "TYPE", - "BASIC_TYPE", - "POINTER_TYPE", - "FUNCTION_TYPE", - "ARRAY TYPE", - "SLICE TYPE", - "DYNARR TYPE", - "VARARG TYPE", - "STRUCT TYPE", - "POLYMORPHIC STRUCT TYPE", - "POLYMORPHIC STRUCT CALL TYPE", - "ENUM TYPE", - "TYPE_ALIAS", - "TYPE RAW ALIAS", - "TYPE_END (BAD)", - - "STRUCT MEMBER", - "ENUM VALUE", - - "NUMERIC LITERAL", - "STRING LITERAL", - "PARAM", - "ARGUMENT", - "CALL", - "INTRINSIC CALL", - "RETURN", - "ADDRESS OF", - "DEREFERENCE", - "ARRAY_ACCESS", - "SLICE", - "FIELD_ACCESS", - "PIPE", - "RANGE", - "SIZE OF", - "ALIGN OF", - "FILE CONTENTS", - "STRUCT LITERAL", - "ARRAY LITERAL", - - "IF", - "FOR", - "WHILE", - "JUMP", - "USE", - "DEFER", - "SWITCH", - "SWITCH CASE", - - "AST_NODE_KIND_COUNT", -}; - -const char* onyx_ast_node_kind_string(AstKind kind) { - return ast_node_names[kind]; -} - -const char *binaryop_string[Binary_Op_Count] = { - "+", "-", "*", "/", "%", - "==", "!=", "<", "<=", ">", ">=", - "&", "|", "^", "<<", ">>", ">>>", - "&&", "||", - - "NONE", - "=", "+=", "-=", "*=", "/=", "%=", - "&=", "|=", "^=", "<<=", ">>=", ">>>=", - "NONE", - - "|>", "..", -}; - -const char* entity_state_strings[Entity_State_Count] = { - "Error", - "Parse Builtin", - "Parse", - "Resolve_Symbols", - "Check_Types", - "Code_Gen", - "Finalized", -}; - -const char* entity_type_strings[Entity_Type_Count] = { - "Unknown", - "Add to Load Path", - "Load File", - "Use Package", - "String Literal", - "File Contents", - "Enum", - "Type Alias", - "Memory Reservation Type", - "Use", - "Polymorphic Proc", - "Foreign_Function Header", - "Foreign_Global Header", - "Function Header", - "Global Header", - "Struct Member Default", - "Memory Reservation", - "Expression", - "Global", - "Overloaded_Function", - "Function", -}; - - void program_info_init(ProgramInfo* prog, bh_allocator alloc) { prog->global_scope = scope_create(alloc, NULL, (OnyxFilePos) { 0 }); @@ -278,156 +147,6 @@ void scope_clear(Scope* scope) { bh_table_clear(scope->symbols); } -#define REDUCE_BINOP_ALL(op) \ - if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \ - res->value.i = left->value.i op right->value.i; \ - } else if (type_is_integer(res->type) \ - || res->type->Basic.kind == Basic_Kind_Int_Unsized \ - || res->type->kind == Type_Kind_Enum) { \ - res->value.l = left->value.l op right->value.l; \ - } else if (res->type->Basic.kind == Basic_Kind_F32) { \ - res->value.f = left->value.f op right->value.f; \ - } else if (res->type->Basic.kind == Basic_Kind_F64 || res->type->Basic.kind == Basic_Kind_Float_Unsized) { \ - res->value.d = left->value.d op right->value.d; \ - } \ - break; - -#define REDUCE_BINOP_INT(op) \ - if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \ - res->value.i = left->value.i op right->value.i; \ - } else if (type_is_integer(res->type) \ - || res->type->Basic.kind == Basic_Kind_Int_Unsized \ - || res->type->kind == Type_Kind_Enum) { \ - res->value.l = left->value.l op right->value.l; \ - } \ - break; - -#define REDUCE_BINOP_BOOL(op) \ - if (type_is_bool(res->type)) { \ - res->value.i = left->value.i op right->value.i; \ - } \ - break; - -AstNumLit* ast_reduce_binop(bh_allocator a, AstBinaryOp* node) { - AstNumLit* left = (AstNumLit *) ast_reduce(a, node->left); - AstNumLit* right = (AstNumLit *) ast_reduce(a, node->right); - - if (left->kind != Ast_Kind_NumLit || right->kind != Ast_Kind_NumLit) { - node->left = (AstTyped *) left; - node->right = (AstTyped *) right; - return (AstNumLit *) node; - } - - AstNumLit* res = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); - res->token = node->token; - res->flags |= Ast_Flag_Comptime; - res->type_node = node->type_node; - res->type = node->type; - - switch (node->operation) { - case Binary_Op_Add: REDUCE_BINOP_ALL(+); - case Binary_Op_Minus: REDUCE_BINOP_ALL(-); - case Binary_Op_Multiply: REDUCE_BINOP_ALL(*); - case Binary_Op_Divide: REDUCE_BINOP_ALL(/); - case Binary_Op_Modulus: REDUCE_BINOP_INT(%); - - case Binary_Op_Equal: REDUCE_BINOP_ALL(==); - case Binary_Op_Not_Equal: REDUCE_BINOP_ALL(!=); - case Binary_Op_Less: REDUCE_BINOP_ALL(<); - case Binary_Op_Less_Equal: REDUCE_BINOP_ALL(<=); - case Binary_Op_Greater: REDUCE_BINOP_ALL(>); - case Binary_Op_Greater_Equal: REDUCE_BINOP_ALL(>=); - - case Binary_Op_And: REDUCE_BINOP_INT(&); - case Binary_Op_Or: REDUCE_BINOP_INT(|); - case Binary_Op_Xor: REDUCE_BINOP_INT(^); - case Binary_Op_Shl: REDUCE_BINOP_INT(<<); - case Binary_Op_Shr: REDUCE_BINOP_INT(>>); - case Binary_Op_Sar: REDUCE_BINOP_INT(>>); - - case Binary_Op_Bool_And: REDUCE_BINOP_BOOL(&&); - case Binary_Op_Bool_Or: REDUCE_BINOP_BOOL(||); - - default: break; - } - - return res; -} - -#define REDUCE_UNOP(op) \ - if (type_is_small_integer(unop->type) || type_is_bool(unop->type)) { \ - res->value.i = op ((AstNumLit *) unop->expr)->value.i; \ - } else if (type_is_integer(unop->type) || unop->type->Basic.kind == Basic_Kind_Int_Unsized) { \ - res->value.l = op ((AstNumLit *) unop->expr)->value.l; \ - } else if (unop->type->Basic.kind == Basic_Kind_F32) { \ - res->value.f = op ((AstNumLit *) unop->expr)->value.f; \ - } else if (unop->type->Basic.kind == Basic_Kind_F64 || unop->type->Basic.kind == Basic_Kind_Float_Unsized) { \ - res->value.d = op ((AstNumLit *) unop->expr)->value.d; \ - } \ - break; - -#define REDUCE_UNOP_INT(op) \ - if (type_is_small_integer(unop->type) || type_is_bool(unop->type)) { \ - res->value.i = op ((AstNumLit *) unop->expr)->value.i; \ - } else if (type_is_integer(unop->type)) { \ - res->value.l = op ((AstNumLit *) unop->expr)->value.l; \ - } - -AstTyped* ast_reduce_unaryop(bh_allocator a, AstUnaryOp* unop) { - unop->expr = ast_reduce(a, unop->expr); - - if (unop->expr->kind != Ast_Kind_NumLit) { - return (AstTyped *) unop; - } - - AstNumLit* res = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); - res->token = unop->token; - res->flags |= Ast_Flag_Comptime; - res->type_node = unop->type_node; - res->type = unop->type; - - switch (unop->operation) { - case Unary_Op_Negate: REDUCE_UNOP(-); - case Unary_Op_Not: { - if (type_is_bool(res->type)) res->value.i = ! ((AstNumLit *) unop->expr)->value.i; - break; - } - case Unary_Op_Bitwise_Not: REDUCE_UNOP_INT(~); - - default: return (AstTyped *) unop; - } - - return (AstTyped *) res; -} - -AstTyped* ast_reduce(bh_allocator a, AstTyped* node) { - assert(node->flags & Ast_Flag_Comptime); - - switch (node->kind) { - case Ast_Kind_Binary_Op: return (AstTyped *) ast_reduce_binop(a, (AstBinaryOp *) node); - case Ast_Kind_Unary_Op: return (AstTyped *) ast_reduce_unaryop(a, (AstUnaryOp *) node); - case Ast_Kind_NumLit: return node; - case Ast_Kind_Enum_Value: return (AstTyped *) ((AstEnumValue *) node)->value; - default: return NULL; - } -} - -void promote_numlit_to_larger(AstNumLit* num) { - assert(num->type != NULL); - - if (type_is_integer(num->type) && num->type->Basic.size <= 4) { - // NOTE: Int32, Int16, Int8 - i64 val = (i64) num->value.i; - num->value.l = val; - num->type = &basic_types[Basic_Kind_I64]; - } else if (num->type->Basic.size <= 4) { - // NOTE: Float32 - f64 val = (f64) num->value.f; - num->value.d = val; - num->type = &basic_types[Basic_Kind_F64]; - } -} - static void insert_poly_slns_into_scope(Scope* scope, bh_arr(AstPolySolution) slns) { bh_arr_each(AstPolySolution, sln, slns) { AstNode *node = NULL; @@ -981,287 +700,6 @@ AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstP return concrete_struct; } -// NOTE: Returns 1 if the conversion was successful. -b32 convert_numlit_to_type(AstNumLit* num, Type* type) { - if (num->type == NULL) - num->type = type_build_from_ast(semstate.allocator, num->type_node); - assert(num->type); - - if (types_are_compatible(num->type, type)) return 1; - if (!type_is_numeric(type)) return 0; - - if (num->type->Basic.kind == Basic_Kind_Int_Unsized) { - - // - // Integer literal auto cast rules: - // - Up in size always works - // - Down in size only works if value is in range of smaller type. - // - Cast to float only works if value is less than the maximum precise value for float size. - // - - if (type->Basic.flags & Basic_Flag_Integer) { - if (type->Basic.flags & Basic_Flag_Unsigned) { - u64 value = (u64) num->value.l; - if (type->Basic.size == 8) { - num->type = type; - return 1; - } - switch (type->Basic.size) { - case 1: if (value <= 255) { - num->type = type; - return 1; - } - case 2: if (value <= 65535) { - num->type = type; - return 1; - } - case 4: if (value <= 4294967295) { - num->type = type; - return 1; - } - } - - onyx_report_error(num->token->pos, "Unsigned integer constant with value '%l' does not fit into %d-bits.", - num->value.l, - type->Basic.size * 8); - - } else { - i64 value = (i64) num->value.l; - switch (type->Basic.size) { - case 1: if (-128ll <= value && value <= 127ll) { - num->value.i = (i32) value; - num->type = type; - return 1; - } break; - case 2: if (-32768ll <= value && value <= 32767ll) { - num->value.i = (i32) value; - num->type = type; - return 1; - } break; - case 4: if (-2147483648ll <= value && value <= 2147483647ll) { - num->value.i = (i32) value; - num->type = type; - return 1; - } break; - case 8: { num->type = type; - return 1; - } break; - } - - onyx_report_error(num->token->pos, "Integer constant with value '%l' does not fit into %d-bits.", - num->value.l, - type->Basic.size * 8); - } - } - - else if (type->Basic.flags & Basic_Flag_Float) { - if (type->Basic.size == 4) { - // TODO(Brendan): Check these boundary conditions - if (bh_abs(num->value.l) >= (1 << 23)) { - onyx_report_error(num->token->pos, "Integer '%l' does not fit in 32-bit float exactly.", num->value.l); - return 0; - } - - num->type = type; - num->value.f = (f32) num->value.l; - return 1; - } - if (type->Basic.size == 8) { - // TODO(Brendan): Check these boundary conditions - if (bh_abs(num->value.l) >= (1ull << 52)) { - onyx_report_error(num->token->pos, "Integer '%l' does not fit in 64-bit float exactly.", num->value.l); - return 0; - } - - num->type = type; - num->value.d = (f64) num->value.l; - return 1; - } - } - } - else if (num->type->Basic.kind == Basic_Kind_Float_Unsized) { - // NOTE: Floats don't cast to integers implicitly. - if ((type->Basic.flags & Basic_Flag_Float) == 0) return 0; - - if (type->Basic.kind == Basic_Kind_F32) { - num->value.f = (f32) num->value.d; - } - - num->type = type; - return 1; - } - else if (num->type->Basic.kind == Basic_Kind_F32) { - // NOTE: Floats don't cast to integers implicitly. - if ((type->Basic.flags & Basic_Flag_Float) == 0) return 0; - - if (type->Basic.kind == Basic_Kind_F64) { - num->value.d = (f64) num->value.f; - num->type = type; - return 1; - } - } - - return 0; -} - -// NOTE: Returns 0 if it was not possible to make the types compatible. -b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) { - AstTyped* node = *pnode; - assert(type != NULL); - assert(node != NULL); - - if (node->kind == Ast_Kind_Polymorphic_Proc) { - AstFunction* func = polymorphic_proc_lookup((AstPolyProc *) node, PPLM_By_Function_Type, type, node->token->pos); - if (func == NULL) return 0; - - *pnode = (AstTyped *) func; - node = *pnode; - } - - // HACK: NullProcHack - if (type->kind == Type_Kind_Function && (node->flags & Ast_Flag_Proc_Is_Null) != 0) return 1; - - if (types_are_compatible(node->type, type)) return 1; - if (node_is_auto_cast((AstNode *) node)) { - char* dummy; - if (!cast_is_legal(((AstUnaryOp *) node)->expr->type, type, &dummy)) { - return 0; - - } else { - ((AstUnaryOp *) node)->type = type; - return 1; - } - } - else if (node->kind == Ast_Kind_NumLit) { - if (convert_numlit_to_type((AstNumLit *) node, type)) return 1; - } - - return 0; -} - -Type* resolve_expression_type(AstTyped* node) { - if (node->type == NULL) - node->type = type_build_from_ast(semstate.allocator, node->type_node); - - if (node->kind == Ast_Kind_NumLit && node->type->kind == Type_Kind_Basic) { - if (node->type->Basic.kind == Basic_Kind_Int_Unsized) { - if ((((u64) ((AstNumLit *) node)->value.l) >> 32) > 0) - convert_numlit_to_type((AstNumLit *) node, &basic_types[Basic_Kind_I64]); - else - convert_numlit_to_type((AstNumLit *) node, &basic_types[Basic_Kind_I32]); - } - else if (node->type->Basic.kind == Basic_Kind_Float_Unsized) { - convert_numlit_to_type((AstNumLit *) node, &basic_types[Basic_Kind_F64]); - } - } - - return node->type; -} - -static const b32 cast_legality[][11] = { - /* I8 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, - /* U8 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, - /* I16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, - /* U16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, - /* I32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - /* U32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - /* I64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - /* U64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - /* F32 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, - /* F64 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, - /* PTR */ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1 }, -}; - -b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) { - Type* from = from_; - Type* to = to_; - - if (from->kind == Type_Kind_Enum) from = from->Enum.backing; - if (to->kind == Type_Kind_Enum) to = to->Enum.backing; - - if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) { - *err_msg = "Cannot cast to or from a struct."; - return 0; - } - - if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) { - *err_msg = "Cannot cast to or from a slice."; - return 0; - } - - if (from->kind == Type_Kind_DynArray || to->kind == Type_Kind_DynArray) { - *err_msg = "Cannot cast to or from a dynamic array."; - return 0; - } - - if (to->kind == Type_Kind_Function) { - *err_msg = "Cannot cast to a function."; - return 0; - } - - if ( (type_is_simd(to) && !type_is_simd(from)) - || (!type_is_simd(to) && type_is_simd(from))) { - *err_msg = "Can only perform a SIMD cast between SIMD types."; - return 0; - } - - if (from->kind == Type_Kind_Basic && from->Basic.kind == Basic_Kind_Void) { - *err_msg = "Cannot cast from void."; - return 0; - } - i32 fromidx = -1, toidx = -1; - if (from->Basic.flags & Basic_Flag_Pointer || from->kind == Type_Kind_Array) { - fromidx = 10; - } - else if (from->Basic.flags & Basic_Flag_Integer) { - b32 unsign = (from->Basic.flags & Basic_Flag_Unsigned) != 0; - - fromidx = log2_dumb(from->Basic.size) * 2 + unsign; - } - else if (from->Basic.flags & Basic_Flag_Float) { - if (from->Basic.size == 4) fromidx = 8; - else if (from->Basic.size == 8) fromidx = 9; - } - - if (to->Basic.flags & Basic_Flag_Pointer || to->kind == Type_Kind_Array) { - toidx = 10; - } - else if (to->Basic.flags & Basic_Flag_Integer) { - b32 unsign = (to->Basic.flags & Basic_Flag_Unsigned) != 0; - - toidx = log2_dumb(to->Basic.size) * 2 + unsign; - } - else if (to->Basic.flags & Basic_Flag_Float) { - if (to->Basic.size == 4) toidx = 8; - else if (to->Basic.size == 8) toidx = 9; - } - - if (fromidx != -1 && toidx != -1) { - if (!cast_legality[fromidx][toidx]) { - *err_msg = bh_aprintf(global_heap_allocator, "Cast from '%s' to '%s' is not allowed.", type_get_name(from_), type_get_name(to_)); - return 0; - } - } - - *err_msg = NULL; - return 1; -} - -char* get_function_name(AstFunction* func) { - if (func->name != NULL) { - return bh_aprintf(global_scratch_allocator, "%b", func->name->text, func->name->length); - } - - if (func->exported_name != NULL) { - return bh_aprintf(global_scratch_allocator, - "EXPORTED:%b", - func->exported_name->text, - func->exported_name->length); - } - - return ""; -} - void entity_bring_to_state(Entity* ent, EntityState state) { while (ent->state != state) { switch (ent->state) {