Added deferred statements; maybe a little buggy
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 30 Jul 2020 20:04:15 +0000 (15:04 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 30 Jul 2020 20:04:15 +0000 (15:04 -0500)
17 files changed:
docs/plan
include/onyxastnodes.h
include/onyxlex.h
include/onyxsempass.h
include/onyxwasm.h
misc/onyx.sublime-syntax
misc/onyx.vim
onyx
progs/alloc.onyx
progs/alloc_test.onyx
src/onyxchecker.c
src/onyxlex.c
src/onyxparser.c
src/onyxsempass.c
src/onyxsymres.c
src/onyxutils.c
src/onyxwasm.c

index a8f1956beb05d3d81f24229a0a2e3e8ece4ac375..c1ce3901747a95608a09c2ea5645cee179528e44 100644 (file)
--- a/docs/plan
+++ b/docs/plan
@@ -132,7 +132,7 @@ HOW:
 
         [X] Procedures as arguments
 
-        [ ] Deferred statements
+        [X] Deferred statements
 
         [ ] Pointer math
 
@@ -140,6 +140,10 @@ HOW:
 
         [ ] Hex literals
 
+        [ ] #file_contents
+
+        [ ] #initialize structs
+
         [ ] Start work on evaluating compile time known values.
             - An expression marked COMPTIME will be reduced to its value in the parse tree.
 
index af36357434204a1d337f171d7ef4e5f94e95ff93..60e592fe8d0cb07235d095ac648440e5b6e1dee2 100644 (file)
@@ -31,6 +31,7 @@ typedef struct AstBlock AstBlock;
 typedef struct AstIf AstIf;
 typedef struct AstFor AstFor;
 typedef struct AstWhile AstWhile;
+typedef struct AstDefer AstDefer;
 
 typedef struct AstType AstType;
 typedef struct AstBasicType AstBasicType;
@@ -117,6 +118,7 @@ typedef enum AstKind {
     Ast_Kind_While,
     Ast_Kind_Break,
     Ast_Kind_Continue,
+    Ast_Kind_Defer,
 
     Ast_Kind_Count
 } AstKind;
@@ -275,6 +277,7 @@ struct AstContinue      { AstNode_base; u64 count; };
 // Structure Nodes
 struct AstBlock         { AstNode_base; AstNode *body; Scope *scope; };
 struct AstWhile         { AstNode_base; AstTyped *cond; AstNode *stmt; };
+struct AstDefer         { AstNode_base; AstNode *stmt; };
 struct AstFor           {
     AstNode_base;
 
index 5410ae4bdacee36f2247f57f374a41458a500e8e..e122fda305e3ffb025fe06a46aedcd56b5037c83 100644 (file)
@@ -28,6 +28,7 @@ typedef enum TokenType {
     Token_Type_Keyword_Continue,
     Token_Type_Keyword_Sizeof,
     Token_Type_Keyword_Alignof,
+    Token_Type_Keyword_Defer,
 
     Token_Type_Right_Arrow,
     Token_Type_Left_Arrow,
index f2863d657d7aeda5c7f487a7212a118628ce3d74..ea504989163fc42770b421cd06e7e4351a7d2560 100644 (file)
@@ -23,6 +23,8 @@ typedef struct SemState {
 
     // NOTE: Used in type checking phase
     Type* expected_return_type;
+
+    u32 defer_allowed : 1;
 } SemState;
 
 extern SemState semstate;
index 6be722bd930722a58746ed297cab300ecc56c247..3471b64fdc7222cce72ff914e00f028283f558c5 100644 (file)
@@ -285,6 +285,11 @@ typedef struct WasmDatum {
     ptr data;
 } WasmDatum;
 
+typedef struct DeferredStmt {
+    u64 depth;
+    AstNode *stmt;
+} DeferredStmt;
+
 typedef struct OnyxWasmModule {
     bh_allocator allocator;
 
@@ -297,6 +302,8 @@ typedef struct OnyxWasmModule {
     // NOTE: Mapping ptrs to elements
     bh_imap elem_map;
 
+    bh_arr(DeferredStmt) deferred_stmts;
+
     // NOTE: Used internally as a map from strings that represent function types,
     // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
     // to the function type index if it has been created.
index 7e44579bf11993ee82e1e135e220e703795fad7d..5159d5800ce120631aa620bc2dee1172686624a1 100644 (file)
@@ -23,7 +23,7 @@ contexts:
     # strings in YAML. When using single quoted strings, only single quotes
     # need to be escaped: this is done by using two single quotes next to each
     # other.
-    - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|cast|sizeof|alignof)\b'
+    - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|cast|sizeof|alignof|defer)\b'
       scope: keyword.control.onyx
 
     - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b'
index e8c8b761ff753eb800b7a0a006fad69187d922a2..73eb5d1bb55b51a93d448b48900fa0190b8d150d 100644 (file)
@@ -13,7 +13,7 @@ set cpo&vim
 syn keyword onyxKeyword package struct proc use global
 syn keyword onyxKeyword if elseif else
 syn keyword onyxKeyword for while do
-syn keyword onyxKeyword break continue return
+syn keyword onyxKeyword break continue return defer
 syn keyword onyxKeyword as cast sizeof alignof
 
 syn keyword onyxType bool void
@@ -25,7 +25,7 @@ syn keyword onyxType f32
 syn keyword onyxType f64
 syn keyword onyxType rawptr
 
-syn keyword onyxConstant        true false
+syn keyword onyxConstant        true false null
 
 syn keyword onyxCommentStart    contained TODO NOTE BUG HACK
 
diff --git a/onyx b/onyx
index 4f3f842f402ce6c92edd5f40a2962ef8bb9f6737..1950f6fb5dc3d18974c78a16652e7824d94173b3 100755 (executable)
Binary files a/onyx and b/onyx differ
index 11ff27c89473f4bd4eee70d61457fe2e263f8b24..f5899f07a77d197f640bd0c5c612b3ed60cb2044 100644 (file)
@@ -2,8 +2,6 @@ package memory
 
 use "progs/intrinsics"
 
-use package printing { print }
-
 use package intrinsics {
     memory_size, memory_grow
 }
@@ -24,12 +22,12 @@ Allocator :: struct {
 
 alloc_proc :: #type proc (rawptr, AllocAction, u32, u32, rawptr) -> rawptr;
 
-alloc :: proc (a: ^Allocator, size: u32) -> rawptr {
-    return a.func(a.data, AllocAction.Alloc, size, 16, null);
+alloc :: proc (use a: ^Allocator, size: u32) -> rawptr {
+    return func(data, AllocAction.Alloc, size, 16, null);
 }
 
-free :: proc (a: ^Allocator, ptr: rawptr) {
-    a.func(a.data, AllocAction.Free, 0, 0, ptr);
+free :: proc (use a: ^Allocator, ptr: rawptr) {
+    func(data, AllocAction.Free, 0, 0, ptr);
 }
 
 
@@ -56,7 +54,7 @@ heap_init :: proc {
     heap_state.next_alloc = __heap_start;
     heap_state.remaining_space = (memory_size() << 16) - cast(u32) __heap_start;
 
-    heap_allocator.data = null;
+    heap_allocator.data = ^heap_state;
     heap_allocator.func = heap_alloc_proc;
 }
 
@@ -112,6 +110,12 @@ heap_alloc :: proc (size_: u32, align: u32) -> rawptr {
 
 heap_free :: proc (ptr: rawptr) {
     hb_ptr := cast(^heap_block) (cast(u32) ptr - sizeof heap_block);
+
+    // DEBUGGING: Fills freed memory with 0's
+    for i: 0, hb_ptr.size {
+        (cast(^u8) ptr)[i] = cast(u8) 0;
+    }
+
     hb_ptr.next = heap_state.free_list;
     heap_state.free_list = hb_ptr;
 }
index 4b9371e6af5ab767ace3974a8b4761ecd2755a72..f6d6dea7ef15d5faa69a13a04a455bd8f8780ab1 100644 (file)
@@ -4,35 +4,47 @@ use "progs/print_funcs"
 use package memory
 use package printing
 
+deferred_example :: proc -> i32 {
+    arr := cast([] i32) malloc(sizeof [8] i32);
+    defer if cast(rawptr) arr != null mfree(arr);
+
+    for i: 0, 8 arr[i] = i * i;
+    for i: 0, 8 print(arr[i]);
+
+    return arr[1] + arr[7];
+}
+
 proc #export "main" {
-       asdf :: "staring asdfkjasd asdflkjasdflkajsdflk";
-       heap_init();
+    asdf :: "staring asdfkjasd asdflkjasdflkajsdflk";
+    heap_init();
+
+    print(deferred_example());
 
-       first := cast([] i32) malloc(sizeof [4] i32);
-       for i: 0, 4 first[i] = i * 2;
+    first := cast([] i32) malloc(sizeof [4] i32);
+    for i: 0, 4 first[i] = i * 2;
 
-       second := cast([] f32) malloc(sizeof [24] f32);
-       for i: 0, 24 second[i] = cast(f32) i;
+    second := cast([] f32) malloc(sizeof [24] f32);
+    for i: 0, 24 second[i] = cast(f32) i;
 
-       print(cast(u32) first);
-       print(cast(u32) second);
+    print(cast(u32) first);
+    print(cast(u32) second);
 
-       for i: 0, 4 print(first[i]);
-       for i: 0, 24 print(second[i]);
+    for i: 0, 4 print(first[i]);
+    for i: 0, 24 print(second[i]);
 
-       mfree(first);
+    mfree(first);
 
-       third := cast(^i32) malloc(sizeof i32);
+    third := cast(^i32) malloc(sizeof i32);
 
-       print(cast(u32) third);
-       *third = 1234;
-       print(*third);
+    print(cast(u32) third);
+    *third = 1234;
+    print(*third);
 
-       mfree(second);
+    mfree(second);
 
-       fourth := cast([] i32) malloc(sizeof [128]i32);
-       print(cast(u32) fourth);
+    fourth := cast([] i32) malloc(sizeof [128]i32);
+    print(cast(u32) fourth);
 
-       fifth := cast(^i32) malloc(sizeof i32);
-       print(cast(u32) fifth);
+    fifth := cast(^i32) malloc(sizeof i32);
+    print(cast(u32) fifth);
 }
\ No newline at end of file
index c170994be11c3a444a8107b591c41c9cbf04632f..63bf046efb4a76ffa2f5698507f3492b3949ab6c 100644 (file)
@@ -705,6 +705,21 @@ CHECK(statement, AstNode* stmt) {
         case Ast_Kind_While:      return check_while((AstWhile *) stmt);
         case Ast_Kind_For:        return check_for((AstFor *) stmt);
         case Ast_Kind_Block:      return check_block((AstBlock *) stmt);
+        case Ast_Kind_Defer: {
+            if (!semstate.defer_allowed) {
+                onyx_message_add(Msg_Type_Literal,
+                    stmt->token->pos,
+                    "deferred statement not allowed in deferred block");
+                return 1;
+            }
+
+            semstate.defer_allowed = 0;
+            b32 state = check_statement(((AstDefer *) stmt)->stmt);
+            semstate.defer_allowed = 1;
+
+            return state;
+        }
+
         case Ast_Kind_Binary_Op:
             stmt->flags |= Ast_Flag_Expr_Ignored;
             return check_binaryop((AstBinaryOp *) stmt, 1);
index b2570d12398357cdb8e7707112e781f5a51322ff..a08b46e8f021dd3c19dc723b81ad7c45bf334903 100644 (file)
@@ -26,6 +26,7 @@ static const char* token_type_names[] = {
     "continue",
     "sizeof",
     "alignof",
+    "defer",
 
     "->",
     "<-",
@@ -162,6 +163,7 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {
     LITERAL_TOKEN("continue",   1, Token_Type_Keyword_Continue);
     LITERAL_TOKEN("sizeof",     1, Token_Type_Keyword_Sizeof);
     LITERAL_TOKEN("alignof",    1, Token_Type_Keyword_Alignof);
+    LITERAL_TOKEN("defer",      1, Token_Type_Keyword_Defer);
     LITERAL_TOKEN("true",       1, Token_Type_Literal_True);
     LITERAL_TOKEN("false",      1, Token_Type_Literal_False);
     LITERAL_TOKEN("->",         0, Token_Type_Right_Arrow);
index 583c5993652d5d1722cc351376e86bf65052f93e..17903d2c4ab39e4396749a25b6655d98705dc16c 100644 (file)
@@ -744,6 +744,17 @@ static AstNode* parse_statement(OnyxParser* parser) {
             break;
         }
 
+        case Token_Type_Keyword_Defer: {
+            needs_semicolon = 0;
+
+            AstDefer* defer = make_node(AstDefer, Ast_Kind_Defer);
+            defer->token = expect_token(parser, Token_Type_Keyword_Defer);
+            defer->stmt  = parse_statement(parser);
+
+            retval = (AstNode *) defer;
+            break;
+        }
+
         default:
             break;
     }
index 34f4ef5e7b118888bdee8c26d4bb691321ac2e55..4362dc7ba2d256a0ff014db9b75aa34500322621 100644 (file)
@@ -11,6 +11,8 @@ void onyx_sempass_init(bh_allocator alloc, bh_allocator node_alloc) {
 
         .global_scope = NULL,
         .curr_scope = NULL,
+
+        .defer_allowed = 1,
     };
 }
 
index cd04a31fa8fad7aa1560ec921765d5ba65005a10..0e9dca6883a0d77965e78dcd941cf00d60de6c69 100644 (file)
@@ -309,6 +309,7 @@ static b32 symres_statement(AstNode* stmt) {
         case Ast_Kind_Call:       symres_call((AstCall *) stmt);                    return 0;
         case Ast_Kind_Argument:   symres_expression((AstTyped **) &((AstArgument *)stmt)->value); return 0;
         case Ast_Kind_Block:      symres_block((AstBlock *) stmt);                  return 0;
+        case Ast_Kind_Defer:      symres_statement(((AstDefer *) stmt)->stmt);      return 0;
 
         case Ast_Kind_Break:      return 0;
         case Ast_Kind_Continue:   return 0;
index a8da138bf164e7e7a7190e9a3df5c86feb1d5ffc..4c434fde9737199fd65908391e92fc8824a56610 100644 (file)
@@ -59,6 +59,7 @@ static const char* ast_node_names[] = {
     "WHILE",
     "BREAK",
     "CONTINUE",
+    "DEFER",
 
     "AST_NODE_KIND_COUNT",
 };
index c6ac1b4606281cab548c75027cebfe93e1540f8d..2b2c8e85399e4b2b17b25b973578d42aed36c5b3 100644 (file)
@@ -255,6 +255,8 @@ COMPILE_FUNC(load_instruction,      Type* type, u32 offset);
 COMPILE_FUNC(if,                    AstIf* if_node);
 COMPILE_FUNC(while,                 AstWhile* while_node);
 COMPILE_FUNC(for,                   AstFor* for_node);
+COMPILE_FUNC(defer,                 AstDefer* defer);
+COMPILE_FUNC(deferred_stmts,        AstNode* node);
 COMPILE_FUNC(binop,                 AstBinaryOp* binop);
 COMPILE_FUNC(unaryop,               AstUnaryOp* unop);
 COMPILE_FUNC(call,                  AstCall* call);
@@ -274,6 +276,8 @@ COMPILE_FUNC(function_body, AstFunction* fd) {
         compile_statement(mod, &code, stmt);
     }
 
+    compile_deferred_stmts(mod, &code, (AstNode *) fd);
+
     WI(WI_BLOCK_END);
 
     *pcode = code;
@@ -289,6 +293,8 @@ COMPILE_FUNC(block, AstBlock* block) {
         compile_statement(mod, &code, stmt);
     }
 
+    compile_deferred_stmts(mod, &code, (AstNode *) block);
+
     WI(WI_BLOCK_END);
     bh_arr_pop(mod->structured_jump_target);
 
@@ -335,6 +341,7 @@ COMPILE_FUNC(statement, AstNode* stmt) {
         case Ast_Kind_Break:      compile_structured_jump(mod, &code, ((AstBreak *) stmt)->count); break;
         case Ast_Kind_Continue:   compile_structured_jump(mod, &code, -((AstContinue *) stmt)->count); break;
         case Ast_Kind_Block:      compile_block(mod, &code, (AstBlock *) stmt); break;
+        case Ast_Kind_Defer:      compile_defer(mod, &code, (AstDefer *) stmt); break;
         default:                  compile_expression(mod, &code, (AstTyped *) stmt); break;
     }
 
@@ -512,6 +519,8 @@ COMPILE_FUNC(if, AstIf* if_node) {
         }
     }
 
+    compile_deferred_stmts(mod, &code, (AstNode *) if_node);
+
     bh_arr_pop(mod->structured_jump_target);
 
     WI(WI_IF_END);
@@ -543,6 +552,8 @@ COMPILE_FUNC(while, AstWhile* while_node) {
     bh_arr_pop(mod->structured_jump_target);
     bh_arr_pop(mod->structured_jump_target);
 
+    compile_deferred_stmts(mod, &code, (AstNode *) while_node);
+
     WID(WI_JUMP, 0x00);
 
     WI(WI_LOOP_END);
@@ -586,6 +597,8 @@ COMPILE_FUNC(for, AstFor* for_node) {
     WI(WI_I32_ADD);
     WID(WI_LOCAL_SET, it_idx);
 
+    compile_deferred_stmts(mod, &code, (AstNode *) for_node);
+
     bh_arr_pop(mod->structured_jump_target);
     bh_arr_pop(mod->structured_jump_target);
 
@@ -597,6 +610,26 @@ COMPILE_FUNC(for, AstFor* for_node) {
     *pcode = code;
 }
 
+COMPILE_FUNC(defer, AstDefer* defer) {
+    bh_arr_push(mod->deferred_stmts, ((DeferredStmt) {
+        .depth = bh_arr_length(mod->structured_jump_target),
+        .stmt = defer->stmt,
+    }));
+}
+
+COMPILE_FUNC(deferred_stmts, AstNode* node) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    u64 depth = bh_arr_length(mod->structured_jump_target);
+
+    while (bh_arr_last(mod->deferred_stmts).depth == depth) {
+        compile_statement(mod, &code, bh_arr_last(mod->deferred_stmts).stmt);
+        bh_arr_pop(mod->deferred_stmts);
+    }
+
+    *pcode = code;
+}
+
 // NOTE: These need to be in the same order as
 // the OnyxBinaryOp enum
 static const WasmInstructionType binop_map[][4] = {
@@ -1162,6 +1195,16 @@ COMPILE_FUNC(return, AstReturn* ret) {
         compile_expression(mod, &code, ret->expr);
     }
 
+    compile_deferred_stmts(mod, &code, (AstNode *) ret);
+
+    if (bh_arr_length(mod->deferred_stmts) != 0) {
+        i32 i = bh_arr_length(mod->deferred_stmts) - 1;
+        while (i >= 0) {
+            compile_statement(mod, &code, mod->deferred_stmts[i].stmt);
+            i--;
+        } 
+    }
+
     WI(WI_RETURN);
 
     *pcode = code;
@@ -1490,6 +1533,8 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_imap_init(&module.local_map, global_heap_allocator, 16);
     bh_imap_init(&module.elem_map,  global_heap_allocator, 16);
 
+    bh_arr_new(global_heap_allocator, module.deferred_stmts, 4);
+
     return module;
 }