code cleanup making new ast nodes
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Jan 2021 22:16:17 +0000 (16:16 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Jan 2021 22:16:17 +0000 (16:16 -0600)
bin/onyx
build.bat
build.sh
include/onyxastnodes.h
onyx.exe
src/onyxastnodes.c [new file with mode: 0644]
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c

index 31d17195d7c8a626b1c5925223f29a58260e0ac5..23dd19cdf4c5e69a038d7aded1025d5ee3c6a5c3 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 959743559a45c2fc53c1561c7513250689879051..b41ee9b5f88f04fc535e01adbf2890404b5b9381 100644 (file)
--- 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
index ffa057121806d39a75247f2126a4dd60eba440f4..cdf69ed8b0cce6cbb95ec5d3ff375efa58954f5b 100644 (file)
--- 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'
 
index b29e9a2a61f6a6786f768bd59febc82badc1e17e..113f92327eeb3049e5853f63d8f44fa036ddae40 100644 (file)
@@ -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,
index b74bf61e3bd4eb10392040bf88958a07214391dc..d9206455fd119e4ad0aae6de39ff40cbf1f2c618 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c
new file mode 100644 (file)
index 0000000..c90dc28
--- /dev/null
@@ -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 "<anonymous procedure>";
+}
+
+
+
+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;
+}
+
index cd0147cae37f2b1e7562b77e1fb744ec4c4f4d88..90d7b607dca6da27bd712cb06dc96b23f0e363f3 100644 (file)
@@ -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;
index 1bfe4f01e1cc829adff360b7e21f89e487a59aea..022e4a446479fe1729a3cb56f2a53e334b9350ba 100644 (file)
@@ -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);
index 746f967cef10984be8c213ad5c390b03377d483c..77edbbebd77aa740cfe89e2eb5187fcf8cc7b57f 100644 (file)
@@ -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;
index bc845ebba2c523d3505de29b3a72a7901025bc1d..f6eab9bb729ce3714532783643ab4439be7001d7 100644 (file)
 #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 "<anonymous procedure>";
-}
-
 void entity_bring_to_state(Entity* ent, EntityState state) {
     while (ent->state != state) {
         switch (ent->state) {