blueloveTH 1 год назад
Родитель
Сommit
ff6970101e
4 измененных файлов с 37 добавлено и 57 удалено
  1. 0 2
      include/pocketpy/interpreter/frame.h
  2. 28 19
      src/compiler/compiler.c
  3. 9 8
      src/interpreter/ceval.c
  4. 0 28
      src/interpreter/frame.c

+ 0 - 2
include/pocketpy/interpreter/frame.h

@@ -56,8 +56,6 @@ py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name);
 py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name);
 
 int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*);
-void Frame__prepare_jump_break(Frame* self, ValueStack*, int);
-int Frame__exit_block(Frame* self, ValueStack*, int);
 
 UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock);
 void Frame__set_unwind_target(Frame* self, py_TValue* sp);

+ 28 - 19
src/compiler/compiler.c

@@ -72,7 +72,7 @@ typedef struct Expr Expr;
 
 static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level);
 static void Ctx__dtor(Ctx* self);
-static int Ctx__get_loop(Ctx* self, bool* has_context);
+static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break);
 static int Ctx__enter_block(Ctx* self, CodeBlockType type);
 static void Ctx__exit_block(Ctx* self);
 static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line);
@@ -1107,18 +1107,30 @@ static void Ctx__dtor(Ctx* self) {
 
 static bool is_small_int(int64_t value) { return value >= INT16_MIN && value <= INT16_MAX; }
 
-static bool is_context_block(CodeBlock* block) {
-    return block->type >= CodeBlockType_FOR_LOOP && block->type <= CodeBlockType_FINALLY;
-}
-
-static int Ctx__get_loop(Ctx* self, bool* has_context) {
+static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break) {
     int index = self->curr_iblock;
-    *has_context = false;
     while(index >= 0) {
         CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, index);
-        if(block->type == CodeBlockType_FOR_LOOP) break;
-        if(block->type == CodeBlockType_WHILE_LOOP) break;
-        if(is_context_block(block)) *has_context = true;
+        switch(block->type) {
+            case CodeBlockType_WHILE_LOOP: return index;
+            case CodeBlockType_FOR_LOOP: {
+                if(is_break) Ctx__emit_(self, OP_POP_TOP, BC_NOARG, line);
+                return index;
+            }
+            case CodeBlockType_WITH: {
+                Ctx__emit_(self, OP_POP_TOP, BC_NOARG, line);
+                break;
+            }
+            case CodeBlockType_EXCEPT: {
+                Ctx__emit_(self, OP_END_EXC_HANDLING, 1, line);
+                break;
+            }
+            case CodeBlockType_FINALLY: {
+                Ctx__emit_(self, OP_END_FINALLY, 1, line);
+                break;
+            }
+            default: break;
+        }
         index = block->parent;
     }
     return index;
@@ -1133,14 +1145,9 @@ static int Ctx__enter_block(Ctx* self, CodeBlockType type) {
 
 static void Ctx__exit_block(Ctx* self) {
     CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, self->curr_iblock);
-    CodeBlockType curr_type = block->type;
     block->end = self->co->codes.length;
     self->curr_iblock = block->parent;
     assert(self->curr_iblock >= 0);
-    if(curr_type == CodeBlockType_FOR_LOOP) {
-        // add a no op here to make block check work
-        Ctx__emit_virtual(self, OP_NO_OP, BC_NOARG, BC_KEEPLINE, true);
-    }
 }
 
 static void Ctx__s_emit_decorators(Ctx* self, int count) {
@@ -2540,19 +2547,21 @@ static Error* compile_stmt(Compiler* self) {
     }
     advance();
     int kw_line = prev()->line;  // backup line number
-    bool has_context = false;
-    int curr_loop_block = Ctx__get_loop(ctx(), &has_context);
     switch(prev()->type) {
-        case TK_BREAK:
+        case TK_BREAK: {
+            int curr_loop_block = Ctx__prepare_loop_divert(ctx(), kw_line, true);
             if(curr_loop_block < 0) return SyntaxError(self, "'break' outside loop");
             Ctx__emit_(ctx(), OP_LOOP_BREAK, curr_loop_block, kw_line);
             consume_end_stmt();
             break;
-        case TK_CONTINUE:
+        }
+        case TK_CONTINUE: {
+            int curr_loop_block = Ctx__prepare_loop_divert(ctx(), kw_line, false);
             if(curr_loop_block < 0) return SyntaxError(self, "'continue' not properly in loop");
             Ctx__emit_(ctx(), OP_LOOP_CONTINUE, curr_loop_block, kw_line);
             consume_end_stmt();
             break;
+        }
         case TK_YIELD:
             if(self->contexts.length <= 1) return SyntaxError(self, "'yield' outside function");
             if(match_end_stmt(self)) {

+ 9 - 8
src/interpreter/ceval.c

@@ -617,13 +617,9 @@ FrameResult VM__run_top_frame(VM* self) {
                 }
             }
             case OP_LOOP_CONTINUE: {
-                int target = Frame__ip(frame) + (int16_t)byte.arg;
-                Frame__prepare_jump_break(frame, &self->stack, target);
                 DISPATCH_JUMP((int16_t)byte.arg);
             }
             case OP_LOOP_BREAK: {
-                int target = Frame__ip(frame) + (int16_t)byte.arg;
-                Frame__prepare_jump_break(frame, &self->stack, target);
                 DISPATCH_JUMP((int16_t)byte.arg);
             }
             /*****************************************/
@@ -1023,10 +1019,15 @@ FrameResult VM__run_top_frame(VM* self) {
                 DISPATCH();
             }
             case OP_END_FINALLY: {
-                if(self->curr_exception.type) {
-                    assert(self->is_curr_exc_handled);
-                    // revert the exception handling if needed
-                    self->is_curr_exc_handled = false;
+                if(byte.arg == BC_NOARG) {
+                    if(self->curr_exception.type) {
+                        assert(self->is_curr_exc_handled);
+                        // revert the exception handling if needed
+                        self->is_curr_exc_handled = false;
+                    }
+                } else {
+                    // break or continue inside finally block
+                    py_clearexc(NULL);
                 }
                 DISPATCH();
             }

+ 0 - 28
src/interpreter/frame.c

@@ -79,34 +79,6 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
     return c11__at(CodeBlock, &self->co->blocks, iblock)->end;
 }
 
-void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target) {
-    int iblock = Frame__iblock(self);
-    if(target >= self->co->codes.length) {
-        while(iblock >= 0)
-            iblock = Frame__exit_block(self, _s, iblock);
-    } else {
-        // BUG (solved)
-        // for i in range(4):
-        //     _ = 0
-        // # if there is no op here, the block check will fail
-        // while i: --i
-        int next_block = c11__at(BytecodeEx, &self->co->codes_ex, target)->iblock;
-        while(iblock >= 0 && iblock != next_block)
-            iblock = Frame__exit_block(self, _s, iblock);
-        assert(iblock == next_block);
-    }
-}
-
-int Frame__exit_block(Frame* self, ValueStack* _s, int iblock) {
-    CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock);
-    if(block->type == CodeBlockType_FOR_LOOP || block->type == CodeBlockType_WITH) {
-        _s->sp--;  // pop iterator or context variable
-    } else if(block->type == CodeBlockType_EXCEPT || block->type == CodeBlockType_FINALLY) {
-        py_clearexc(NULL);
-    }
-    return block->parent;
-}
-
 UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock) {
     UnwindTarget* uw;
     for(uw = self->uw_list; uw; uw = uw->next) {