From: Brendan Hansen Date: Fri, 10 Jul 2020 04:36:39 +0000 (-0500) Subject: Revamping type system; X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=16f8ee856e11081ca2ec876cf92dae60893a9c63;p=onyx.git Revamping type system; CODE IS VERY BROKEN --- diff --git a/.vimspector.json b/.vimspector.json index e309f7f9..88493853 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -6,7 +6,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/onyx", - "args": ["progs/test.onyx"], + "args": ["progs/basic.onyx"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index a19b4954..ae30f3ae 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -24,6 +24,10 @@ typedef struct AstIntrinsicCall AstIntrinsicCall; typedef struct AstArgument AstArgument; typedef struct AstUse AstUse; +typedef struct AstType AstType; +typedef struct AstBasicType AstBasicType; +typedef struct AstPointerType AstPointerType; + typedef enum AstKind { Ast_Kind_Error, Ast_Kind_Program, @@ -41,6 +45,9 @@ typedef enum AstKind { Ast_Kind_Binary_Op, Ast_Kind_Type, + Ast_Kind_Basic_Type, + Ast_Kind_Pointer_Type, + Ast_Kind_Literal, Ast_Kind_Param, Ast_Kind_Argument, @@ -92,6 +99,9 @@ typedef enum BinaryOp { Binary_Op_Greater_Equal = 10, } BinaryOp; + +// Base Nodes + // NOTE: AstNode and AstTyped need to be EXACTLY the same for all // arguments existing in AstNode. I do this to avoid a nested // "inheiritance" where you would have to say node.base.base.next @@ -108,67 +118,38 @@ struct AstTyped { u32 flags; OnyxToken *token; AstNode *next; - Type *type; -}; - -struct AstBinOp { - AstTyped base; - BinaryOp operation; - - AstTyped *left, *right; -}; - -struct AstUnaryOp { - AstTyped base; - - UnaryOp operation; - - AstTyped *expr; -}; - -struct AstAssign { - AstNode base; - - AstTyped* lval; - AstTyped* expr; -}; - -struct AstNumLit { - AstTyped base; - - union { i32 i; i64 l; f32 f; f64 d; } value; -}; - -struct AstLocal { - AstTyped base; - - AstLocal *prev_local; -}; - -struct AstReturn { - AstNode base; - - AstTyped* expr; -}; - -struct AstLocalGroup { - AstNode base; - - AstLocalGroup *prev_group; - AstLocal *last_local; -}; - -struct AstBlock { - AstNode base; - - AstNode *body; - AstLocalGroup *locals; + // NOTE: 'type_node' is filled out by the parser. + // For a type such as '^^i32', the tree would look something like + // + // Typed Thing -> AstPointerType -> AstPointerType -> AstNode (symbol node) + // + // The symbol node will be filled out during symbol resolution. + // It will end up pointing to an AstBasicType that corresponds to + // the underlying type. + // + // 'type' is filled out afterwards. If it is NULL, the Type* is built + // using the type_node. This can then be used to typecheck this node. + AstType *type_node; + Type *type; }; +// Expression Nodes +struct AstBinOp { AstTyped base; BinaryOp operation; AstTyped *left, *right; }; +struct AstUnaryOp { AstTyped base; UnaryOp operation; AstTyped *expr; }; +struct AstAssign { AstNode base; AstTyped* lval; AstTyped* expr; }; +struct AstNumLit { AstTyped base; union { i32 i; i64 l; f32 f; f64 d; } value; }; +struct AstLocal { AstTyped base; AstLocal *prev_local; }; +struct AstReturn { AstNode base; AstTyped* expr; }; +struct AstCall { AstTyped base; AstArgument *arguments; AstNode *callee; }; +struct AstArgument { AstTyped base; AstTyped *value; }; + +// Structure Nodes +struct AstLocalGroup { AstNode base; AstLocalGroup *prev_group; AstLocal *last_local; }; +struct AstBlock { AstNode base; AstNode *body; AstLocalGroup *locals; }; +struct AstWhile { AstNode base; AstTyped *cond; AstBlock *body; }; struct AstIf { AstNode base; - AstTyped *cond; union { @@ -177,47 +158,20 @@ struct AstIf { } true_block, false_block; }; -struct AstWhile { - AstNode base; - - AstTyped *cond; - AstBlock *body; -}; - -struct AstFunction { - AstTyped base; - - AstBlock *body; - AstLocal *params; -}; - -struct AstForeign { - AstNode base; - - OnyxToken *mod_token, *name_token; - AstNode *import; -}; - -struct AstGlobal { - AstTyped base; - - AstTyped *initial_value; -}; - -struct AstCall { - AstTyped base; - - AstArgument *arguments; // NOTE: Expressions that form the actual param list - // They will be chained down using the "next" property - // unless this becomes used by something else - AstNode *callee; // NOTE: Function definition node -}; - -struct AstArgument { - AstTyped base; - - AstTyped *value; -}; +// Type Nodes +// NOTE: This node is very similar to an AstNode, just +// without the 'next' member. This is because types +// can't be in expressions so a 'next' thing +// doesn't make sense. +struct AstType { AstKind kind; u32 flags; char* name; }; +struct AstBasicType { AstType base; Type* type; }; +struct AstPointerType { AstType base; AstType* elem; }; + +// Top level nodes +struct AstFunction { AstTyped base; AstBlock *body; AstLocal *params; }; +struct AstForeign { AstNode base; OnyxToken *mod_token, *name_token; AstNode *import; }; +struct AstGlobal { AstTyped base; AstTyped *initial_value; }; +struct AstUse { AstNode base; OnyxToken *filename; }; typedef enum OnyxIntrinsic { ONYX_INTRINSIC_UNDEFINED, @@ -279,16 +233,29 @@ struct AstIntrinsicCall { OnyxIntrinsic intrinsic; }; -struct AstUse { - AstNode base; - - OnyxToken *filename; -}; - typedef struct OnyxProgram { bh_arr(AstGlobal *) globals; bh_arr(AstFunction *) functions; bh_arr(AstForeign *) foreigns; } OnyxProgram; + + + + +// NOTE: Basic internal types constructed in the parser +extern AstBasicType basic_type_void; +extern AstBasicType basic_type_bool; +extern AstBasicType basic_type_i8; +extern AstBasicType basic_type_u8; +extern AstBasicType basic_type_i16; +extern AstBasicType basic_type_u16; +extern AstBasicType basic_type_i32; +extern AstBasicType basic_type_u32; +extern AstBasicType basic_type_i64; +extern AstBasicType basic_type_u64; +extern AstBasicType basic_type_f32; +extern AstBasicType basic_type_f64; +extern AstBasicType basic_type_rawptr; + #endif // #ifndef ONYXASTNODES_H diff --git a/include/onyxparser.h b/include/onyxparser.h index 98c67d43..fbf30cbb 100644 --- a/include/onyxparser.h +++ b/include/onyxparser.h @@ -12,9 +12,6 @@ typedef struct OnyxParser { OnyxToken *prev_token; OnyxToken *curr_token; - // NOTE: Identifiers currently is only used to resolve type names - // at parse time, since these are the only symbols we know. - bh_table(AstNode *) identifiers; OnyxMessages *msgs; bh_allocator allocator; diff --git a/include/onyxsempass.h b/include/onyxsempass.h index 287c4b33..138ef8e0 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -22,7 +22,7 @@ typedef struct OnyxSemPassState { AstLocalGroup* curr_local_group; // NOTE: Used in type checking phase - TypeInfo* expected_return_type; + Type* expected_return_type; // NOTE: All symbols a given point that we can resolve bh_table(SemPassSymbol *) symbols; diff --git a/include/onyxtypes.h b/include/onyxtypes.h index 5a50ba4b..5954d375 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -48,7 +48,7 @@ typedef struct Type Type; #define TYPE_KINDS \ TYPE_KIND(Basic, TypeBasic) \ - TYPE_KIND(Pointer, struct { Type *elem; }) + TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; }) typedef enum TypeKind { Type_Kind_Invalid, @@ -82,5 +82,8 @@ struct Type { extern Type basic_types[]; +struct AstType; +b32 types_are_compatible(Type* t1, Type* t2); +Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node); #endif // #ifndef ONYX_TYPES diff --git a/onyx b/onyx index 6d137519..25b0e01d 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/basic.onyx b/progs/basic.onyx new file mode 100644 index 00000000..3d3f1584 --- /dev/null +++ b/progs/basic.onyx @@ -0,0 +1,9 @@ +use "progs/intrinsics" + +test :: proc (a: bool) -> i32 { + return 0; +} + +export main :: proc { + a : i32 = 0; +} diff --git a/src/onyxchecker.c b/src/onyxchecker.c index c7d0fcd7..38b9bac4 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -10,6 +10,7 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode); static void check_if(OnyxSemPassState* state, AstIf* ifnode); static void check_while(OnyxSemPassState* state, AstWhile* whilenode); static void check_call(OnyxSemPassState* state, AstCall* call); +static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop); static void check_expression(OnyxSemPassState* state, AstTyped* expr); static void check_global(OnyxSemPassState* state, AstGlobal* global); @@ -22,7 +23,11 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) { return; } - if ((assign->lval->flags & Ast_Flag_Const) != 0 && assign->lval->type->is_known) { + if (assign->lval->type == NULL) { + assign->lval->type = type_build_from_ast(state->node_allocator, assign->lval->type_node); + } + + if ((assign->lval->flags & Ast_Flag_Const) != 0 && assign->lval->type != NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_ASSIGN_CONST, assign->base.token->pos, @@ -40,14 +45,14 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) { check_expression(state, assign->expr); - if (!assign->lval->type->is_known) { + if (assign->lval->type == NULL) { assign->lval->type = assign->expr->type; } else { - if (assign->lval->type != assign->expr->type) { + if (!types_are_compatible(assign->lval->type, assign->expr->type)) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH, assign->base.token->pos, - assign->lval->type->name, assign->expr->type->name); + "TEMP", "TEMP"); return; } } @@ -57,14 +62,14 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode) { if (retnode->expr) { check_expression(state, retnode->expr); - if (retnode->expr->type != state->expected_return_type) { + if (!types_are_compatible(retnode->expr->type, state->expected_return_type)) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_FUNCTION_RETURN_MISMATCH, retnode->expr->token->pos, - retnode->expr->type->name, state->expected_return_type->name); + "TEMP", "TEMP"); } } else { - if (state->expected_return_type->size > 0) { + if (state->expected_return_type->Basic.size > 0) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, retnode->base.token->pos, @@ -75,7 +80,10 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode) { static void check_if(OnyxSemPassState* state, AstIf* ifnode) { check_expression(state, ifnode->cond); - if (ifnode->cond->type != &builtin_types[TYPE_INFO_KIND_BOOL]) { + + if (ifnode->cond->type->kind != Type_Kind_Basic + || ifnode->cond->type->Basic.kind != Basic_Kind_Bool) { + onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, ifnode->cond->token->pos, @@ -83,13 +91,16 @@ static void check_if(OnyxSemPassState* state, AstIf* ifnode) { return; } - if (ifnode->true_block.as_if) check_statement(state, (AstNode *) ifnode->true_block.as_block); + if (ifnode->true_block.as_if) check_statement(state, (AstNode *) ifnode->true_block.as_block); if (ifnode->false_block.as_if) check_statement(state, (AstNode *) ifnode->false_block.as_block); } static void check_while(OnyxSemPassState* state, AstWhile* whilenode) { check_expression(state, whilenode->cond); - if (whilenode->cond->type != &builtin_types[TYPE_INFO_KIND_BOOL]) { + + if (whilenode->cond->type->kind != Type_Kind_Basic + || whilenode->cond->type->Basic.kind != Basic_Kind_Bool) { + onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, whilenode->cond->token->pos, @@ -182,6 +193,9 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { onyx_token_null_toggle(callee->base.token); } + if (callee->base.type == NULL) { + callee->base.type = type_build_from_ast(state->node_allocator, callee->base.type_node); + } call->base.type = callee->base.type; AstLocal* formal_param = callee->params; @@ -191,13 +205,17 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { while (formal_param != NULL && actual_param != NULL) { check_expression(state, (AstTyped *) actual_param); - if (formal_param->base.type != actual_param->base.type) { + if (formal_param->base.type == NULL) { + formal_param->base.type = type_build_from_ast(state->node_allocator, formal_param->base.type_node); + } + + if (!types_are_compatible(formal_param->base.type, actual_param->base.type)) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_FUNCTION_PARAM_TYPE_MISMATCH, actual_param->value->token->pos, callee->base.token->text, callee->base.token->length, - formal_param->base.type->name, arg_pos, - actual_param->base.type->name); + "TEMP", arg_pos, + "TEMP"); return; } @@ -223,46 +241,59 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { } } -static void check_expression(OnyxSemPassState* state, AstTyped* expr) { - switch (expr->kind) { - case Ast_Kind_Binary_Op: - expr->type = &builtin_types[TYPE_INFO_KIND_UNKNOWN]; +static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { + check_expression(state, binop->left); + check_expression(state, binop->right); - check_expression(state, ((AstBinaryOp *) expr)->left); - check_expression(state, ((AstBinaryOp *) expr)->right); + if (binop->left->type == NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, + binop->base.token->pos, + NULL, 0); + return; + } - if (((AstBinaryOp *) expr)->left->type == NULL) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, - expr->token->pos, - NULL, 0); - return; - } + if (binop->right->type == NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, + binop->base.token->pos, + NULL, 0); + return; + } - if (((AstBinaryOp *) expr)->right->type == NULL) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, - expr->token->pos, - NULL, 0); - return; - } + if (binop->left->type->kind == Type_Kind_Pointer + || binop->right->type->kind == Type_Kind_Pointer) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + binop->base.token->pos, + "binary operations are not supported for pointers (yet)."); + return; + } - if (((AstBinaryOp *) expr)->left->type != ((AstBinaryOp *) expr)->right->type) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE, - expr->token->pos, - ((AstBinaryOp *) expr)->left->type->name, - ((AstBinaryOp *) expr)->right->type->name); - return; - } + if (!types_are_compatible(binop->left->type, binop->right->type)) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE, + binop->base.token->pos, + "TEMP", "TEMP"); + return; + } - if (((AstBinaryOp *) expr)->operation >= Binary_Op_Equal - && ((AstBinaryOp *) expr)->operation <= Binary_Op_Greater_Equal) { - expr->type = &builtin_types[TYPE_INFO_KIND_BOOL]; - } else { - expr->type = ((AstBinaryOp *) expr)->left->type; - } + if (binop->operation >= Binary_Op_Equal + && binop->operation <= Binary_Op_Greater_Equal) { + binop->base.type = &basic_types[Basic_Kind_Bool]; + } else { + binop->base.type = binop->left->type; + } +} +static void check_expression(OnyxSemPassState* state, AstTyped* expr) { + if (expr->type == NULL) { + expr->type = type_build_from_ast(state->node_allocator, expr->type_node); + } + + switch (expr->kind) { + case Ast_Kind_Binary_Op: + check_binaryop(state, (AstBinaryOp *) expr); break; case Ast_Kind_Unary_Op: @@ -289,7 +320,7 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) { case Ast_Kind_Local: case Ast_Kind_Param: - if (!expr->type->is_known) { + if (expr->type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, expr->token->pos, @@ -298,7 +329,7 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) { break; case Ast_Kind_Global: - if (!expr->type->is_known) { + if (expr->type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, expr->token->pos, @@ -314,7 +345,7 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) { case Ast_Kind_Literal: // NOTE: Literal types should have been decided // in the parser (for now). - assert(expr->type->is_known); + assert(expr->type != NULL); break; default: @@ -327,13 +358,17 @@ static void check_global(OnyxSemPassState* state, AstGlobal* global) { if (global->initial_value) { check_expression(state, global->initial_value); - if (global->base.type->is_known) { - if (global->base.type != global->initial_value->type) { + if (global->base.type == NULL) { + global->base.type = type_build_from_ast(state->node_allocator, global->base.type_node); + } + + if (global->base.type != NULL) { + if (!types_are_compatible(global->base.type, global->initial_value->type)) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_GLOBAL_TYPE_MISMATCH, global->base.token->pos, global->base.token->text, global->base.token->length, - global->base.type->name, global->initial_value->type->name); + "TEMP", "TEMP"); return; } } else { @@ -342,7 +377,7 @@ static void check_global(OnyxSemPassState* state, AstGlobal* global) { } } else { - if (!global->base.type || !global->base.type->is_known) { + if (global->base.type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, global->base.token->pos, @@ -375,7 +410,7 @@ static void check_block(OnyxSemPassState* state, AstBlock* block) { check_statement_chain(state, block->body); forll(AstLocal, local, block->locals->last_local, prev_local) { - if (!local->base.type->is_known) { + if (local->base.type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, local->base.token->pos, @@ -387,7 +422,11 @@ static void check_block(OnyxSemPassState* state, AstBlock* block) { static void check_function(OnyxSemPassState* state, AstFunction* func) { for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) { - if (!param->base.type->is_known) { + if (param->base.type == NULL) { + param->base.type = type_build_from_ast(state->node_allocator, param->base.type_node); + } + + if (param->base.type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, param->base.token->pos, @@ -395,7 +434,7 @@ static void check_function(OnyxSemPassState* state, AstFunction* func) { return; } - if (param->base.type->size == 0) { + if (param->base.type->Basic.size == 0) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_LITERAL, param->base.token->pos, @@ -404,6 +443,10 @@ static void check_function(OnyxSemPassState* state, AstFunction* func) { } } + if (func->base.type == NULL) { + func->base.type = type_build_from_ast(state->node_allocator, func->base.type_node); + } + state->expected_return_type = func->base.type; if (func->body) { check_block(state, func->body); diff --git a/src/onyxmsgs.c b/src/onyxmsgs.c index 4ef2848c..949adcf1 100644 --- a/src/onyxmsgs.c +++ b/src/onyxmsgs.c @@ -63,7 +63,7 @@ static void print_detailed_message(OnyxMessage* msg, bh_file_contents* fc) { void onyx_message_print(OnyxMessages* msgs) { OnyxMessage* msg = msgs->first; - i32 msg_count = 3; + i32 msg_count = 1000; while (msg && msg_count-- > 0) { if (msg->pos.filename) { diff --git a/src/onyxparser.c b/src/onyxparser.c index 0f5fb536..3356c981 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -6,27 +6,22 @@ // NOTE: The one weird define you need to know before read the code below #define make_node(nclass, kind) onyx_ast_node_new(parser->allocator, sizeof(nclass), kind) -struct TypeInfo builtin_types[] = { - { TYPE_INFO_KIND_UNKNOWN, 0, "unknown" }, - { TYPE_INFO_KIND_VOID, 0, "void", 0, 0, 0, 0, 1 }, - - { TYPE_INFO_KIND_BOOL, 1, "bool", 0, 1, 0, 1, 1 }, - - { TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0, 1 }, - { TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0, 1 }, - - { TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0, 1 }, - { TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0, 1 }, - - { TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0, 1 }, - { TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0, 1}, - { TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0, 1 }, - - { 0xffffffff } // Sentinel -}; - static AstNode error_node = { Ast_Kind_Error, 0, NULL, NULL }; +AstBasicType basic_type_void = { { Ast_Kind_Basic_Type, 0, "void" }, &basic_types[Basic_Kind_Void] }; +AstBasicType basic_type_bool = { { Ast_Kind_Basic_Type, 0, "bool" }, &basic_types[Basic_Kind_Bool] }; +AstBasicType basic_type_i8 = { { Ast_Kind_Basic_Type, 0, "i8" }, &basic_types[Basic_Kind_I8] }; +AstBasicType basic_type_u8 = { { Ast_Kind_Basic_Type, 0, "u8" }, &basic_types[Basic_Kind_U8] }; +AstBasicType basic_type_i16 = { { Ast_Kind_Basic_Type, 0, "i16" }, &basic_types[Basic_Kind_I16] }; +AstBasicType basic_type_u16 = { { Ast_Kind_Basic_Type, 0, "u16" }, &basic_types[Basic_Kind_U16] }; +AstBasicType basic_type_i32 = { { Ast_Kind_Basic_Type, 0, "i32" }, &basic_types[Basic_Kind_I32] }; +AstBasicType basic_type_u32 = { { Ast_Kind_Basic_Type, 0, "u32" }, &basic_types[Basic_Kind_U32] }; +AstBasicType basic_type_i64 = { { Ast_Kind_Basic_Type, 0, "i64" }, &basic_types[Basic_Kind_I64] }; +AstBasicType basic_type_u64 = { { Ast_Kind_Basic_Type, 0, "u64" }, &basic_types[Basic_Kind_U64] }; +AstBasicType basic_type_f32 = { { Ast_Kind_Basic_Type, 0, "f32" }, &basic_types[Basic_Kind_F32] }; +AstBasicType basic_type_f64 = { { Ast_Kind_Basic_Type, 0, "f64" }, &basic_types[Basic_Kind_F64] }; +AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, "rawptr" }, &basic_types[Basic_Kind_Rawptr] }; + // NOTE: Forward declarations static void parser_next_token(OnyxParser* parser); static void parser_prev_token(OnyxParser* parser); @@ -41,7 +36,7 @@ static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret); static AstReturn* parse_return_statement(OnyxParser* parser); static AstBlock* parse_block(OnyxParser* parser); static AstNode* parse_statement(OnyxParser* parser); -static AstNode* parse_type(OnyxParser* parser); +static AstType* parse_type(OnyxParser* parser); static AstLocal* parse_function_params(OnyxParser* parser); static AstFunction* parse_function_definition(OnyxParser* parser); static AstNode* parse_top_level_statement(OnyxParser* parser); @@ -94,33 +89,32 @@ static AstNumLit* parse_numeric_literal(OnyxParser* parser) { lit_node->base.flags |= Ast_Flag_Comptime; lit_node->value.l = 0ll; + AstType* type; onyx_token_null_toggle(lit_node->base.token); - - TypeInfo* type; char* tok = lit_node->base.token->text; // NOTE: charset_contains() behaves more like string_contains() // so I'm using it in this case if (charset_contains(tok, '.')) { if (tok[lit_node->base.token->length - 1] == 'f') { - type = &builtin_types[TYPE_INFO_KIND_FLOAT32]; + type = (AstType *) &basic_type_f32; lit_node->value.f = strtof(tok, NULL); } else { - type = &builtin_types[TYPE_INFO_KIND_FLOAT64]; + type = (AstType *) &basic_type_f64; lit_node->value.d = strtod(tok, NULL); } } else { i64 value = strtoll(tok, NULL, 0); if (bh_abs(value) < ((u64) 1 << 32)) { - type = &builtin_types[TYPE_INFO_KIND_INT32]; + type = (AstType *) &basic_type_i32; } else { - type = &builtin_types[TYPE_INFO_KIND_INT64]; + type = (AstType *) &basic_type_i64; } lit_node->value.l = value; } - lit_node->base.type = type; + lit_node->base.type_node = type; onyx_token_null_toggle(lit_node->base.token); return lit_node; } @@ -209,7 +203,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { case Token_Type_Literal_True: { AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal); - bool_node->base.type = &builtin_types[TYPE_INFO_KIND_BOOL]; + bool_node->base.type_node = (AstType *) &basic_type_i8; bool_node->base.token = expect(parser, Token_Type_Literal_True); bool_node->value.i = 1; retval = (AstTyped *) bool_node; @@ -219,7 +213,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { case Token_Type_Literal_False: { AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal); - bool_node->base.type = &builtin_types[TYPE_INFO_KIND_BOOL]; + bool_node->base.type_node = (AstType *) &basic_type_i8; bool_node->base.token = expect(parser, Token_Type_Literal_False); bool_node->value.i = 0; retval = (AstTyped *) bool_node; @@ -238,7 +232,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { parser_next_token(parser); AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op); - cast_node->base.type = parse_type(parser); + cast_node->base.type_node = parse_type(parser); cast_node->operation = Unary_Op_Cast; cast_node->expr = retval; retval = (AstTyped *) cast_node; @@ -398,16 +392,16 @@ static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) { case ':': { parser_next_token(parser); - TypeInfo* type = &builtin_types[TYPE_INFO_KIND_UNKNOWN]; + AstType* type_node = NULL; // NOTE: var: type if (parser->curr_token->type == Token_Type_Symbol) { - type = parse_type(parser); + type_node = parse_type(parser); } AstLocal* local = make_node(AstLocal, Ast_Kind_Local); local->base.token = symbol; - local->base.type = type; + local->base.type_node = type_node; local->base.flags |= Ast_Flag_Lval; // NOTE: DELETE *ret = (AstNode *) local; @@ -621,26 +615,40 @@ static AstBlock* parse_block(OnyxParser* parser) { return block; } -static TypeInfo* parse_type(OnyxParser* parser) { - TypeInfo* type_info = &builtin_types[TYPE_INFO_KIND_UNKNOWN]; +static AstType* parse_type(OnyxParser* parser) { + AstType* root = NULL; + AstType** next_insertion = &root; - OnyxToken* symbol = expect(parser, Token_Type_Symbol); - if (symbol == NULL) return type_info; + while (1) { + if (parser->curr_token->type == '^') { + AstPointerType* new = make_node(AstPointerType, Ast_Kind_Pointer_Type); + *next_insertion = (AstType *) new; + next_insertion = &new->elem; + } - onyx_token_null_toggle(symbol); + else if (parser->curr_token->type == Token_Type_Symbol) { + AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol); + symbol_node->token = expect(parser, Token_Type_Symbol); + *next_insertion = (AstType *) symbol_node; + next_insertion = NULL; + } - if (!bh_table_has(AstNode*, parser->identifiers, symbol->text)) { - onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_UNKNOWN_TYPE, symbol->pos, symbol->text); - } else { - AstTyped* type_info_node = bh_table_get(AstTyped*, parser->identifiers, symbol->text); + else { + onyx_token_null_toggle(parser->curr_token); + onyx_message_add(parser->msgs, + ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN, + parser->curr_token->pos, + parser->curr_token->text); + onyx_token_null_toggle(parser->curr_token); - if (type_info_node->kind == Ast_Kind_Type) { - type_info = type_info_node->type; + parser_next_token(parser); + break; } + + if (next_insertion == NULL) break; } - onyx_token_null_toggle(symbol); - return type_info; + return root; } static AstLocal* parse_function_params(OnyxParser* parser) { @@ -668,7 +676,7 @@ static AstLocal* parse_function_params(OnyxParser* parser) { curr_param = make_node(AstLocal, Ast_Kind_Param); curr_param->base.token = symbol; curr_param->base.flags |= Ast_Flag_Const; - curr_param->base.type = parse_type(parser); + curr_param->base.type_node = parse_type(parser); if (first_param == NULL) first_param = curr_param; @@ -727,10 +735,10 @@ static AstFunction* parse_function_definition(OnyxParser* parser) { if (parser->curr_token->type == Token_Type_Right_Arrow) { expect(parser, Token_Type_Right_Arrow); - TypeInfo* return_type = parse_type(parser); - func_def->base.type = return_type; + AstType* return_type = parse_type(parser); + func_def->base.type_node = return_type; } else { - func_def->base.type = &builtin_types[TYPE_INFO_KIND_VOID]; + func_def->base.type_node = (AstType *) &basic_type_void; } func_def->body = parse_block(parser); @@ -749,10 +757,10 @@ static AstNode* parse_foreign(OnyxParser* parser) { foreign->import = (AstNode *) parse_function_definition(parser); } else { - TypeInfo* type = parse_type(parser); + AstType* type = parse_type(parser); AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); - global->base.type = type; + global->base.type_node = type; global->base.flags |= Ast_Flag_Lval; foreign->import = (AstNode *) global; @@ -776,7 +784,6 @@ static AstNode* parse_top_level_constant_symbol(OnyxParser* parser) { // Global constant with initial value AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); global->initial_value = parse_expression(parser); - global->base.type = &builtin_types[TYPE_INFO_KIND_UNKNOWN]; global->base.flags |= Ast_Flag_Const; global->base.flags |= Ast_Flag_Lval; global->base.flags |= Ast_Flag_Comptime; @@ -820,7 +827,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) { expect(parser, ':'); - TypeInfo* type = &builtin_types[TYPE_INFO_KIND_UNKNOWN]; + AstType* type = NULL; if (parser->curr_token->type == Token_Type_Symbol) { type = parse_type(parser); @@ -832,7 +839,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) { AstNode* node = parse_top_level_constant_symbol(parser); if (node->kind == Ast_Kind_Global) { - ((AstGlobal *) node)->base.type = type; + ((AstGlobal *) node)->base.type_node = type; } if (node->kind == Ast_Kind_Foreign) { @@ -851,7 +858,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) { global->base.token = symbol; global->base.flags |= Ast_Flag_Lval; global->initial_value = parse_expression(parser); - global->base.type = type; + global->base.type_node = type; return (AstNode *) global; @@ -891,16 +898,6 @@ void* onyx_ast_node_new(bh_allocator alloc, i32 size, AstKind kind) { OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs) { OnyxParser parser; - bh_table_init(bh_heap_allocator(), parser.identifiers, 61); - - TypeInfo* it = &builtin_types[0]; - while (it->kind != 0xffffffff) { - AstTyped* tmp = onyx_ast_node_new(alloc, sizeof(AstTyped), Ast_Kind_Type); - tmp->type = it; - bh_table_put(AstNode*, parser.identifiers, (char *)it->name, tmp); - it++; - } - parser.allocator = alloc; parser.tokenizer = tokenizer; parser.curr_token = tokenizer->tokens; @@ -909,7 +906,6 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, Onyx } void onyx_parser_free(OnyxParser* parser) { - bh_table_free(parser->identifiers); } bh_arr(AstNode *) onyx_parse(OnyxParser *parser) { diff --git a/src/onyxsymres.c b/src/onyxsymres.c index e3a19b5d..06e43044 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -2,6 +2,7 @@ #include "onyxsempass.h" static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol); +static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* basic_type); static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol); static void symbol_remove(OnyxSemPassState* state, AstNode* symbol); static AstNode* symbol_resolve(OnyxSemPassState* state, AstNode* symbol); @@ -9,7 +10,7 @@ static void local_group_enter(OnyxSemPassState* state, AstLocalGroup* local_grou static void local_group_leave(OnyxSemPassState* state); static void symres_local(OnyxSemPassState* state, AstLocal** local); static void symres_call(OnyxSemPassState* state, AstCall* call); -static void symres_expression(OnyxSemPassState* state, AstNode** expr); +static void symres_expression(OnyxSemPassState* state, AstTyped** expr); static void symres_assignment(OnyxSemPassState* state, AstAssign* assign); static void symres_return(OnyxSemPassState* state, AstReturn* ret); static void symres_if(OnyxSemPassState* state, AstIf* ifnode); @@ -18,6 +19,7 @@ static void symres_statement_chain(OnyxSemPassState* state, AstNode* walker, Ast static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt); static void symres_block(OnyxSemPassState* state, AstBlock* block); static void symres_function(OnyxSemPassState* state, AstFunction* func); +static AstType* symres_type(OnyxSemPassState* state, AstType* type); static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol) { onyx_token_null_toggle(symbol->token); @@ -89,6 +91,13 @@ static void local_group_leave(OnyxSemPassState* state) { state->curr_local_group = state->curr_local_group->prev_group; } +static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* basic_type) { + SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol); + sp_sym->node = (AstNode *) basic_type; + sp_sym->shadowed = NULL; + bh_table_put(SemPassSymbol *, state->symbols, basic_type->base.name, sp_sym); +} + static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol) { onyx_token_null_toggle(symbol->token); @@ -113,7 +122,27 @@ static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol) { return 1; } +static AstType* symres_type(OnyxSemPassState* state, AstType* type) { + if (type == NULL) return NULL; + + if (type->kind == Ast_Kind_Symbol) { + return (AstType *) symbol_resolve(state, (AstNode *) type); + } + + // NOTE: Already resolved + if (type->kind == Ast_Kind_Basic_Type) return type; + + if (type->kind == Ast_Kind_Pointer_Type) { + ((AstPointerType *) type)->elem = symres_type(state, ((AstPointerType *) type)->elem); + return type; + } + + assert(("Bad type node", 0)); + return NULL; +} + static void symres_local(OnyxSemPassState* state, AstLocal** local) { + (*local)->base.type_node = symres_type(state, (*local)->base.type_node); symbol_introduce(state, (AstNode *) *local); } @@ -125,15 +154,23 @@ static void symres_call(OnyxSemPassState* state, AstCall* call) { symres_statement_chain(state, (AstNode *) call->arguments, (AstNode **) &call->arguments); } -static void symres_expression(OnyxSemPassState* state, AstNode** expr) { +static void symres_unaryop(OnyxSemPassState* state, AstUnaryOp** unaryop) { + if ((*unaryop)->operation == Unary_Op_Cast) { + (*unaryop)->base.type_node = symres_type(state, (*unaryop)->base.type_node); + } + + symres_expression(state, &(*unaryop)->expr); +} + +static void symres_expression(OnyxSemPassState* state, AstTyped** expr) { switch ((*expr)->kind) { case Ast_Kind_Binary_Op: - symres_expression(state, (AstNode **) &((AstBinaryOp *)(*expr))->left); - symres_expression(state, (AstNode **) &((AstBinaryOp *)(*expr))->right); + symres_expression(state, &((AstBinaryOp *)(*expr))->left); + symres_expression(state, &((AstBinaryOp *)(*expr))->right); break; case Ast_Kind_Unary_Op: - symres_expression(state, (AstNode **) &((AstUnaryOp *)(*expr))->expr); + symres_unaryop(state, (AstUnaryOp **) expr); break; case Ast_Kind_Call: symres_call(state, (AstCall *) *expr); break; @@ -141,13 +178,15 @@ static void symres_expression(OnyxSemPassState* state, AstNode** expr) { case Ast_Kind_Block: symres_block(state, (AstBlock *) *expr); break; case Ast_Kind_Symbol: - *expr = symbol_resolve(state, *expr); + *expr = (AstTyped *) symbol_resolve(state, (AstNode *) *expr); break; // NOTE: This is a good case, since it means the symbol is already resolved case Ast_Kind_Local: break; - case Ast_Kind_Literal: break; + case Ast_Kind_Literal: + (*expr)->type_node = symres_type(state, (*expr)->type_node); + break; default: DEBUG_HERE; @@ -160,16 +199,16 @@ static void symres_assignment(OnyxSemPassState* state, AstAssign* assign) { if (lval == NULL) return; assign->lval = lval; - symres_expression(state, (AstNode **) &assign->expr); + symres_expression(state, &assign->expr); } static void symres_return(OnyxSemPassState* state, AstReturn* ret) { if (ret->expr) - symres_expression(state, (AstNode **) &ret->expr); + symres_expression(state, &ret->expr); } static void symres_if(OnyxSemPassState* state, AstIf* ifnode) { - symres_expression(state, (AstNode **) &ifnode->cond); + symres_expression(state, &ifnode->cond); if (ifnode->true_block.as_if != NULL) { if (ifnode->true_block.as_if->base.kind == Ast_Kind_Block) symres_block(state, ifnode->true_block.as_block); @@ -192,7 +231,7 @@ static void symres_if(OnyxSemPassState* state, AstIf* ifnode) { } static void symres_while(OnyxSemPassState* state, AstWhile* whilenode) { - symres_expression(state, (AstNode **) &whilenode->cond); + symres_expression(state, &whilenode->cond); symres_block(state, whilenode->body); } @@ -205,7 +244,7 @@ static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt) { case Ast_Kind_If: symres_if(state, (AstIf *) stmt); return 0; case Ast_Kind_While: symres_while(state, (AstWhile *) stmt); return 0; case Ast_Kind_Call: symres_call(state, (AstCall *) stmt); return 0; - case Ast_Kind_Argument: symres_expression(state, (AstNode **) &((AstArgument *)stmt)->value); return 0; + case Ast_Kind_Argument: symres_expression(state, (AstTyped **) &((AstArgument *)stmt)->value); return 0; case Ast_Kind_Block: symres_block(state, (AstBlock *) stmt); return 0; default: return 0; @@ -236,9 +275,17 @@ static void symres_block(OnyxSemPassState* state, AstBlock* block) { static void symres_function(OnyxSemPassState* state, AstFunction* func) { for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) { + param->base.type_node = symres_type(state, param->base.type_node); + symbol_introduce(state, (AstNode *) param); } + if (func->base.type_node != NULL) { + if (func->base.type_node->kind == Ast_Kind_Symbol) { + func->base.type_node = symres_type(state, func->base.type_node); + } + } + symres_block(state, func->body); for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) { @@ -248,7 +295,22 @@ static void symres_function(OnyxSemPassState* state, AstFunction* func) { void onyx_resolve_symbols(OnyxSemPassState* state, OnyxProgram* program) { - // NOTE: First, introduce all global symbols + // NOTE: Add types to global scope + symbol_basic_type_introduce(state, &basic_type_void); + symbol_basic_type_introduce(state, &basic_type_bool); + symbol_basic_type_introduce(state, &basic_type_i8); + symbol_basic_type_introduce(state, &basic_type_u8); + symbol_basic_type_introduce(state, &basic_type_i16); + symbol_basic_type_introduce(state, &basic_type_u16); + symbol_basic_type_introduce(state, &basic_type_i32); + symbol_basic_type_introduce(state, &basic_type_u32); + symbol_basic_type_introduce(state, &basic_type_i64); + symbol_basic_type_introduce(state, &basic_type_u64); + symbol_basic_type_introduce(state, &basic_type_f32); + symbol_basic_type_introduce(state, &basic_type_f64); + symbol_basic_type_introduce(state, &basic_type_rawptr); + + // NOTE: Introduce all global symbols bh_arr_each(AstGlobal *, global, program->globals) if (!symbol_unique_introduce(state, (AstNode *) *global)) return; diff --git a/src/onyxtypes.c b/src/onyxtypes.c index eee00a7d..f70a2710 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -1,5 +1,7 @@ #include "onyxtypes.h" +#include "onyxastnodes.h" +// NOTE: These have to be in the same order as Basiuc Type basic_types[] = { { Type_Kind_Basic, { Basic_Kind_Void, 0, 0, "void" } }, @@ -47,3 +49,26 @@ b32 types_are_compatible(Type* t1, Type* t2) { return 0; } + +Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { + if (type_node == NULL) return NULL; + + switch (type_node->kind) { + case Ast_Kind_Pointer_Type: { + TypePointer* ptr_type = bh_alloc_item(alloc, TypePointer); + + ptr_type->base.flags |= Basic_Flag_Pointer; + ptr_type->base.size = 4; + ptr_type->elem = type_build_from_ast(alloc, ((AstPointerType *) type_node)->elem); + + return (Type *) ptr_type; + } + + case Ast_Kind_Basic_Type: + return ((AstBasicType *) type_node)->type; + + default: + assert(("Node is not a type node", 0)); + return NULL; + } +} diff --git a/src/onyxwasm.c b/src/onyxwasm.c index aaee1bbb..9eb365a0 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -195,15 +195,23 @@ static const char* wi_string(WasmInstructionType wit) { } } -static WasmType onyx_type_to_wasm_type(TypeInfo* type) { - if (type->is_bool) return WASM_TYPE_INT32; - else if (type->is_int) { - if (type->size == 4) return WASM_TYPE_INT32; - if (type->size == 8) return WASM_TYPE_INT64; +static WasmType onyx_type_to_wasm_type(Type* type) { + if (type->kind == Type_Kind_Pointer) { + return WASM_TYPE_INT32; } - else if (type->is_float) { - if (type->size == 4) return WASM_TYPE_FLOAT32; - if (type->size == 8) return WASM_TYPE_FLOAT64; + + if (type->kind == Type_Kind_Basic) { + TypeBasic* basic = &type->Basic; + if (basic->flags & Basic_Flag_Boolean) return WASM_TYPE_INT32; + if (basic->flags & Basic_Flag_Integer) { + if (basic->size <= 4) return WASM_TYPE_INT32; + if (basic->size == 8) return WASM_TYPE_INT64; + } + if (basic->flags & Basic_Flag_Float) { + if (basic->size <= 4) return WASM_TYPE_FLOAT32; + if (basic->size == 8) return WASM_TYPE_FLOAT64;; + } + if (basic->size == 0) return WASM_TYPE_VOID; } return WASM_TYPE_VOID; @@ -457,7 +465,7 @@ static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A // Unsigned instructions are always right after // the signed equivalent if (is_sign_significant) { - if (binop->left->type->is_unsigned) { + if (binop->left->type->Basic.flags & Basic_Flag_Unsigned) { binop_instr = (WasmInstructionType) ((i32) binop_instr + 1); } } @@ -476,25 +484,29 @@ static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, switch (unop->operation) { case Unary_Op_Negate: { - TypeInfoKind type_kind = unop->base.type->kind; + TypeBasic* type = &unop->base.type->Basic; - if (type_kind == TYPE_INFO_KIND_INT32) { + if (type->kind == Basic_Kind_I32 + || type->kind == Basic_Kind_I16 + || type->kind == Basic_Kind_I8) { WID(WI_I32_CONST, 0x00); compile_expression(mod, &code, unop->expr); WI(WI_I32_SUB); - } else if (type_kind == TYPE_INFO_KIND_INT64) { + } + else if (type->kind == Basic_Kind_I64) { WID(WI_I64_CONST, 0x00); compile_expression(mod, &code, unop->expr); WI(WI_I64_SUB); - } else { + } + else { compile_expression(mod, &code, unop->expr); - if (type_kind == TYPE_INFO_KIND_FLOAT32) + if (type->kind == Basic_Kind_F32) WI(WI_F32_NEG); - if (type_kind == TYPE_INFO_KIND_FLOAT64) + if (type->kind == Basic_Kind_F64) WI(WI_F64_NEG); } @@ -687,28 +699,34 @@ static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, As compile_expression(mod, &code, cast->expr); - TypeInfo* from = cast->expr->type; - TypeInfo* to = cast->base.type; + Type* from = cast->expr->type; + Type* to = cast->base.type; i32 fromidx = 0, toidx = 0; - if (from->is_int) { - if (from->size == 4 && !from->is_unsigned) fromidx = 0; - else if (from->size == 4 && from->is_unsigned) fromidx = 1; - else if (from->size == 8 && !from->is_unsigned) fromidx = 2; - else if (from->size == 8 && from->is_unsigned) fromidx = 3; - } else if (from->is_float) { - if (from->size == 4) fromidx = 4; - else if (from->size == 8) fromidx = 5; + if (from->Basic.flags & Basic_Flag_Numeric) { + b32 unsign = (from->Basic.flags & Basic_Flag_Unsigned) != 0; + + if (from->Basic.size == 4 && !unsign) fromidx = 0; + else if (from->Basic.size == 4 && unsign) fromidx = 1; + else if (from->Basic.size == 8 && !unsign) fromidx = 2; + else if (from->Basic.size == 8 && unsign) fromidx = 3; + } + else if (from->Basic.flags & Basic_Flag_Float) { + if (from->Basic.size == 4) fromidx = 4; + else if (from->Basic.size == 8) fromidx = 5; } - if (to->is_int) { - if (to->size == 4 && !to->is_unsigned) toidx = 0; - else if (to->size == 4 && to->is_unsigned) toidx = 1; - else if (to->size == 8 && !to->is_unsigned) toidx = 2; - else if (to->size == 8 && to->is_unsigned) toidx = 3; - } else if (to->is_float) { - if (to->size == 4) toidx = 4; - else if (to->size == 8) toidx = 5; + if (to->Basic.flags & Basic_Flag_Numeric) { + b32 unsign = (to->Basic.flags & Basic_Flag_Unsigned) != 0; + + if (to->Basic.size == 4 && !unsign) toidx = 0; + else if (to->Basic.size == 4 && unsign) toidx = 1; + else if (to->Basic.size == 8 && !unsign) toidx = 2; + else if (to->Basic.size == 8 && unsign) toidx = 3; + } + else if (to->Basic.flags & Basic_Flag_Float) { + if (to->Basic.size == 4) toidx = 4; + else if (to->Basic.size == 8) toidx = 5; } WasmInstructionType cast_op = cast_map[fromidx][toidx];