diff --git a/port/linux/test/pikaMain-test.cpp b/port/linux/test/pikaMain-test.cpp index c31bd60af..fd404a942 100644 --- a/port/linux/test/pikaMain-test.cpp +++ b/port/linux/test/pikaMain-test.cpp @@ -2475,3 +2475,38 @@ TEST(pikaMain, returnNullString) { obj_deinit(pikaMain); EXPECT_EQ(pikaMemNow(), 0); } + +TEST(pikaMain, for_loop_issue_1b2a3f1bdf) { + char* lines = + "res = 0\n" + "for i in range(0, 10):\n" + " if i < 3:\n" + " continue\n" + " if i > 7:\n" + " continue\n" + " for i in range(i, i+3):\n" + " res += i\n" + "\n"; + + Args* buffs = New_strBuff(); + __platform_printf("%s\n", lines); + char* pikaAsm = Parser_multiLineToAsm(buffs, lines); + __platform_printf("%s", pikaAsm); + args_deinit(buffs); + EXPECT_EQ(pikaMemNow(), 0); + + /* init */ + pikaMemInfo.heapUsedMax = 0; + PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); + /* run */ + __platform_printf("BEGIN\r\n"); + + obj_run(pikaMain, lines); + /* collect */ + int res = obj_getInt(pikaMain, "res"); + /* assert */ + EXPECT_EQ(res, 90); + /* deinit */ + obj_deinit(pikaMain); + EXPECT_EQ(pikaMemNow(), 0); +} diff --git a/src/PikaVM.c b/src/PikaVM.c index 237415177..fdfb222f0 100644 --- a/src/PikaVM.c +++ b/src/PikaVM.c @@ -74,14 +74,30 @@ static char* VMState_getConstWithInstructUnit(VMState* vs, static int32_t VMState_getAddrOffsetOfJmpBack(VMState* vs) { int offset = 0; - InstructUnit* ins_unit_now = VMState_getInstructNow(vs); + int loop_deepth = -1; + + /* find loop deepth */ while (1) { - offset += instructUnit_getSize(ins_unit_now); - ins_unit_now = VMState_getInstructWithOffset(vs, offset); + offset -= instructUnit_getSize(ins_unit_now); + InstructUnit* ins_unit_now = VMState_getInstructWithOffset(vs, offset); uint16_t invoke_deepth = instructUnit_getInvokeDeepth(ins_unit_now); enum Instruct ins = instructUnit_getInstruct(ins_unit_now); char* data = VMState_getConstWithInstructUnit(vs, ins_unit_now); - if ((0 == invoke_deepth) && (JMP == ins) && strEqu(data, "-1")) { + if ((0 == invoke_deepth) && (JEZ == ins) && strEqu(data, "2")) { + loop_deepth = instructUnit_getBlockDeepth(ins_unit_now); + break; + } + } + + offset = 0; + while (1) { + offset += instructUnit_getSize(ins_unit_now); + InstructUnit* ins_unit_now = VMState_getInstructWithOffset(vs, offset); + enum Instruct ins = instructUnit_getInstruct(ins_unit_now); + char* data = VMState_getConstWithInstructUnit(vs, ins_unit_now); + int block_deepth_now = instructUnit_getBlockDeepth(ins_unit_now); + if ((block_deepth_now == loop_deepth) && (JMP == ins) && + strEqu(data, "-1")) { return offset; } } @@ -972,16 +988,25 @@ static Arg* VM_instruction_handler_SER(PikaObj* self, VMState* vs, char* data) { static Arg* VM_instruction_handler_JEZ(PikaObj* self, VMState* vs, char* data) { int thisBlockDeepth; thisBlockDeepth = VMState_getBlockDeepthNow(vs); + int jmp_expect = fast_atoi(data); Arg* pika_assertArg = stack_popArg(&(vs->stack)); int pika_assert = arg_getInt(pika_assertArg); arg_deinit(pika_assertArg); char __else[] = "__else0"; __else[6] = '0' + thisBlockDeepth; args_setInt(self->list, __else, !pika_assert); + if (0 == pika_assert) { - /* set __else flag */ - vs->jmp = fast_atoi(data); + /* jump */ + vs->jmp = jmp_expect; } + + /* restore loop deepth */ + if (2 == jmp_expect && 0 == pika_assert) { + int block_deepth_now = VMState_getBlockDeepthNow(vs); + vs->loop_deepth = block_deepth_now; + } + return NULL; } @@ -1885,6 +1910,7 @@ static VMParameters* __pikaVM_runByteCodeFrameWithState( .globals = globals, .jmp = 0, .pc = pc, + .loop_deepth = 0, .error_code = PIKA_RES_OK, .line_error_code = PIKA_RES_OK, .try_error_code = PIKA_RES_OK, diff --git a/src/PikaVM.h b/src/PikaVM.h index bc7738915..7b14e200d 100644 --- a/src/PikaVM.h +++ b/src/PikaVM.h @@ -72,6 +72,7 @@ struct VMState { int32_t jmp; int32_t pc; ByteCodeFrame* bytecode_frame; + uint8_t loop_deepth; uint8_t error_code; uint8_t line_error_code; uint8_t try_error_code;