Added if statements
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 20 Jun 2020 20:10:29 +0000 (15:10 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 20 Jun 2020 20:10:29 +0000 (15:10 -0500)
include/onyxlex.h
include/onyxparser.h
onyx
progs/minimal.onyx
progs/test.onyx [new file with mode: 0644]
src/onyxlex.c
src/onyxparser.c
src/onyxutils.c
src/onyxwasm.c

index 977546482565e69efbc2679d0785fe3fcb045c84..c9a4632ad8f0b7388fa1a7e58c0c7a8bdf66f1ba 100644 (file)
@@ -14,6 +14,7 @@ typedef enum OnyxTokenType {
        TOKEN_TYPE_KEYWORD_EXPORT,
        TOKEN_TYPE_KEYWORD_IF,
        TOKEN_TYPE_KEYWORD_ELSE,
+       TOKEN_TYPE_KEYWORD_ELSEIF,
        TOKEN_TYPE_KEYWORD_FOR,
        TOKEN_TYPE_KEYWORD_DO,
        TOKEN_TYPE_KEYWORD_RETURN,
index 91dc48ffbf4c908679b0177cddabcd83dbcd8155..081e2adc3a174faed054ceff14d8100643663526 100644 (file)
@@ -11,6 +11,7 @@ typedef struct OnyxAstNodeNumLit OnyxAstNodeNumLit;
 typedef struct OnyxAstNodeLocal OnyxAstNodeLocal;
 typedef struct OnyxAstNodeScope OnyxAstNodeScope;
 typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;
+typedef struct OnyxAstNodeIf OnyxAstNodeIf;
 typedef struct OnyxAstNodeParam OnyxAstNodeParam;
 typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef;
 typedef struct OnyxAstNodeForeign OnyxAstNodeForeign;
@@ -162,6 +163,16 @@ struct OnyxAstNodeBlock {
        OnyxAstNodeScope *scope; // NOTE: Only set on blocks belonging to functions
 };
 
+struct OnyxAstNodeIf {
+    OnyxAstNodeKind kind;
+    u32 flags;
+    OnyxToken *token;    // NOTE: UNUSED
+    OnyxAstNode *false_block;
+    OnyxAstNode *next;
+    OnyxAstNode *cond;
+    OnyxAstNode *true_block;
+};
+
 struct OnyxAstNodeFuncDef {
        OnyxAstNodeKind kind;
        u32 flags;
@@ -215,6 +226,7 @@ union OnyxAstNode {
        OnyxAstNodeCall as_call;
     OnyxAstNodeNumLit as_numlit;
     OnyxAstNodeForeign as_foreign;
+    OnyxAstNodeIf as_if;
 };
 
 const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind);
diff --git a/onyx b/onyx
index ea67fa4bbb97ca42a50fc2e210a29caab902b2cb..20ab66431676508fa008c72cdaa70068536b9c33 100755 (executable)
Binary files a/onyx and b/onyx differ
index a78a82afea75b8c63d7827630045c2059b519447..818a598a76ec6a4811c33c7c1b22b541273748cb 100644 (file)
@@ -33,6 +33,14 @@ float_test :: proc -> f32 {
 export main :: proc {
     output := do_stuff();
 
+    if output + 66 {
+        new_output :: -output * 2;
+        print(new_output);
+
+    } else {
+        print(-1);
+    };
+
     print(output);
     print_float(float_test());
 
diff --git a/progs/test.onyx b/progs/test.onyx
new file mode 100644 (file)
index 0000000..5c6f367
--- /dev/null
@@ -0,0 +1,17 @@
+
+// Foreign functions are included this way:
+//      sym_name :: foreign "module" "name" proc ...
+print       :: foreign "host" "print" proc (value i32) ---
+
+get_value   :: foreign "env" "get_val" proc -> i32 ---
+
+
+
+// This is the entry point
+export main :: proc {
+    nineteen :: 5 * 3 + 4;
+    thirty_five :: 5 * (3 + 4) + get_value();
+
+    print(nineteen);
+    print(thirty_five);
+}
index d0069690824904207686330c2bce57da714dcbff..3ed4c58fb36fb12fb65906b61fabdd89fcdde418 100644 (file)
@@ -12,6 +12,7 @@ static const char* onyx_token_type_names[] = {
        "export",               //"TOKEN_TYPE_KEYWORD_EXPORT",
        "if",                   //"TOKEN_TYPE_KEYWORD_IF",
        "else",                 //"TOKEN_TYPE_KEYWORD_ELSE",
+       "elseif",               //"TOKEN_TYPE_KEYWORD_ELSEIF",
        "for",                  //"TOKEN_TYPE_KEYWORD_FOR",
        "do",                   //"TOKEN_TYPE_KEYWORD_DO",
        "return",               //"TOKEN_TYPE_KEYWORD_RETURN",
@@ -138,6 +139,7 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {
        LITERAL_TOKEN("export",  1, TOKEN_TYPE_KEYWORD_EXPORT);
        LITERAL_TOKEN("use",     1, TOKEN_TYPE_KEYWORD_USE);
        LITERAL_TOKEN("if",      1, TOKEN_TYPE_KEYWORD_IF);
+       LITERAL_TOKEN("elseif",    1, TOKEN_TYPE_KEYWORD_ELSEIF);
        LITERAL_TOKEN("else",    1, TOKEN_TYPE_KEYWORD_ELSE);
        LITERAL_TOKEN("foreign", 1, TOKEN_TYPE_KEYWORD_FOREIGN);
        LITERAL_TOKEN("for",     1, TOKEN_TYPE_KEYWORD_FOR);
index 07cbfd1b2ac74fcbb68e2fb9f477ac7010fd1545..0eaa4db1d0850fb1a737007e7e6cdb62e167f780 100644 (file)
@@ -341,7 +341,7 @@ static inline i32 get_precedence(OnyxAstNodeKind kind) {
 
 static OnyxAstNode* parse_expression(OnyxParser* parser) {
     bh_arr(OnyxAstNode*) tree_stack = NULL;
-    bh_arr_new(global_scratch_allocator, tree_stack, 1);
+    bh_arr_new(global_scratch_allocator, tree_stack, 4);
     bh_arr_set_length(tree_stack, 0);
 
        OnyxAstNode* left = parse_factor(parser);
@@ -413,7 +413,39 @@ expression_done:
 }
 
 static OnyxAstNode* parse_if_stmt(OnyxParser* parser) {
-       return &error_node;
+    expect(parser, TOKEN_TYPE_KEYWORD_IF);
+
+    OnyxAstNode* cond = parse_expression(parser);
+    OnyxAstNode* true_block = (OnyxAstNode *) parse_block(parser, 0);
+
+    OnyxAstNodeIf* if_node = (OnyxAstNodeIf *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_IF);
+    OnyxAstNodeIf* root_if = if_node;
+
+    if_node->cond = cond;
+    if_node->true_block = true_block->as_block.body;
+
+    while (parser->curr_token->type == TOKEN_TYPE_KEYWORD_ELSEIF) {
+        parser_next_token(parser);
+        OnyxAstNodeIf* elseif_node = (OnyxAstNodeIf *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_IF);
+
+        cond = parse_expression(parser);
+        true_block = (OnyxAstNode *) parse_block(parser, 0);
+
+        elseif_node->cond = cond;
+        elseif_node->true_block = true_block->as_block.body;
+
+        if_node->false_block = (OnyxAstNode *) elseif_node;
+        if_node = elseif_node;
+    }
+
+    if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_ELSE) {
+        parser_next_token(parser);
+
+        OnyxAstNode* false_block = (OnyxAstNode *) parse_block(parser, 0);
+        if_node->false_block = false_block->as_block.body;
+    }
+
+    return (OnyxAstNode *) root_if;
 }
 
 // Returns 1 if the symbol was consumed. Returns 0 otherwise
index 77cd47d0ff8f988c758e0e4b4fe99e7f3769d075..5070e721cdc0277b8257a468749b44eda0690795 100644 (file)
@@ -143,6 +143,23 @@ void onyx_ast_print(OnyxAstNode* node, i32 indent) {
         break;
     }
 
+    case ONYX_AST_NODE_KIND_IF: {
+        OnyxAstNodeIf* if_node = &node->as_if;
+        if (if_node->cond) {
+            onyx_ast_print(if_node->cond, indent + 1);
+        }
+        if (if_node->true_block) {
+            onyx_ast_print(if_node->true_block, indent + 1);
+        }
+        if (if_node->false_block) {
+            onyx_ast_print(if_node->false_block, indent + 1);
+        }
+        if (if_node->next) {
+            onyx_ast_print(if_node->next, indent);
+        }
+        break;
+    }
+
        default: {
                onyx_ast_print(node->left, indent + 1);
                onyx_ast_print(node->right, indent + 1);
index ce965f2012e5fb948f1a35a4d733ca793ca3c51e..090919920a2fbe1bf175684b669ba486e507d284 100644 (file)
@@ -213,6 +213,7 @@ static void process_block(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBlock*
 static void process_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* stmt);
 static void process_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval);
 static void process_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign);
+static void process_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_node);
 static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr);
 static void process_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* cast);
 static void process_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret);
@@ -242,6 +243,7 @@ static void process_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode*
                case ONYX_AST_NODE_KIND_SCOPE: break;
                case ONYX_AST_NODE_KIND_RETURN: process_return(mod, func, stmt); break;
                case ONYX_AST_NODE_KIND_ASSIGNMENT: process_assignment(mod, func, stmt); break;
+        case ONYX_AST_NODE_KIND_IF: process_if(mod, func, (OnyxAstNodeIf *) stmt); break;
                default: process_expression(mod, func, stmt);
        }
 }
