From: Brendan Hansen Date: Fri, 3 Dec 2021 17:09:41 +0000 (-0600) Subject: added #no_close option to for loops X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=dc22c5fab32b0da9c681e8c2e1ec18d4b0eb048c;p=onyx.git added #no_close option to for loops --- diff --git a/include/astnodes.h b/include/astnodes.h index 581391a9..3b76bd00 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -753,6 +753,7 @@ struct AstFor { // ROBUSTNESS: This should be able to be set by a compile time variable at some point. // But for now, this will do. b32 by_pointer : 1; + b32 no_close : 1; }; struct AstIfWhile { AstNode_base; diff --git a/scripts/run_tests.onyx b/scripts/run_tests.onyx index 330d218c..0895c4a3 100644 --- a/scripts/run_tests.onyx +++ b/scripts/run_tests.onyx @@ -45,7 +45,8 @@ distributor :: (arr: [] $T) -> Iterator(T) { } close :: (use c: ^Context($T)) { - // This will leak because it shouldn't be freed. + sync.mutex_destroy(^c.mutex); + cfree(c); } c := new(Context(T)); @@ -117,7 +118,7 @@ find_onyx_files :: (root: str, cases: ^[..] Test_Case) { } test_cases :: (cases) => { - for *cases { + for #no_close *cases { printf("[{}] Running test {}...\n", context.thread_id, it.source_file); proc := io.process_spawn(onyx_cmd, .["run", it.source_file]); @@ -191,5 +192,7 @@ main :: (args) => { test_cases(^case_iterator); } + case_iterator->close(); + println("Done"); } \ No newline at end of file diff --git a/src/checker.c b/src/checker.c index adcd680d..2078bc38 100644 --- a/src/checker.c +++ b/src/checker.c @@ -205,6 +205,8 @@ CheckStatus check_while(AstIfWhile* whilenode) { } CheckStatus check_for(AstFor* fornode) { + if (fornode->flags & Ast_Flag_Has_Been_Checked) goto fornode_expr_checked; + CHECK(expression, &fornode->iter); resolve_expression_type(fornode->iter); @@ -288,6 +290,14 @@ CheckStatus check_for(AstFor* fornode) { if (fornode->loop_type == For_Loop_Invalid) ERROR_(error_loc, "Cannot iterate over a '%s'.", type_get_name(iter_type)); + if (fornode->no_close && fornode->loop_type != For_Loop_Iterator) { + onyx_report_warning(error_loc, "Warning: #no_close here is meaningless as the iterable is not an iterator."); + } + + fornode->flags |= Ast_Flag_Has_Been_Checked; + +fornode_expr_checked: + CHECK(block, fornode->stmt); return Check_Success; diff --git a/src/parser.c b/src/parser.c index b3e770dd..05832ab1 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1097,6 +1097,10 @@ static AstFor* parse_for_stmt(OnyxParser* parser) { AstFor* for_node = make_node(AstFor, Ast_Kind_For); for_node->token = expect_token(parser, Token_Type_Keyword_For); + if (parse_possible_directive(parser, "no_close")) { + for_node->no_close = 1; + } + if (consume_token_if_next(parser, '^')) { for_node->by_pointer = 1; } diff --git a/src/wasm_emit.c b/src/wasm_emit.c index 4f4988ef..b7aea1a6 100644 --- a/src/wasm_emit.c +++ b/src/wasm_emit.c @@ -334,7 +334,7 @@ EMIT_FUNC(enter_structured_block, StructuredBlockType sbt) { /* SBT_Basic_Loop */ 0, /* SBT_Continue_Loop */ 2, }; - + static const WasmInstructionType block_instrs[SBT_Count] = { /* SBT_Basic_Block */ WI_BLOCK_START, /* SBT_Breakable_Block */ WI_BLOCK_START, @@ -553,7 +553,7 @@ EMIT_FUNC(assignment_of_array, AstTyped* left, AstTyped* right) { emit_expression(mod, &code, al->values[i]); emit_store_instruction(mod, &code, elem_type, i * elem_size); } - + local_raw_free(mod->local_alloc, WASM_TYPE_PTR); } else { @@ -595,7 +595,7 @@ EMIT_FUNC(compound_assignment, AstBinaryOp* assign) { u64 offset = 0; emit_location_return_offset(mod, &code, lval, &offset); WIL(WI_LOCAL_GET, expr_tmp); - + local_raw_free(mod->local_alloc, wt); emit_store_instruction(mod, &code, lval->type, offset); } @@ -1008,22 +1008,24 @@ EMIT_FUNC(for_iterator, AstFor* for_node, u64 iter_local) { // Enter a deferred statement for the auto-close emit_enter_structured_block(mod, &code, SBT_Basic_Block); - TypeWithOffset close_func_type; - type_linear_member_lookup(for_node->iter->type, 2, &close_func_type); - i32 close_type_idx = generate_type_idx(mod, close_func_type.type); - - WasmInstruction* close_instructions = bh_alloc_array(global_heap_allocator, WasmInstruction, 8); - close_instructions[0] = (WasmInstruction) { WI_LOCAL_GET, { .l = iterator_close_func } }; - close_instructions[1] = (WasmInstruction) { WI_I32_CONST, { .l = mod->null_proc_func_idx } }; - close_instructions[2] = (WasmInstruction) { WI_I32_NE, { .l = 0x00 } }; - close_instructions[3] = (WasmInstruction) { WI_IF_START, { .l = 0x40 } }; - close_instructions[4] = (WasmInstruction) { WI_LOCAL_GET, { .l = iterator_data_ptr } }; - close_instructions[5] = (WasmInstruction) { WI_LOCAL_GET, { .l = iterator_close_func } }; - close_instructions[6] = (WasmInstruction) { WI_CALL_INDIRECT, { .l = close_type_idx } }; - close_instructions[7] = (WasmInstruction) { WI_IF_END, { .l = 0x00 } }; - - emit_defer_code(mod, &code, close_instructions, 8); - + if (!for_node->no_close) { + TypeWithOffset close_func_type; + type_linear_member_lookup(for_node->iter->type, 2, &close_func_type); + i32 close_type_idx = generate_type_idx(mod, close_func_type.type); + + WasmInstruction* close_instructions = bh_alloc_array(global_heap_allocator, WasmInstruction, 8); + close_instructions[0] = (WasmInstruction) { WI_LOCAL_GET, { .l = iterator_close_func } }; + close_instructions[1] = (WasmInstruction) { WI_I32_CONST, { .l = mod->null_proc_func_idx } }; + close_instructions[2] = (WasmInstruction) { WI_I32_NE, { .l = 0x00 } }; + close_instructions[3] = (WasmInstruction) { WI_IF_START, { .l = 0x40 } }; + close_instructions[4] = (WasmInstruction) { WI_LOCAL_GET, { .l = iterator_data_ptr } }; + close_instructions[5] = (WasmInstruction) { WI_LOCAL_GET, { .l = iterator_close_func } }; + close_instructions[6] = (WasmInstruction) { WI_CALL_INDIRECT, { .l = close_type_idx } }; + close_instructions[7] = (WasmInstruction) { WI_IF_END, { .l = 0x00 } }; + + emit_defer_code(mod, &code, close_instructions, 8); + } + emit_enter_structured_block(mod, &code, SBT_Breakable_Block); emit_enter_structured_block(mod, &code, SBT_Continue_Loop); @@ -1035,7 +1037,7 @@ EMIT_FUNC(for_iterator, AstFor* for_node, u64 iter_local) { // CLEANUP: Calling a function is way too f-ing complicated. FACTOR IT!! u64 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top); - + TypeWithOffset next_func_type; type_linear_member_lookup(for_node->iter->type, 1, &next_func_type); Type* return_type = next_func_type.type->Function.return_type; @@ -1046,7 +1048,7 @@ EMIT_FUNC(for_iterator, AstFor* for_node, u64 iter_local) { u64 reserve_size = return_size; bh_align(reserve_size, 16); - + WID(WI_GLOBAL_GET, stack_top_idx); WID(WI_PTR_CONST, reserve_size); WI(WI_PTR_ADD); @@ -1074,7 +1076,7 @@ EMIT_FUNC(for_iterator, AstFor* for_node, u64 iter_local) { WID(WI_COND_JUMP, 0x01); emit_block(mod, &code, for_node->stmt, 0); - WID(WI_JUMP, 0x00); + WID(WI_JUMP, 0x00); emit_leave_structured_block(mod, &code); emit_leave_structured_block(mod, &code); @@ -1425,7 +1427,7 @@ EMIT_FUNC(unaryop, AstUnaryOp* unop) { // simple structs/primitives (y, x) // // Linear memory stack: -// +// // ... | struct-like arguments (z) | variadic arguments (va) | return space | ... // // The interesting part from above is the fact that 'y' gets passed on the WASM stack, not the linear memory @@ -1690,7 +1692,7 @@ EMIT_FUNC(intrinsic_call, AstCall* call) { emit_intrinsic_memory_copy(mod, &code); } break; - case ONYX_INTRINSIC_MEMORY_FILL: + case ONYX_INTRINSIC_MEMORY_FILL: if (context.options->use_post_mvp_features) { WIL(WI_MEMORY_FILL, 0x00); } else { @@ -2236,7 +2238,7 @@ EMIT_FUNC(compound_store, Type* type, u64 offset, b32 location_first) { fori (i, 0, elem_count) { type_linear_member_lookup(type, i, &two); - u64 tmp_idx = temp_locals[i]; + u64 tmp_idx = temp_locals[i]; WIL(WI_LOCAL_GET, loc_idx); WIL(WI_LOCAL_GET, tmp_idx); emit_store_instruction(mod, &code, two.type, offset + two.offset); @@ -2423,7 +2425,7 @@ EMIT_FUNC(if_expression, AstIfExpression* if_expr) { b32 result_is_local = (b32) ((result_local & LOCAL_IS_WASM) != 0); bh_imap_put(&mod->local_map, (u64) if_expr, result_local); - emit_expression(mod, &code, if_expr->cond); + emit_expression(mod, &code, if_expr->cond); emit_enter_structured_block(mod, &code, SBT_Basic_If); if (!result_is_local) emit_local_location(mod, &code, (AstLocal *) if_expr, &offset); @@ -2538,7 +2540,7 @@ EMIT_FUNC(location, AstTyped* expr) { if (offset != 0) { WID(WI_PTR_CONST, offset); WI(WI_PTR_ADD); - } + } *pcode = code; } @@ -3344,7 +3346,7 @@ static void emit_export_directive(OnyxWasmModule* mod, AstDirectiveExport* expor shput(mod->exports, export->export_name->text, wasm_export); mod->export_count++; - + token_toggle_end(export->export_name); return; }