From: Brendan Hansen Date: Fri, 17 Jul 2020 22:08:05 +0000 (-0500) Subject: Added simple array mechanics; Cleaned up code in the process X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=3f07fa7e41b23d7165c9f750f24e50ac1190ed95;p=onyx.git Added simple array mechanics; Cleaned up code in the process --- diff --git a/.vimspector.json b/.vimspector.json index 88493853..404230c7 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -6,7 +6,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/onyx", - "args": ["progs/basic.onyx"], + "args": ["progs/arrays.onyx"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/include/bh.h b/include/bh.h index e443f27b..4b1b07b5 100644 --- a/include/bh.h +++ b/include/bh.h @@ -94,12 +94,32 @@ inline i64 chars_match(char* ptr1, char* ptr2) { //------------------------------------------------------------------------------------- // Better math functions //------------------------------------------------------------------------------------- -#define bh_max(a, b) ((a) > (b) ? (a) : (b)) -#define bh_min(a, b) ((a) < (b) ? (a) : (b)) +#define bh_max(a, b) ((a) > (b) ? (a) : (b)) +#define bh_min(a, b) ((a) < (b) ? (a) : (b)) #define bh_clamp(v, a, b) (bh_min((b), bh_max((a), (v)))) #define bh_abs(x) ((x) < 0 ? -(x) : (x)) - +static inline u64 log2_dumb(u64 n) { + switch (n) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 8: return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + case 128: return 7; + case 256: return 8; + case 512: return 9; + case 1024: return 10; + case 2048: return 11; + case 4096: return 12; + case 8192: return 13; + + // Don't need all of them right now + default: return 0; + } +} diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 1d2293b1..6e3a2366 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -6,15 +6,18 @@ typedef struct AstNode AstNode; typedef struct AstTyped AstTyped; -typedef struct AstUnaryOp AstUnaryOp; + typedef struct AstBinOp AstBinaryOp; -typedef struct AstAssign AstAssign; +typedef struct AstUnaryOp AstUnaryOp; typedef struct AstNumLit AstNumLit; typedef struct AstLocal AstLocal; -typedef struct AstReturn AstReturn; typedef struct AstCall AstCall; typedef struct AstIntrinsicCall AstIntrinsicCall; typedef struct AstArgument AstArgument; +typedef struct AstArrayAccess AstArrayAccess; + +typedef struct AstAssign AstAssign; +typedef struct AstReturn AstReturn; typedef struct AstBlock AstBlock; typedef struct AstIf AstIf; @@ -61,8 +64,8 @@ typedef enum AstKind { Ast_Kind_Argument, Ast_Kind_Call, Ast_Kind_Intrinsic_Call, - Ast_Kind_Assignment, Ast_Kind_Return, + Ast_Kind_Array_Access, Ast_Kind_If, Ast_Kind_While, @@ -77,14 +80,16 @@ typedef enum AstKind { typedef enum AstFlags { // Top-level flags Ast_Flag_Exported = BH_BIT(0), - Ast_Flag_Lval = BH_BIT(1), + Ast_Flag_Foreign = BH_BIT(1), Ast_Flag_Const = BH_BIT(2), Ast_Flag_Comptime = BH_BIT(3), // Function flags Ast_Flag_Inline = BH_BIT(8), Ast_Flag_Intrinsic = BH_BIT(9), - Ast_Flag_Foreign = BH_BIT(10), + + // Expression flags + Ast_Flag_Expr_Ignored = BH_BIT(8), } AstFlags; typedef enum UnaryOp { @@ -94,20 +99,57 @@ typedef enum UnaryOp { } UnaryOp; typedef enum BinaryOp { - Binary_Op_Add = 0, - Binary_Op_Minus = 1, - Binary_Op_Multiply = 2, - Binary_Op_Divide = 3, - Binary_Op_Modulus = 4, - - Binary_Op_Equal = 5, - Binary_Op_Not_Equal = 6, - Binary_Op_Less = 7, - Binary_Op_Less_Equal = 8, - Binary_Op_Greater = 9, - Binary_Op_Greater_Equal = 10, + Binary_Op_Add = 0, + Binary_Op_Minus = 1, + Binary_Op_Multiply = 2, + Binary_Op_Divide = 3, + Binary_Op_Modulus = 4, + + Binary_Op_Equal = 5, + Binary_Op_Not_Equal = 6, + Binary_Op_Less = 7, + Binary_Op_Less_Equal = 8, + Binary_Op_Greater = 9, + Binary_Op_Greater_Equal = 10, + + Binary_Op_Assign_Start = 11, + Binary_Op_Assign = 12, + Binary_Op_Assign_Add = 13, + Binary_Op_Assign_Minus = 14, + Binary_Op_Assign_Multiply = 15, + Binary_Op_Assign_Divide = 16, + Binary_Op_Assign_Modulus = 17, + Binary_Op_Assign_End = 18, } BinaryOp; +typedef enum OnyxIntrinsic { + ONYX_INTRINSIC_UNDEFINED, + + ONYX_INTRINSIC_MEMORY_SIZE, ONYX_INTRINSIC_MEMORY_GROW, + + ONYX_INTRINSIC_I32_CLZ, ONYX_INTRINSIC_I32_CTZ, ONYX_INTRINSIC_I32_POPCNT, + ONYX_INTRINSIC_I32_AND, ONYX_INTRINSIC_I32_OR, ONYX_INTRINSIC_I32_XOR, + ONYX_INTRINSIC_I32_SHL, ONYX_INTRINSIC_I32_SLR, ONYX_INTRINSIC_I32_SAR, + ONYX_INTRINSIC_I32_ROTL, ONYX_INTRINSIC_I32_ROTR, + + ONYX_INTRINSIC_I64_CLZ, ONYX_INTRINSIC_I64_CTZ, ONYX_INTRINSIC_I64_POPCNT, + ONYX_INTRINSIC_I64_AND, ONYX_INTRINSIC_I64_OR, ONYX_INTRINSIC_I64_XOR, + ONYX_INTRINSIC_I64_SHL, ONYX_INTRINSIC_I64_SLR, ONYX_INTRINSIC_I64_SAR, + ONYX_INTRINSIC_I64_ROTL, ONYX_INTRINSIC_I64_ROTR, + + ONYX_INTRINSIC_F32_ABS, ONYX_INTRINSIC_F32_SQRT, + ONYX_INTRINSIC_F32_CEIL, ONYX_INTRINSIC_F32_FLOOR, + ONYX_INTRINSIC_F32_TRUNC, ONYX_INTRINSIC_F32_NEAREST, + ONYX_INTRINSIC_F32_MIN, ONYX_INTRINSIC_F32_MAX, + ONYX_INTRINSIC_F32_COPYSIGN, + + ONYX_INTRINSIC_F64_ABS, ONYX_INTRINSIC_F64_SQRT, + ONYX_INTRINSIC_F64_CEIL, ONYX_INTRINSIC_F64_FLOOR, + ONYX_INTRINSIC_F64_TRUNC, ONYX_INTRINSIC_F64_NEAREST, + ONYX_INTRINSIC_F64_MIN, ONYX_INTRINSIC_F64_MAX, + ONYX_INTRINSIC_F64_COPYSIGN, +} OnyxIntrinsic; + // Base Nodes #define AstNode_members { \ @@ -141,12 +183,15 @@ struct AstTyped AstTyped_members; // 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 AstIntrinsicCall { AstTyped_base; AstArgument *arguments; OnyxIntrinsic intrinsic; }; struct AstArgument { AstTyped_base; AstTyped *value; }; +struct AstArrayAccess { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; }; + +// Intruction Node +struct AstReturn { AstNode_base; AstTyped* expr; }; // Structure Nodes struct AstLocalGroup { AstNode_base; AstLocalGroup *prev_group; AstLocal *last_local; }; @@ -211,38 +256,6 @@ struct AstFunction { }; }; -typedef enum OnyxIntrinsic { - ONYX_INTRINSIC_UNDEFINED, - - ONYX_INTRINSIC_MEMORY_SIZE, ONYX_INTRINSIC_MEMORY_GROW, - - ONYX_INTRINSIC_I32_CLZ, ONYX_INTRINSIC_I32_CTZ, ONYX_INTRINSIC_I32_POPCNT, - ONYX_INTRINSIC_I32_AND, ONYX_INTRINSIC_I32_OR, ONYX_INTRINSIC_I32_XOR, - ONYX_INTRINSIC_I32_SHL, ONYX_INTRINSIC_I32_SLR, ONYX_INTRINSIC_I32_SAR, - ONYX_INTRINSIC_I32_ROTL, ONYX_INTRINSIC_I32_ROTR, - - ONYX_INTRINSIC_I64_CLZ, ONYX_INTRINSIC_I64_CTZ, ONYX_INTRINSIC_I64_POPCNT, - ONYX_INTRINSIC_I64_AND, ONYX_INTRINSIC_I64_OR, ONYX_INTRINSIC_I64_XOR, - ONYX_INTRINSIC_I64_SHL, ONYX_INTRINSIC_I64_SLR, ONYX_INTRINSIC_I64_SAR, - ONYX_INTRINSIC_I64_ROTL, ONYX_INTRINSIC_I64_ROTR, - - ONYX_INTRINSIC_F32_ABS, ONYX_INTRINSIC_F32_SQRT, - ONYX_INTRINSIC_F32_CEIL, ONYX_INTRINSIC_F32_FLOOR, - ONYX_INTRINSIC_F32_TRUNC, ONYX_INTRINSIC_F32_NEAREST, - ONYX_INTRINSIC_F32_MIN, ONYX_INTRINSIC_F32_MAX, - ONYX_INTRINSIC_F32_COPYSIGN, - - ONYX_INTRINSIC_F64_ABS, ONYX_INTRINSIC_F64_SQRT, - ONYX_INTRINSIC_F64_CEIL, ONYX_INTRINSIC_F64_FLOOR, - ONYX_INTRINSIC_F64_TRUNC, ONYX_INTRINSIC_F64_NEAREST, - ONYX_INTRINSIC_F64_MIN, ONYX_INTRINSIC_F64_MAX, - ONYX_INTRINSIC_F64_COPYSIGN, -} OnyxIntrinsic; - -// NOTE: This needs to have 'arguments' in the -// same position as AstNodeCall -struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; OnyxIntrinsic intrinsic; }; - // NOTE: Simple data structure for storing what comes out of the parser typedef struct ParserOutput { bh_arr(AstBinding *) top_level_bindings; @@ -271,4 +284,17 @@ extern AstBasicType basic_type_f32; extern AstBasicType basic_type_f64; extern AstBasicType basic_type_rawptr; + +// NOTE: Useful inlined functions +static inline b32 is_lval(AstNode* node) { + return (node->kind == Ast_Kind_Local) + || (node->kind == Ast_Kind_Global) + || (node->kind == Ast_Kind_Array_Access); +} + +static inline b32 binop_is_assignment(AstBinaryOp* binop) { + return (binop->operation >= Binary_Op_Assign_Start + && binop->operation <= Binary_Op_Assign_End); +} + #endif // #ifndef ONYXASTNODES_H diff --git a/onyx b/onyx index 8457bd02..a645223c 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/arrays.onyx b/progs/arrays.onyx new file mode 100644 index 00000000..0db8ba95 --- /dev/null +++ b/progs/arrays.onyx @@ -0,0 +1,23 @@ +use "progs/intrinsics" +use "progs/print_funcs" + +main :: proc #export { + print_i32(memory_size()); + + arr := 0 as ^i64; + + arr[0] = 10 as i64; + arr[1] = 20 as i64; + arr[2] = 30 as i64; + arr[3] = 40 as i64; + + i := 0; + while i < 4 { + arr[i] += 1 as i64; + arr[i] *= 2 as i64; + + print_i64(arr[i]); + i += 1; + } +} + diff --git a/progs/basic.onyx b/progs/basic.onyx index caed8770..5b9de01f 100644 --- a/progs/basic.onyx +++ b/progs/basic.onyx @@ -31,7 +31,7 @@ global_value :: 5 * 2 + 6 wasm_global :: global i32 main :: proc #export { - a := 16; + a : i32 = 16; print(clz_i32(a)); wasm_global = 5 + global_value; @@ -40,7 +40,7 @@ main :: proc #export { print(4 + global_value); b := 1 + foo(2); - if b == 13 b = 10; + if b == 13 b += 10; print(b); if b == 13 print(5678); diff --git a/progs/intrinsics.onyx b/progs/intrinsics.onyx index ceece40f..cb4fce4d 100644 --- a/progs/intrinsics.onyx +++ b/progs/intrinsics.onyx @@ -1,5 +1,5 @@ memory_size :: proc #intrinsic -> i32 --- -memory_grow :: proc #intrinsic -> i32 --- +memory_grow :: proc #intrinsic (val: i32) -> i32 --- clz_i32 :: proc #intrinsic (val: i32) -> i32 --- ctz_i32 :: proc #intrinsic (val: i32) -> i32 --- diff --git a/src/onyxchecker.c b/src/onyxchecker.c index ec81e35f..97b18cb7 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -1,66 +1,20 @@ #define BH_DEBUG #include "onyxsempass.h" +#include "onyxparser.h" static b32 check_function(SemState* state, AstFunction* func); static b32 check_block(SemState* state, AstBlock* block); static b32 check_statement_chain(SemState* state, AstNode* start); static b32 check_statement(SemState* state, AstNode* stmt); -static b32 check_assignment(SemState* state, AstAssign* assign); static b32 check_return(SemState* state, AstReturn* retnode); static b32 check_if(SemState* state, AstIf* ifnode); static b32 check_while(SemState* state, AstWhile* whilenode); static b32 check_call(SemState* state, AstCall* call); static b32 check_binaryop(SemState* state, AstBinaryOp* binop); static b32 check_expression(SemState* state, AstTyped* expr); +static b32 check_array_access(SemState* state, AstArrayAccess* expr); static b32 check_global(SemState* state, AstGlobal* global); -static b32 check_assignment(SemState* state, AstAssign* assign) { - if (assign->lval->kind == Ast_Kind_Symbol) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, - assign->lval->token->pos, - assign->lval->token->text, assign->lval->token->length); - return 1; - } - - if ((assign->lval->flags & Ast_Flag_Const) != 0 && assign->lval->type != NULL) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_ASSIGN_CONST, - assign->token->pos, - assign->lval->token->text, assign->lval->token->length); - return 1; - } - - if ((assign->lval->flags & Ast_Flag_Lval) == 0) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_NOT_LVAL, - assign->token->pos, - assign->lval->token->text, assign->lval->token->length); - return 1; - } - - if (assign->lval->type == NULL) { - assign->lval->type = type_build_from_ast(state->node_allocator, assign->lval->type_node); - } - - if (check_expression(state, assign->expr)) return 1; - - if (assign->lval->type == NULL) { - assign->lval->type = assign->expr->type; - } else { - if (!types_are_compatible(assign->lval->type, assign->expr->type)) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH, - assign->token->pos, - type_get_name(assign->lval->type), - type_get_name(assign->expr->type)); - return 1; - } - } - - return 0; -} - static b32 check_return(SemState* state, AstReturn* retnode) { if (retnode->expr) { if (check_expression(state, retnode->expr)) return 1; @@ -255,6 +209,63 @@ static b32 check_binaryop(SemState* state, AstBinaryOp* binop) { if (check_expression(state, binop->left)) return 1; if (check_expression(state, binop->right)) return 1; + if (binop_is_assignment(binop)) { + if (!is_lval((AstNode *) binop->left)) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_NOT_LVAL, + binop->token->pos, + binop->left->token->text, binop->left->token->length); + return 1; + } + + if ((binop->left->flags & Ast_Flag_Const) != 0 && binop->left->type != NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_ASSIGN_CONST, + binop->token->pos, + binop->left->token->text, binop->left->token->length); + return 1; + } + + if (binop->operation == Binary_Op_Assign) { + // NOTE: Raw assignment + if (binop->left->type == NULL) { + binop->left->type = binop->right->type; + } + + } else { + // NOTE: +=, -=, ... + + AstBinaryOp* binop_node = onyx_ast_node_new( + state->node_allocator, + sizeof(AstBinaryOp), + Ast_Kind_Binary_Op); + + binop_node->token = binop->token; + binop_node->left = binop->left; + binop_node->right = binop->right; + binop_node->type = binop->right->type; + + 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; + + binop->right = (AstTyped *) binop_node; + binop->operation = Binary_Op_Assign; + } + + } else { + if (type_is_pointer(binop->left->type) + || type_is_pointer(binop->right->type)) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + binop->token->pos, + "binary operations are not supported for pointers (yet)."); + return 1; + } + } + if (binop->left->type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, @@ -271,14 +282,6 @@ static b32 check_binaryop(SemState* state, AstBinaryOp* binop) { return 1; } - if (type_is_pointer(binop->left->type) - || type_is_pointer(binop->right->type)) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_LITERAL, - binop->token->pos, - "binary operations are not supported for pointers (yet)."); - return 1; - } if (!types_are_compatible(binop->left->type, binop->right->type)) { onyx_message_add(state->msgs, @@ -299,6 +302,33 @@ static b32 check_binaryop(SemState* state, AstBinaryOp* binop) { return 0; } +static b32 check_array_access(SemState* state, AstArrayAccess* aa) { + check_expression(state, aa->addr); + check_expression(state, aa->expr); + + if (!type_is_pointer(aa->addr->type)) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + aa->addr->token->pos, + "expected pointer type for left of array access"); + return 1; + } + + if (aa->expr->type->kind != Type_Kind_Basic + || (aa->expr->type->Basic.flags & Basic_Flag_Integer) == 0) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + aa->expr->token->pos, + "expected integer type for index"); + return 1; + } + + aa->type = aa->addr->type->Pointer.elem; + aa->elem_size = aa->type->Basic.size; + + return 0; +} + static b32 check_expression(SemState* state, AstTyped* expr) { if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) { onyx_message_add(state->msgs, @@ -335,7 +365,6 @@ static b32 check_expression(SemState* state, AstTyped* expr) { retval = 1; break; - case Ast_Kind_Local: case Ast_Kind_Param: if (expr->type == NULL) { onyx_message_add(state->msgs, @@ -346,6 +375,12 @@ static b32 check_expression(SemState* state, AstTyped* expr) { } break; + case Ast_Kind_Local: break; + + case Ast_Kind_Array_Access: + retval = check_array_access(state, (AstArrayAccess *) expr); + break; + case Ast_Kind_Global: if (expr->type == NULL) { onyx_message_add(state->msgs, @@ -397,14 +432,15 @@ static b32 check_global(SemState* state, AstGlobal* global) { static b32 check_statement(SemState* state, AstNode* stmt) { switch (stmt->kind) { - case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) stmt); case Ast_Kind_Return: return check_return(state, (AstReturn *) stmt); case Ast_Kind_If: return check_if(state, (AstIf *) stmt); case Ast_Kind_While: return check_while(state, (AstWhile *) stmt); case Ast_Kind_Call: return check_call(state, (AstCall *) stmt); case Ast_Kind_Block: return check_block(state, (AstBlock *) stmt); - default: return 0; + default: + stmt->flags |= Ast_Flag_Expr_Ignored; + return check_expression(state, (AstTyped *) stmt); } } @@ -506,7 +542,6 @@ static b32 check_node(SemState* state, AstNode* node) { switch (node->kind) { case Ast_Kind_Function: return check_function(state, (AstFunction *) node); case Ast_Kind_Block: return check_block(state, (AstBlock *) node); - case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) node); case Ast_Kind_Return: return check_return(state, (AstReturn *) node); case Ast_Kind_If: return check_if(state, (AstIf *) node); case Ast_Kind_While: return check_while(state, (AstWhile *) node); diff --git a/src/onyxmsgs.c b/src/onyxmsgs.c index 5b1d8c57..f7a6e52b 100644 --- a/src/onyxmsgs.c +++ b/src/onyxmsgs.c @@ -2,7 +2,7 @@ #include "onyxmsgs.h" #include "onyxutils.h" -#define MAX_MSGS 5 +#define MAX_MSGS 10 static const char* msg_formats[] = { "%s", diff --git a/src/onyxparser.c b/src/onyxparser.c index d98a8c6e..85c1d753 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -33,7 +33,7 @@ static AstTyped* parse_factor(OnyxParser* parser); static AstTyped* parse_expression(OnyxParser* parser); static AstIf* parse_if_stmt(OnyxParser* parser); static AstWhile* parse_while_stmt(OnyxParser* parser); -static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret); +static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret); static AstReturn* parse_return_statement(OnyxParser* parser); static AstBlock* parse_block(OnyxParser* parser); static AstNode* parse_statement(OnyxParser* parser); @@ -256,6 +256,17 @@ static AstTyped* parse_factor(OnyxParser* parser) { return NULL; } + while (parser->curr->type == '[') { + AstArrayAccess* aa_node = make_node(AstArrayAccess, Ast_Kind_Array_Access); + aa_node->token = expect_token(parser, '['); + aa_node->addr = retval; + aa_node->expr = parse_expression(parser); + + expect_token(parser, ']'); + + retval = (AstTyped *) aa_node; + } + while (parser->curr->type == Token_Type_Keyword_Cast) { consume_token(parser); @@ -266,41 +277,56 @@ static AstTyped* parse_factor(OnyxParser* parser) { retval = (AstTyped *) cast_node; } + return retval; } static inline i32 get_precedence(BinaryOp kind) { switch (kind) { - case Binary_Op_Equal: return 3; - case Binary_Op_Not_Equal: return 3; + case Binary_Op_Assign: return 2; + case Binary_Op_Assign_Add: return 2; + case Binary_Op_Assign_Minus: return 2; + case Binary_Op_Assign_Multiply: return 2; + case Binary_Op_Assign_Divide: return 2; + case Binary_Op_Assign_Modulus: return 2; + + case Binary_Op_Equal: return 3; + case Binary_Op_Not_Equal: return 3; + + case Binary_Op_Less_Equal: return 4; + case Binary_Op_Less: return 4; + case Binary_Op_Greater_Equal: return 4; + case Binary_Op_Greater: return 4; - case Binary_Op_Less_Equal: return 4; - case Binary_Op_Less: return 4; - case Binary_Op_Greater_Equal: return 4; - case Binary_Op_Greater: return 4; + case Binary_Op_Add: return 5; + case Binary_Op_Minus: return 5; - case Binary_Op_Add: return 5; - case Binary_Op_Minus: return 5; + case Binary_Op_Multiply: return 6; + case Binary_Op_Divide: return 6; - case Binary_Op_Multiply: return 6; - case Binary_Op_Divide: return 6; + case Binary_Op_Modulus: return 7; - case Binary_Op_Modulus: return 7; - default: return -1; + default: return -1; } } -// + -// - -// * -// / -// % -// == -// != -// <= -// >= -// < -// > +// + +// - +// * +// / +// % +// == +// != +// <= +// >= +// < +// > +// = +// += +// -= +// *= +// /= +// %= // With expected precedence rules static AstTyped* parse_expression(OnyxParser* parser) { bh_arr(AstBinaryOp*) tree_stack = NULL; @@ -329,6 +355,13 @@ static AstTyped* parse_expression(OnyxParser* parser) { case '*': bin_op_kind = Binary_Op_Multiply; break; case '/': bin_op_kind = Binary_Op_Divide; break; case '%': bin_op_kind = Binary_Op_Modulus; break; + + case '=': bin_op_kind = Binary_Op_Assign; break; + case Token_Type_Plus_Equal: bin_op_kind = Binary_Op_Assign_Add; break; + case Token_Type_Minus_Equal: bin_op_kind = Binary_Op_Assign_Minus; break; + case Token_Type_Star_Equal: bin_op_kind = Binary_Op_Assign_Multiply; break; + case Token_Type_Fslash_Equal: bin_op_kind = Binary_Op_Assign_Divide; break; + case Token_Type_Percent_Equal: bin_op_kind = Binary_Op_Assign_Modulus; break; default: goto expression_done; } @@ -429,125 +462,54 @@ static AstWhile* parse_while_stmt(OnyxParser* parser) { // : : // := // :: -// = -// += -// -= -// *= -// /= -// %= -static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) { +static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret) { if (parser->curr->type != Token_Type_Symbol) return 0; - OnyxToken* symbol = expect_token(parser, Token_Type_Symbol); - - switch ((u16) parser->curr->type) { - // NOTE: Declaration - case ':': - { - consume_token(parser); - AstType* type_node = NULL; - - // NOTE: var: type - if (parser->curr->type != ':' - && parser->curr->type != '=') { - type_node = parse_type(parser); - } - - AstLocal* local = make_node(AstLocal, Ast_Kind_Local); - local->token = symbol; - local->type_node = type_node; - local->flags |= Ast_Flag_Lval; // NOTE: DELETE - *ret = (AstNode *) local; - - if (parser->curr->type == '=' || parser->curr->type == ':') { - if (parser->curr->type == ':') { - local->flags |= Ast_Flag_Const; - } - - AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment); - local->next = (AstNode *) assignment; - assignment->token = parser->curr; - consume_token(parser); - - AstTyped* expr = parse_expression(parser); - if (expr == NULL) { - token_toggle_end(parser->curr); - onyx_message_add(parser->msgs, - ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION, - assignment->token->pos, - parser->curr->text); - token_toggle_end(parser->curr); - return 1; - } - assignment->expr = expr; - - AstNode* left_symbol = make_node(AstNode, Ast_Kind_Symbol); - left_symbol->token = symbol; - assignment->lval = (AstTyped *) left_symbol; - } - return 1; - } - - // NOTE: Assignment - case '=': - { - AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment); - assignment->token = parser->curr; - consume_token(parser); - - AstNode* lval = make_node(AstNode, Ast_Kind_Symbol); - lval->token = symbol; - - AstTyped* rval = parse_expression(parser); - assignment->expr = rval; - assignment->lval = (AstTyped *) lval; - *ret = (AstNode *) assignment; - return 1; - } + if ((parser->curr + 1)->type != ':') return 0; - case Token_Type_Plus_Equal: - case Token_Type_Minus_Equal: - case Token_Type_Star_Equal: - case Token_Type_Fslash_Equal: - case Token_Type_Percent_Equal: - { - BinaryOp bin_op; - if (parser->curr->type == Token_Type_Plus_Equal) bin_op = Binary_Op_Add; - else if (parser->curr->type == Token_Type_Minus_Equal) bin_op = Binary_Op_Minus; - else if (parser->curr->type == Token_Type_Star_Equal) bin_op = Binary_Op_Multiply; - else if (parser->curr->type == Token_Type_Fslash_Equal) bin_op = Binary_Op_Divide; - else if (parser->curr->type == Token_Type_Percent_Equal) bin_op = Binary_Op_Modulus; - - AstBinaryOp* bin_op_node = make_node(AstBinaryOp, Ast_Kind_Binary_Op); - bin_op_node->operation = bin_op; - bin_op_node->token = parser->curr; - - consume_token(parser); - AstTyped* expr = parse_expression(parser); + OnyxToken* symbol = expect_token(parser, Token_Type_Symbol); + consume_token(parser); + AstType* type_node = NULL; - AstNode* bin_op_left = make_node(AstNode, Ast_Kind_Symbol); - bin_op_left->token = symbol; - bin_op_node->left = (AstTyped *) bin_op_left; - bin_op_node->right = expr; + // NOTE: var: type + if (parser->curr->type != ':' + && parser->curr->type != '=') { + type_node = parse_type(parser); + } - AstAssign* assign_node = make_node(AstAssign, Ast_Kind_Assignment); - assign_node->token = bin_op_node->token; + AstLocal* local = make_node(AstLocal, Ast_Kind_Local); + local->token = symbol; + local->type_node = type_node; + *ret = (AstNode *) local; - // TODO: Maybe I don't need to make another lval node? - AstNode* lval = make_node(AstNode, Ast_Kind_Symbol); - lval->token = symbol; - assign_node->lval = (AstTyped *) lval; - assign_node->expr = (AstTyped *) bin_op_node; + if (parser->curr->type == '=' || parser->curr->type == ':') { + if (parser->curr->type == ':') { + local->flags |= Ast_Flag_Const; + } - *ret = (AstNode *) assign_node; + AstBinaryOp* assignment = make_node(AstBinaryOp, Ast_Kind_Binary_Op); + assignment->operation = Binary_Op_Assign; + local->next = (AstNode *) assignment; + assignment->token = parser->curr; + consume_token(parser); - return 1; - } + AstTyped* expr = parse_expression(parser); + if (expr == NULL) { + token_toggle_end(parser->curr); + onyx_message_add(parser->msgs, + ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION, + assignment->token->pos, + parser->curr->text); + token_toggle_end(parser->curr); + return 1; + } + assignment->right = expr; - default: - unconsume_token(parser); + AstNode* left_symbol = make_node(AstNode, Ast_Kind_Symbol); + left_symbol->token = symbol; + assignment->left = (AstTyped *) left_symbol; } - return 0; + return 1; } // 'return' ? @@ -594,7 +556,7 @@ static AstNode* parse_statement(OnyxParser* parser) { break; case Token_Type_Symbol: - if (parse_symbol_statement(parser, &retval)) break; + if (parse_symbol_declaration(parser, &retval)) break; // fallthrough case '(': @@ -894,8 +856,6 @@ static AstTyped* parse_global_declaration(OnyxParser* parser) { } global_node->type_node = parse_type(parser); - global_node->flags |= Ast_Flag_Lval; - bh_arr_push(parser->results.nodes_to_process, (AstNode *) global_node); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index a75c15cc..58f988bd 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -13,7 +13,6 @@ static AstType* symres_type(SemState* state, AstType* type); static void symres_local(SemState* state, AstLocal** local); static void symres_call(SemState* state, AstCall* call); static void symres_expression(SemState* state, AstTyped** expr); -static void symres_assignment(SemState* state, AstAssign* assign); static void symres_return(SemState* state, AstReturn* ret); static void symres_if(SemState* state, AstIf* ifnode); static void symres_while(SemState* state, AstWhile* whilenode); @@ -222,20 +221,17 @@ static void symres_expression(SemState* state, AstTyped** expr) { (*expr)->type_node = symres_type(state, (*expr)->type_node); break; + case Ast_Kind_Array_Access: + symres_expression(state, &((AstArrayAccess *)(*expr))->addr); + symres_expression(state, &((AstArrayAccess *)(*expr))->expr); + break; + default: DEBUG_HERE; break; } } -static void symres_assignment(SemState* state, AstAssign* assign) { - AstTyped* lval = (AstTyped *) symbol_resolve(state, assign->lval->token); - if (lval == NULL) return; - assign->lval = lval; - - symres_expression(state, &assign->expr); -} - static void symres_return(SemState* state, AstReturn* ret) { if (ret->expr) symres_expression(state, &ret->expr); @@ -263,7 +259,6 @@ static void symres_while(SemState* state, AstWhile* whilenode) { static b32 symres_statement(SemState* state, AstNode* stmt) { switch (stmt->kind) { case Ast_Kind_Local: symres_local(state, (AstLocal **) &stmt); return 1; - case Ast_Kind_Assignment: symres_assignment(state, (AstAssign *) stmt); return 0; case Ast_Kind_Return: symres_return(state, (AstReturn *) stmt); return 0; case Ast_Kind_If: symres_if(state, (AstIf *) stmt); return 0; case Ast_Kind_While: symres_while(state, (AstWhile *) stmt); return 0; @@ -271,7 +266,10 @@ static b32 symres_statement(SemState* state, AstNode* stmt) { 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; + case Ast_Kind_Break: return 0; + case Ast_Kind_Continue: return 0; + + default: symres_expression(state, (AstTyped **) &stmt); return 0; } } diff --git a/src/onyxutils.c b/src/onyxutils.c index 09881374..d45042ee 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -35,8 +35,8 @@ static const char* ast_node_names[] = { "PARAM", "ARGUMENT", "CALL", - "ASSIGN", "RETURN", + "ARRAY_ACCESS", "IF", "WHILE", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 721cbc0f..cccb53c5 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -217,15 +217,14 @@ static WasmType onyx_type_to_wasm_type(Type* type) { return WASM_TYPE_VOID; } -#define WI(instr) bh_arr_push(code, ((WasmInstruction){ instr, 0x00 })); -#define WID(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, data })); +#define WI(instr) bh_arr_push(code, ((WasmInstruction){ instr, 0x00 })) +#define WID(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, data })) #define COMPILE_FUNC(kind, ...) static void compile_ ## kind (OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, __VA_ARGS__) COMPILE_FUNC(function_body, AstFunction* fd); COMPILE_FUNC(block, AstBlock* block); COMPILE_FUNC(statement, AstNode* stmt); -COMPILE_FUNC(assign_lval, AstTyped* lval); -COMPILE_FUNC(assignment, AstAssign* assign); +COMPILE_FUNC(assignment, AstBinaryOp* assign); COMPILE_FUNC(if, AstIf* if_node); COMPILE_FUNC(while, AstWhile* while_node); COMPILE_FUNC(binop, AstBinaryOp* binop); @@ -297,38 +296,58 @@ COMPILE_FUNC(statement, AstNode* stmt) { switch (stmt->kind) { case Ast_Kind_Return: compile_return(mod, &code, (AstReturn *) stmt); break; - case Ast_Kind_Assignment: compile_assignment(mod, &code, (AstAssign *) stmt); break; case Ast_Kind_If: compile_if(mod, &code, (AstIf *) stmt); break; case Ast_Kind_While: compile_while(mod, &code, (AstWhile *) stmt); break; case Ast_Kind_Break: compile_structured_jump(mod, &code, 0); break; case Ast_Kind_Continue: compile_structured_jump(mod, &code, 1); break; case Ast_Kind_Block: compile_block(mod, &code, (AstBlock *) stmt); break; - - case Ast_Kind_Call: - case Ast_Kind_Intrinsic_Call: - compile_expression(mod, &code, (AstTyped *) stmt); - break; - - - default: break; + default: compile_expression(mod, &code, (AstTyped *) stmt); break; } *pcode = code; } -COMPILE_FUNC(assign_lval, AstTyped* lval) { +COMPILE_FUNC(assignment, AstBinaryOp* assign) { bh_arr(WasmInstruction) code = *pcode; - if (lval->kind == Ast_Kind_Local || lval->kind == Ast_Kind_Param) { + AstTyped* lval = assign->left; + + if (lval->kind == Ast_Kind_Local) { i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) lval); + compile_expression(mod, &code, assign->right); WID(WI_LOCAL_SET, localidx); } else if (lval->kind == Ast_Kind_Global) { i32 globalidx = (i32) bh_imap_get(&mod->global_map, (u64) lval); + compile_expression(mod, &code, assign->right); WID(WI_GLOBAL_SET, globalidx); + } else if (lval->kind == Ast_Kind_Array_Access) { + AstArrayAccess* aa = (AstArrayAccess *) lval; + WID(WI_I32_CONST, aa->elem_size); + compile_expression(mod, &code, aa->expr); + WI(WI_I32_MUL); + compile_expression(mod, &code, aa->addr); + WI(WI_I32_ADD); + + compile_expression(mod, &code, assign->right); + + i32 store_size = aa->type->Basic.size; + i32 is_integer = (aa->type->Basic.flags & Basic_Flag_Integer) + || (aa->type->Basic.flags & Basic_Flag_Pointer); + + if (is_integer) { + if (store_size == 1) WID(WI_I32_STORE_8, ((WasmInstructionData) { 0, 0 })); + else if (store_size == 2) WID(WI_I32_STORE_16, ((WasmInstructionData) { 1, 0 })); + else if (store_size == 4) WID(WI_I32_STORE, ((WasmInstructionData) { 2, 0 })); + else if (store_size == 8) WID(WI_I64_STORE, ((WasmInstructionData) { 3, 0 })); + } else { + if (store_size == 4) WID(WI_F32_STORE, ((WasmInstructionData) { 2, 0 })); + else if (store_size == 8) WID(WI_F64_STORE, ((WasmInstructionData) { 3, 0 })); + } + } else { assert(("Invalid lval", 0)); } @@ -405,15 +424,6 @@ COMPILE_FUNC(while, AstWhile* while_node) { *pcode = code; } -COMPILE_FUNC(assignment, AstAssign* assign) { - bh_arr(WasmInstruction) code = *pcode; - - compile_expression(mod, &code, assign->expr); - compile_assign_lval(mod, &code, assign->lval); - - *pcode = code; -} - // NOTE: These need to be in the same order as // the OnyxBinaryOp enum static const WasmInstructionType binop_map[][4] = { @@ -435,6 +445,12 @@ static const WasmInstructionType binop_map[][4] = { COMPILE_FUNC(binop, AstBinaryOp* binop) { bh_arr(WasmInstruction) code = *pcode; + if (binop_is_assignment(binop)) { + compile_assignment(mod, &code, binop); + *pcode = code; + return; + } + b32 is_sign_significant = 0; switch (binop->operation) { @@ -667,7 +683,6 @@ COMPILE_FUNC(expression, AstTyped* expr) { case Ast_Kind_Block: compile_block(mod, &code, (AstBlock *) expr); break; - case Ast_Kind_Call: compile_call(mod, &code, (AstCall *) expr); break; @@ -676,9 +691,46 @@ COMPILE_FUNC(expression, AstTyped* expr) { compile_intrinsic_call(mod, &code, (AstIntrinsicCall *) expr); break; + case Ast_Kind_Array_Access: { + AstArrayAccess* aa = (AstArrayAccess *) expr; + WID(WI_I32_CONST, aa->elem_size); + compile_expression(mod, &code, aa->expr); + WI(WI_I32_MUL); + compile_expression(mod, &code, aa->addr); + WI(WI_I32_ADD); + + i32 load_size = aa->type->Basic.size; + i32 is_integer = (aa->type->Basic.flags & Basic_Flag_Integer) + || (aa->type->Basic.flags & Basic_Flag_Pointer); + i32 is_unsigned = aa->type->Basic.flags & Basic_Flag_Unsigned; + + WasmInstructionType instr = WI_NOP; + i32 alignment = log2_dumb(load_size); + + if (is_integer) { + if (load_size == 1) instr = WI_I32_LOAD_8_S; + else if (load_size == 2) instr = WI_I32_LOAD_16_S; + else if (load_size == 4) instr = WI_I32_LOAD; + else if (load_size == 8) instr = WI_I64_LOAD; + + if (alignment < 4 && is_unsigned) instr += 1; + } else { + if (load_size == 4) instr = WI_F32_LOAD; + else if (load_size == 8) instr = WI_F64_LOAD; + } + + if (instr != WI_NOP) { + WID(instr, ((WasmInstructionData) { alignment, 0 })); + } else { + DEBUG_HERE; + } + + break; + } + default: - DEBUG_HERE; bh_printf("Unhandled case: %d\n", expr->kind); + DEBUG_HERE; assert(0); } @@ -1064,6 +1116,23 @@ static i32 output_name(const char* start, i32 length, bh_buffer* buff) { return buff->length - prev_len; } +static i32 output_limits(i32 min, i32 max, bh_buffer* buff) { + i32 leb_len, prev_len = buff->length; + u8* leb; + + bh_buffer_write_byte(buff, (max >= 0) ? 0x01 : 0x00); + + leb = uint_to_uleb128((u64) min, &leb_len); + bh_buffer_append(buff, leb, leb_len); + + if (max >= 0) { + leb = uint_to_uleb128((u64) max, &leb_len); + bh_buffer_append(buff, leb, leb_len); + } + + return buff->length - prev_len; +} + static i32 output_functype(WasmFuncType* type, bh_buffer* buff) { i32 prev_len = buff->length; @@ -1133,6 +1202,28 @@ static i32 output_funcsection(OnyxWasmModule* module, bh_buffer* buff) { return buff->length - prev_len; } +static i32 output_memorysection(OnyxWasmModule* module, bh_buffer* buff) { + i32 prev_len = buff->length; + bh_buffer_write_byte(buff, WASM_SECTION_ID_MEMORY); + + bh_buffer vec_buff; + bh_buffer_init(&vec_buff, buff->allocator, 128); + + i32 leb_len; + u8* leb = uint_to_uleb128((u64) 1, &leb_len); + bh_buffer_append(&vec_buff, leb, leb_len); + + output_limits(4, 20, &vec_buff); + + leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len); + bh_buffer_append(buff, leb, leb_len); + + bh_buffer_concat(buff, vec_buff); + bh_buffer_free(&vec_buff); + + return buff->length - prev_len; +} + static i32 output_globalsection(OnyxWasmModule* module, bh_buffer* buff) { i32 prev_len = buff->length; bh_buffer_write_byte(buff, WASM_SECTION_ID_GLOBAL); @@ -1317,6 +1408,35 @@ static void output_instruction(WasmInstruction* instr, bh_buffer* buff) { bh_buffer_append(buff, leb, leb_len); break; + case WI_I32_STORE: + case WI_I32_STORE_8: + case WI_I32_STORE_16: + case WI_I64_STORE: + case WI_I64_STORE_8: + case WI_I64_STORE_16: + case WI_I64_STORE_32: + case WI_F32_STORE: + case WI_F64_STORE: + case WI_I32_LOAD: + case WI_I32_LOAD_8_S: + case WI_I32_LOAD_8_U: + case WI_I32_LOAD_16_S: + case WI_I32_LOAD_16_U: + case WI_I64_LOAD: + case WI_I64_LOAD_8_S: + case WI_I64_LOAD_8_U: + case WI_I64_LOAD_16_S: + case WI_I64_LOAD_16_U: + case WI_I64_LOAD_32_S: + case WI_I64_LOAD_32_U: + case WI_F32_LOAD: + case WI_F64_LOAD: + leb = uint_to_uleb128((u64) instr->data.i1, &leb_len); + bh_buffer_append(buff, leb, leb_len); + leb = uint_to_uleb128((u64) instr->data.i2, &leb_len); + bh_buffer_append(buff, leb, leb_len); + break; + case WI_I32_CONST: leb = int_to_leb128((i64) instr->data.i1, &leb_len); bh_buffer_append(buff, leb, leb_len); @@ -1393,6 +1513,7 @@ void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file) { output_typesection(module, &master_buffer); output_importsection(module, &master_buffer); output_funcsection(module, &master_buffer); + output_memorysection(module, &master_buffer); output_globalsection(module, &master_buffer); output_exportsection(module, &master_buffer); output_startsection(module, &master_buffer);