From: Brendan Hansen Date: Thu, 30 Jul 2020 20:04:15 +0000 (-0500) Subject: Added deferred statements; maybe a little buggy X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=60b7ec273529a300972513ccbeb0597ae2646fac;p=onyx.git Added deferred statements; maybe a little buggy --- diff --git a/docs/plan b/docs/plan index a8f1956b..c1ce3901 100644 --- 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. diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index af363574..60e592fe 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; diff --git a/include/onyxlex.h b/include/onyxlex.h index 5410ae4b..e122fda3 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -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, diff --git a/include/onyxsempass.h b/include/onyxsempass.h index f2863d65..ea504989 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -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; diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 6be722bd..3471b64f 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -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. diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index 7e44579b..5159d580 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -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' diff --git a/misc/onyx.vim b/misc/onyx.vim index e8c8b761..73eb5d1b 100644 --- a/misc/onyx.vim +++ b/misc/onyx.vim @@ -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 4f3f842f..1950f6fb 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/alloc.onyx b/progs/alloc.onyx index 11ff27c8..f5899f07 100644 --- a/progs/alloc.onyx +++ b/progs/alloc.onyx @@ -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; } diff --git a/progs/alloc_test.onyx b/progs/alloc_test.onyx index 4b9371e6..f6d6dea7 100644 --- a/progs/alloc_test.onyx +++ b/progs/alloc_test.onyx @@ -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 diff --git a/src/onyxchecker.c b/src/onyxchecker.c index c170994b..63bf046e 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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); diff --git a/src/onyxlex.c b/src/onyxlex.c index b2570d12..a08b46e8 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -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); diff --git a/src/onyxparser.c b/src/onyxparser.c index 583c5993..17903d2c 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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; } diff --git a/src/onyxsempass.c b/src/onyxsempass.c index 34f4ef5e..4362dc7b 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -11,6 +11,8 @@ void onyx_sempass_init(bh_allocator alloc, bh_allocator node_alloc) { .global_scope = NULL, .curr_scope = NULL, + + .defer_allowed = 1, }; } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index cd04a31f..0e9dca68 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; diff --git a/src/onyxutils.c b/src/onyxutils.c index a8da138b..4c434fde 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -59,6 +59,7 @@ static const char* ast_node_names[] = { "WHILE", "BREAK", "CONTINUE", + "DEFER", "AST_NODE_KIND_COUNT", }; diff --git a/src/onyxwasm.c b/src/onyxwasm.c index c6ac1b46..2b2c8e85 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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; }