def pop_with_body_instrs(setup_with_instr, queue): """ Pop instructions from `queue` that form the body of a with block. """ body_instrs = popwhile(op.is_not(setup_with_instr.arg), queue, side='left') # Last two instructions should always be POP_BLOCK, LOAD_CONST(None). # These don't correspond to anything in the AST, so remove them here. load_none = body_instrs.pop() expect(load_none, instrs.LOAD_CONST, "at end of with-block") pop_block = body_instrs.pop() expect(pop_block, instrs.POP_BLOCK, "at end of with-block") if load_none.arg is not None: raise DecompilationError( "Expected LOAD_CONST(None), but got " "%r instead" % (load_none) ) # Target of the setup_with should be a WITH_CLEANUP instruction followed by # an END_FINALLY. Neither of these correspond to anything in the AST. with_cleanup = queue.popleft() expect(with_cleanup, instrs.WITH_CLEANUP, "at end of with-block") end_finally = queue.popleft() expect(end_finally, instrs.END_FINALLY, "at end of with-block") return body_instrs
def pop_loop_instrs(setup_loop_instr, queue): """ Determine whether setup_loop_instr is setting up a for-loop or a while-loop. Then pop the loop instructions from queue. The easiest way to tell the difference is to look at the target of the JUMP_ABSOLUTE instruction at the end of the loop. If it jumps to a FOR_ITER, then this is a for-loop. Otherwise it's a while-loop. The jump we want to inspect is the first JUMP_ABSOLUTE instruction prior to the jump target of `setup_loop_instr`. Parameters ---------- setup_loop_instr : instructions.SETUP_LOOP First instruction of the loop being parsed. queue : collections.deque Queue of unprocessed instructions. Returns ------- loop_type : str, {'for', 'while'} The kind of loop being constructed. loop_instrs : deque The instructions forming body of the loop. else_instrs : deque The instructions forming the else-block of the loop. Side Effects ------------ Pops all returned instructions from `queue`. """ # Grab everything from left side of the queue until the jump target of # SETUP_LOOP. body = popwhile(op.is_not(setup_loop_instr.arg), queue, side='left') # Anything after the last POP_BLOCK instruction is the else-block. else_body = popwhile(not_a(instrs.POP_BLOCK), body, side='right') jump_to_top, pop_block = body[-2], body[-1] if not isinstance(jump_to_top, instrs.JUMP_ABSOLUTE): raise DecompilationError( "Penultimate instruction of loop body is " "%s, not JUMP_ABSOLUTE." % jump_to_top, ) if not isinstance(pop_block, instrs.POP_BLOCK): raise DecompilationError( "Last instruction of loop body is " "%s, not pop_block." % pop_block, ) loop_expr = jump_to_top.arg if isinstance(loop_expr, instrs.FOR_ITER): return 'for', body, else_body return 'while', body, else_body