diff --git a/.gitignore b/.gitignore index 7cfe02d..3b39e81 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ /.kdev4 __pycache__ tests-out +build/ +.vscode/ diff --git a/ASTree.cpp b/ASTree.cpp index 851f735..e6e6c7e 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -897,7 +897,10 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) case Pyc::INSTRUMENTED_FOR_ITER_A: { PycRef iter = stack.top(); // Iterable - stack.pop(); + if (mod->verCompare(3, 12) < 0) { + // Do not pop the iterator for py 3.12+ + stack.pop(); + } /* Pop it? Don't pop it? */ int end; @@ -1163,10 +1166,13 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } break; case Pyc::JUMP_ABSOLUTE_A: + // bpo-47120: Replaced JUMP_ABSOLUTE by the relative jump JUMP_BACKWARD. + case Pyc::JUMP_BACKWARD_A: + case Pyc::JUMP_BACKWARD_NO_INTERRUPT_A: { int offs = operand; if (mod->verCompare(3, 10) >= 0) - offs *= sizeof(uint16_t); // // BPO-27129 + offs *= sizeof(uint16_t); // // BPO-27129 if (offs < pos) { if (curblock->blktype() == ASTBlock::BLK_FOR) { @@ -1678,10 +1684,37 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) case Pyc::POP_EXCEPT: /* Do nothing. */ break; + case Pyc::END_FOR: + { + stack.pop(); + + if ((opcode == Pyc::END_FOR) && (mod->majorVer() == 3) && (mod->minorVer() == 12)) { + // one additional pop for python 3.12 + stack.pop(); + } + + // end for loop here + /* TODO : Ensure that FOR loop ends here. + Due to CACHE instructions at play, the end indicated in + the for loop by pycdas is not correct, it is off by + some small amount. */ + if (curblock->blktype() == ASTBlock::BLK_FOR) { + PycRef prev = blocks.top(); + blocks.pop(); + + curblock = blocks.top(); + curblock->append(prev.cast()); + } + else { + fprintf(stderr, "Wrong block type %i for END_FOR\n", curblock->blktype()); + } + } + break; case Pyc::POP_TOP: { PycRef value = stack.top(); stack.pop(); + if (!curblock->inited()) { if (curblock->blktype() == ASTBlock::BLK_WITH) { curblock.cast()->setExpr(value); diff --git a/FastStack.h b/FastStack.h index 3f8950c..b91ec71 100644 --- a/FastStack.h +++ b/FastStack.h @@ -30,6 +30,11 @@ public: { if (m_ptr > -1) m_stack[m_ptr--] = nullptr; + else { + #ifdef BLOCK_DEBUG + fprintf(stderr, "pop from empty stack\n"); + #endif + } } PycRef top(int i = 1) const diff --git a/bytecode.cpp b/bytecode.cpp index 7821459..c6b7cba 100644 --- a/bytecode.cpp +++ b/bytecode.cpp @@ -472,6 +472,10 @@ void bc_disasm(std::ostream& pyc_output, PycRef code, PycModule* mod, case Pyc::INSTRUMENTED_POP_JUMP_IF_FALSE_A: case Pyc::INSTRUMENTED_POP_JUMP_IF_TRUE_A: { + /* TODO: Fix offset based on CACHE instructions. + Offset is relative to next non-CACHE instruction + and thus will be printed lower than actual value. + See TODO @ END_FOR ASTree.cpp */ int offs = operand; if (mod->verCompare(3, 10) >= 0) offs *= sizeof(uint16_t); // BPO-27129 diff --git a/tests/compiled/test_loops3.3.12.pyc b/tests/compiled/test_loops3.3.12.pyc new file mode 100644 index 0000000..efb575c Binary files /dev/null and b/tests/compiled/test_loops3.3.12.pyc differ diff --git a/tests/input/test_loops3.py b/tests/input/test_loops3.py new file mode 100644 index 0000000..5f2c036 --- /dev/null +++ b/tests/input/test_loops3.py @@ -0,0 +1,34 @@ +def loop1(): + iterable = [1, 2, 3] + for item in iterable: + pass + +loop1() + +def loop2(): + for i in range(2): + print(i) + +loop2() + +def loop3(): + def loop(): + x = (1,2,3) + l = [] + for i in x: + l.append(i) + return l + + return loop() + +loop3() + +def loop4(): + for i in range(3): + for j in range(2): + print(i*j) + +loop4() + +for j in [1,2,3][::-1]: + print("hi", j) diff --git a/tests/tokenized/test_loops3.txt b/tests/tokenized/test_loops3.txt new file mode 100644 index 0000000..62ee5d4 --- /dev/null +++ b/tests/tokenized/test_loops3.txt @@ -0,0 +1,46 @@ +def loop1 ( ) : + +iterable = [ 1 , 2 , 3 ] +for item in iterable : + +pass + + +loop1 ( ) +def loop2 ( ) : + +for i in range ( 2 ) : + +print ( i ) + + +loop2 ( ) +def loop3 ( ) : + +def loop ( ) : + +x = ( 1 , 2 , 3 ) +l = [ ] +for i in x : + +l . append ( i ) + +return l + +return loop ( ) + +loop3 ( ) +def loop4 ( ) : + +for i in range ( 3 ) : + +for j in range ( 2 ) : + +print ( i * j ) + + + +loop4 ( ) +for j in [ 1 , 2 , 3 ] [ : : - 1 ] : + +print ( 'hi' , j )