Added bin ops with precedence; bug fixes
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 20 Jun 2020 02:38:04 +0000 (21:38 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 20 Jun 2020 02:38:04 +0000 (21:38 -0500)
include/onyxparser.h
include/onyxutils.h
onyx
progs/minimal.onyx
src/onyx.c
src/onyxparser.c
src/onyxutils.c
src/onyxwasm.c

index df4adab62000b4944947b8e6ca1cfd5d5122efe6..91dc48ffbf4c908679b0177cddabcd83dbcd8155 100644 (file)
@@ -21,10 +21,6 @@ typedef struct OnyxParser {
        OnyxToken *prev_token;
        OnyxToken *curr_token;
 
-       // BUG: This way of handling identifiers will work for now,
-       // but it will not allow for shadowing. Also, variable names
-       // cannot be the same as any function or global variable.
-       // That will get annoying to program.
        // NOTE: A table of the current identifiers in the current scope.
        // If the identifier doesn't at the time of parsing, it is an error.
        // Cleared at the end of a block.
index 63b6f6015459237aa41d8bfb473ac202f7219e32..a63e4558918aaa2ee5e4694628bcfcb4be666a89 100644 (file)
@@ -2,4 +2,7 @@
 
 #include "onyxparser.h"
 
+extern bh_scratch global_scratch;
+extern bh_allocator global_scratch_allocator;
+
 void onyx_ast_print(OnyxAstNode* program, i32 indent);
diff --git a/onyx b/onyx
index 86ccaf9ebe9972c33c0e141faf14cae4bed9c0cb..59fdd5b4cc20fbbebe03806ed8025a447c2791a6 100755 (executable)
Binary files a/onyx and b/onyx differ
index 0218c5172249a6f08f3fedccd8e07cc8960c19d9..a78a82afea75b8c63d7827630045c2059b519447 100644 (file)
@@ -16,18 +16,18 @@ diff_square :: proc (a i32, b i32) -> i32 {
        c := a - b; // Mutable
        d :: a + b; // Constant
 
-       return (c * d) as i32;
+       return c * d;
 }
 
 export do_stuff :: proc -> i32 {
        res := diff_square((4 + 5) as i32, (2 + 3) as i32);
        res = res + foo();
-    // res should be 66
-    return res * (0 - 1);
+    // res should be -66
+    return res * -1;
 }
 
-export float_test :: proc -> f32 {
-    return (1.2f + 5.3f);
+float_test :: proc -> f32 {
+    return 3.14159f;
 }
 
 export main :: proc {
index 5a07b655b7d83728ca14f969cdb526c4ab0e2655..816a38a778008652879f76baf8d275e49038b713 100644 (file)
@@ -9,6 +9,12 @@
 #include "onyxwasm.h"
 
 int main(int argc, char *argv[]) {
+
+       bh_allocator alloc = bh_heap_allocator();
+
+    bh_scratch_init(&global_scratch, alloc, 16 * 1024); // NOTE: 16 KB
+    global_scratch_allocator = bh_scratch_allocator(&global_scratch);
+
        bh_file source_file;
        bh_file_error err = bh_file_open(&source_file, argv[1]);
        if (err != BH_FILE_ERROR_NONE) {
@@ -16,8 +22,6 @@ int main(int argc, char *argv[]) {
                return EXIT_FAILURE;
        }
 
-       bh_allocator alloc = bh_heap_allocator();
-
        // NOTE: 1st: Read file contents
        bh_file_contents fc = bh_file_read_contents(alloc, &source_file);
        bh_file_close(&source_file);
@@ -51,7 +55,7 @@ int main(int argc, char *argv[]) {
                onyx_message_print(&msgs);
                goto main_exit;
        } else {
-               onyx_ast_print(program, 0);
+               // onyx_ast_print(program, 0);
            bh_printf("\nNo errors.\n");
     }
 
index 4a65939a6a1733d5a6a05c250c17c6bc80d8322a..9cdbda4964828198cc1a5b41fe39d36bfde15812 100644 (file)
@@ -1,6 +1,7 @@
 #include "onyxlex.h"
 #include "onyxmsgs.h"
 #include "onyxparser.h"
+#include "onyxutils.h"
 
 static const char* ast_node_names[] = {
        "ERROR",
@@ -240,6 +241,22 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) {
                                return expr;
                        }
 
+        case TOKEN_TYPE_SYM_MINUS:
+            {
+                parser_next_token(parser);
+                OnyxAstNode* factor = parse_factor(parser);
+
+                OnyxAstNode* negate_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_NEGATE);
+                negate_node->left = factor;
+                negate_node->type = factor->type;
+
+                if ((factor->flags & ONYX_AST_FLAG_COMPTIME) != 0) {
+                    negate_node->flags |= ONYX_AST_FLAG_COMPTIME;
+                }
+
+                return negate_node;
+            }
+
                case TOKEN_TYPE_SYMBOL:
                        {
                                OnyxToken* sym_token = expect(parser, TOKEN_TYPE_SYMBOL);
@@ -310,82 +327,89 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) {
        return NULL;
 }
 
-static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left) {
-       OnyxAstNodeKind kind = -1;
-
-       switch (parser->curr_token->type) {
-       case TOKEN_TYPE_SYM_PLUS:               kind = ONYX_AST_NODE_KIND_ADD; break;
-       case TOKEN_TYPE_SYM_MINUS:              kind = ONYX_AST_NODE_KIND_MINUS; break;
-       case TOKEN_TYPE_SYM_STAR:               kind = ONYX_AST_NODE_KIND_MULTIPLY; break;
-       case TOKEN_TYPE_SYM_FSLASH:             kind = ONYX_AST_NODE_KIND_DIVIDE; break;
-       case TOKEN_TYPE_SYM_PERCENT:    kind = ONYX_AST_NODE_KIND_MODULUS; break;
-       default: break;
-       }
-
-       if (kind != -1) {
-               OnyxToken* bin_op_tok = parser->curr_token;
-               parser_next_token(parser);
-
-               OnyxAstNode* right = parse_factor(parser);
-
-               // NOTE: Typechecking like this will not be here for long but
-               // want to start working on it early
-               if (left->type != right->type) {
-                       onyx_message_add(parser->msgs,
-                               ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
-                               bin_op_tok->pos,
-                               left->type->name, right->type->name);
-                       return &error_node;
-               }
-
-               OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, kind);
-               bin_op->left = left;
-               bin_op->right = right;
-               bin_op->type = left->type;
-
-               if ((left->flags & ONYX_AST_FLAG_COMPTIME) != 0 && (right->flags & ONYX_AST_FLAG_COMPTIME) != 0) {
-                       bin_op->flags |= ONYX_AST_FLAG_COMPTIME;
-               }
-
-               return bin_op;
-       }
-
-       return &error_node;
+static inline i32 get_precedence(OnyxAstNodeKind kind) {
+    switch (kind) {
+        case ONYX_AST_NODE_KIND_ADD: return 1;
+        case ONYX_AST_NODE_KIND_MINUS: return 1;
+        case ONYX_AST_NODE_KIND_MULTIPLY: return 2;
+        case ONYX_AST_NODE_KIND_DIVIDE: return 2;
+        case ONYX_AST_NODE_KIND_MODULUS: return 3;
+        case ONYX_AST_NODE_KIND_CAST: return 4;
+        default: return -1;
+    }
 }
 
 static OnyxAstNode* parse_expression(OnyxParser* parser) {
-       OnyxAstNode* left = parse_factor(parser);
+    bh_arr(OnyxAstNode*) tree_stack = NULL;
+    bh_arr_new(global_scratch_allocator, tree_stack, 4);
+    bh_arr_set_length(tree_stack, 0);
 
-       switch (parser->curr_token->type) {
-               case TOKEN_TYPE_SYM_PLUS:
-               case TOKEN_TYPE_SYM_MINUS:
-               case TOKEN_TYPE_SYM_STAR:
-               case TOKEN_TYPE_SYM_FSLASH:
-               case TOKEN_TYPE_SYM_PERCENT:
-                       {
-                               OnyxAstNode* expr = parse_bin_op(parser, left);
-                               return expr;
-                       }
-               case TOKEN_TYPE_KEYWORD_CAST:
-                       {
-                               parser_next_token(parser);
-                               OnyxTypeInfo* type = parse_type(parser);
+       OnyxAstNode* left = parse_factor(parser);
+    OnyxAstNode* right;
+    OnyxAstNode* root = left;
+
+    i32 bin_op_kind;
+    OnyxToken* bin_op_tok;
+
+    while (1) {
+        bin_op_kind = -1;
+        switch (parser->curr_token->type) {
+            case TOKEN_TYPE_SYM_PLUS:       bin_op_kind = ONYX_AST_NODE_KIND_ADD; break;
+            case TOKEN_TYPE_SYM_MINUS:      bin_op_kind = ONYX_AST_NODE_KIND_MINUS; break;
+            case TOKEN_TYPE_SYM_STAR:       bin_op_kind = ONYX_AST_NODE_KIND_MULTIPLY; break;
+            case TOKEN_TYPE_SYM_FSLASH:     bin_op_kind = ONYX_AST_NODE_KIND_DIVIDE; break;
+            case TOKEN_TYPE_SYM_PERCENT:    bin_op_kind = ONYX_AST_NODE_KIND_MODULUS; break;
+            case TOKEN_TYPE_KEYWORD_CAST:   bin_op_kind = ONYX_AST_NODE_KIND_CAST; break;
+            default: goto expression_done;
+        }
 
-                               // NOTE: This may be premature in the parser but a cast
-                               // node doesn't need to exist if the source and target
-                               // types are the same
-                               if (type == left->type) return left;
+        if (bin_op_kind != -1) {
+            bin_op_tok = parser->curr_token;
+            parser_next_token(parser);
+
+            OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, bin_op_kind);
+
+            while ( !bh_arr_is_empty(tree_stack) &&
+                    get_precedence(bh_arr_last(tree_stack)->kind) >= get_precedence(bin_op_kind))
+                bh_arr_pop(tree_stack);
+
+            if (bh_arr_is_empty(tree_stack)) {
+                // NOTE: new is now the root node
+                bin_op->left = root;
+                root = bin_op;
+            } else {
+                bin_op->left = bh_arr_last(tree_stack)->right;
+                bh_arr_last(tree_stack)->right = bin_op;
+            }
+
+            bh_arr_push(tree_stack, bin_op);
+
+            if (bin_op_kind == ONYX_AST_NODE_KIND_CAST) {
+                bin_op->type = parse_type(parser);
+            } else {
+                right = parse_factor(parser);
+                if (left->type != right->type) {
+                    onyx_message_add(parser->msgs,
+                        ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
+                        bin_op_tok->pos,
+                        left->type->name, right->type->name);
+
+                    find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
+                    return &error_node;
+                }
 
-                               OnyxAstNode* cast_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_CAST);
-                               cast_node->type = type;
-                               cast_node->left = left;
+                bin_op->right = right;
+                bin_op->type = right->type;
 
-                               return cast_node;
-                       }
-               default: break;
-       }
+                if ((left->flags & ONYX_AST_FLAG_COMPTIME) != 0 && (right->flags & ONYX_AST_FLAG_COMPTIME) != 0) {
+                    bin_op->flags |= ONYX_AST_FLAG_COMPTIME;
+                }
+            }
+        }
+    }
 
-       return left;
+expression_done:
+       return root;
 }
 
 static OnyxAstNode* parse_if_stmt(OnyxParser* parser) {
index 5f0e97c960200de9f6403a1d0ae5e9c45065ddfe..77cd47d0ff8f988c758e0e4b4fe99e7f3769d075 100644 (file)
@@ -2,6 +2,9 @@
 #include "onyxlex.h"
 #include "onyxparser.h"
 
+bh_scratch global_scratch;
+bh_allocator global_scratch_allocator;
+
 #define print_indent { if (indent > 0) bh_printf("\n"); for (int i = 0; i < indent; i++) bh_printf("  "); }
 
 void onyx_ast_print(OnyxAstNode* node, i32 indent) {
index 27760df304365c0f8dd63af4839d7d8cda53e41d..ce965f2012e5fb948f1a35a4d733ca793ca3c51e 100644 (file)
@@ -333,6 +333,32 @@ static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode*
                                break;
                        }
 
+        case ONYX_AST_NODE_KIND_NEGATE:
+            {
+                OnyxTypeInfoKind type_kind = expr->type->kind;
+
+                if (type_kind == ONYX_TYPE_INFO_KIND_INT32) {
+                    bh_arr_push(func->code, ((WasmInstruction){ WI_I32_CONST, 0x00 }));
+                    process_expression(mod, func, expr->left);
+                    bh_arr_push(func->code, ((WasmInstruction){ WI_I32_SUB, 0x00 }));
+
+                } else if (type_kind == ONYX_TYPE_INFO_KIND_INT64) {
+                    bh_arr_push(func->code, ((WasmInstruction){ WI_I64_CONST, 0x00 }));
+                    process_expression(mod, func, expr->left);
+                    bh_arr_push(func->code, ((WasmInstruction){ WI_I64_SUB, 0x00 }));
+
+                } else {
+                    process_expression(mod, func, expr->left);
+
+                    if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT32)
+                        bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
+
+                    if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT64)
+                        bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
+                }
+                break;
+            }
+
                case ONYX_AST_NODE_KIND_LOCAL:
                case ONYX_AST_NODE_KIND_PARAM:
                        {