From ff6970101e5732380a4db8139db109a4695689a6 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 26 Oct 2024 16:49:01 +0800 Subject: [PATCH] ... --- include/pocketpy/interpreter/frame.h | 2 -- src/compiler/compiler.c | 47 +++++++++++++++++----------- src/interpreter/ceval.c | 17 +++++----- src/interpreter/frame.c | 28 ----------------- 4 files changed, 37 insertions(+), 57 deletions(-) diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 21e82a44..e3f0ce8e 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/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); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 39c6e761..ff339812 100644 --- a/src/compiler/compiler.c +++ b/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)) { diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 5bfeaced..50fdd7a2 100644 --- a/src/interpreter/ceval.c +++ b/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(); } diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index f339f528..da1b54e4 100644 --- a/src/interpreter/frame.c +++ b/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) {