added #no_close option to for loops
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 3 Dec 2021 17:09:41 +0000 (11:09 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 3 Dec 2021 17:09:41 +0000 (11:09 -0600)
include/astnodes.h
scripts/run_tests.onyx
src/checker.c
src/parser.c
src/wasm_emit.c

index 581391a99beb03e1fc5aaca5a19c44bc996f6acc..3b76bd00ea0db0702691e3f8b53832bc8d4a6fca 100644 (file)
@@ -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;
index 330d218c94394bef4fabbe9cc2662d0fd69623d9..0895c4a385bcc439623b6a6dacd81b7d4dce751b 100644 (file)
@@ -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
index adcd680de0440d571d660bbe0543d85575787c37..2078bc389f8b47c463c62be7d6034c10fd942fc8 100644 (file)
@@ -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;
index b3e770dd4aee6ab040902fb6dd1ecefcadb89d6d..05832ab1755b5f055ea7177bb334e461df3de6ba 100644 (file)
@@ -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;
     }
index 4f4988efd2c84331d84bfee8ecbdc1abafcb09b7..b7aea1a65b6aaf7858a41371e47d9cc9096bd34d 100644 (file)
@@ -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;
 }