@@ -256,6 +258,28 @@ static void process_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode
        }
 }
 
+static void process_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_node) {
+    process_expression(mod, func, if_node->cond);
+    bh_arr_push(func->code, ((WasmInstruction){ WI_IF_START, 0x40 }));
+
+    if (if_node->true_block) {
+        // NOTE: This is kind of gross, but making a function for this doesn't feel right
+        forll (OnyxAstNode, stmt, if_node->true_block, next) {
+            process_statement(mod, func, stmt);
+        }
+    }
+
+    if (if_node->false_block) {
+        bh_arr_push(func->code, ((WasmInstruction){ WI_ELSE, 0x00 }));
+
+        forll (OnyxAstNode, stmt, if_node->false_block, next) {
+            process_statement(mod, func, stmt);
+        }
+    }
+
+    bh_arr_push(func->code, ((WasmInstruction){ WI_IF_END, 0x00 }));
+}
+
 static void process_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign) {
        process_expression(mod, func, assign->right);
        process_assign_lval(mod, func, assign->left);
@@ -915,6 +939,7 @@ static void output_instruction(WasmInstruction* instr, bh_buffer* buff) {
                case WI_LOCAL_SET:
         case WI_CALL:
                case WI_BLOCK_START:
+               case WI_IF_START:
                        leb = uint_to_uleb128((u64) instr->data.i1, &leb_len);
                        bh_buffer_append(buff, leb, leb_len);
                        break;