From f19f1679674cd1853c346ed95b1aad8ea6416393 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 22 May 2012 09:19:17 -0400 Subject: [PATCH 1/4] DOC: added docstring. --- meta/bytecodetools/pyc_file.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/meta/bytecodetools/pyc_file.py b/meta/bytecodetools/pyc_file.py index 33120ad..7105cae 100644 --- a/meta/bytecodetools/pyc_file.py +++ b/meta/bytecodetools/pyc_file.py @@ -10,7 +10,11 @@ import marshal def extract(binary): + ''' + Extract a code object from a binary pyc file. + :param binary: a sequence of bytes from a pyc file. + ''' if len(binary) <= 8: raise Exception("Binary pyc must be greater than 8 bytes (got %i)" % len(binary)) From 1e8c076f4788bfc01e97307f5f61426d2de452d8 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Jul 2012 11:36:44 -0500 Subject: [PATCH 2/4] ENH: added is_jump property --- meta/bytecodetools/instruction.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meta/bytecodetools/instruction.py b/meta/bytecodetools/instruction.py index 0fb2570..159abaa 100644 --- a/meta/bytecodetools/instruction.py +++ b/meta/bytecodetools/instruction.py @@ -28,6 +28,11 @@ def __init__(self, i= -1, op=None, lineno=None): @property def opname(self): return opcode.opname[self.op] + + @property + def is_jump(self): + return self.op in opcode.hasjrel or self.op in opcode.hasjabs + @property def to(self): if self.op in opcode.hasjrel: From c3975b8d51d41d830a11e403a2aa7ac8fc02c572 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Jul 2012 11:37:51 -0500 Subject: [PATCH 3/4] FIX: fixed bug from issue #4. (return statements inside of control flow) --- meta/decompiler/control_flow_instructions.py | 28 +++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/meta/decompiler/control_flow_instructions.py b/meta/decompiler/control_flow_instructions.py index 70fc72c..83a6bfb 100644 --- a/meta/decompiler/control_flow_instructions.py +++ b/meta/decompiler/control_flow_instructions.py @@ -706,7 +706,6 @@ def JUMP_IF_TRUE_OR_POP(self, instr): def make_if(self, instr, left, and_block): block = [instr] + and_block[:-1] -# maxmax = max(block, key=lambda ins: (0, 0) if (ins.op not in JUMP_OPS) else (ins.oparg, ins.i)) maxmax = max(block, key=lambda ins: (0, 0) if (ins.op not in JUMP_OPS) else (self.jump_map.get(ins.oparg, ins.oparg), ins.i)) idx = block.index(maxmax) @@ -714,25 +713,29 @@ def make_if(self, instr, left, and_block): assert idx is not None hi = self.process_logic(block[:idx + 1]) + if hi.right is None and hi.parent is None: if instr.opname == 'POP_JUMP_IF_TRUE': cond = _ast.UnaryOp(op=_ast.Not(), operand=left, lineno=0, col_offset=0) -# cond = ast.Not(left, lineno=instr.lineno) else: cond = left else: cond = self.logic_ast(instr, left, hi) - -# if block[-1].opname == 'JUMP_ABSOLUTE': -# pass - - body = self.decompile_block(block[idx + 1:]).stmnt() - -# tests = [(cond, body)] - + jump = and_block[-1] - else_block = self.make_block(jump.to, inclusive=False, raise_=False) + + if jump.opname == 'RETURN_VALUE': + body_block = block[idx + 1:] + [jump] + else: + body_block = block[idx + 1:] + + body = self.decompile_block(body_block).stmnt() + + if jump.is_jump: + else_block = self.make_block(jump.to, inclusive=False, raise_=False) + else: # it is a return + else_block = [] if len(else_block): else_ = self.decompile_block(else_block).stmnt() @@ -757,7 +760,7 @@ def POP_JUMP_IF_TRUE(self, instr): and_block = self.gather_jumps(instr) - if and_block[-1].opname in ['JUMP_FORWARD', 'JUMP_ABSOLUTE']: + if and_block[-1].opname in ['JUMP_FORWARD', 'JUMP_ABSOLUTE', 'RETURN_VALUE']: self.make_if(instr, left, and_block) return @@ -774,6 +777,7 @@ def POP_JUMP_IF_FALSE(self, instr): and_block = self.gather_jumps(instr) #This is an IF statement + if and_block[-1].opname in ['JUMP_FORWARD', 'JUMP_ABSOLUTE', 'RETURN_VALUE']: #this happens if the function was going to return anyway From 42ef1655009fff057fe3b036ff8c223262ee7a0c Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Jul 2012 11:38:40 -0500 Subject: [PATCH 4/4] ENH: added test for issue #4 --- meta/decompiler/tests/test_decompiler.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meta/decompiler/tests/test_decompiler.py b/meta/decompiler/tests/test_decompiler.py index 7927807..edaaf2a 100644 --- a/meta/decompiler/tests/test_decompiler.py +++ b/meta/decompiler/tests/test_decompiler.py @@ -515,6 +515,17 @@ def test_aug_assign_slice(self): stmnt = 'c[idx:a:3] += b[idx:a]' self.statement(stmnt) + def test_issue_4(self): + example = """ +def example(idx): + if(idx == 2 or idx == 3): + idx = 1 + return None + i += 1 + return None + """ + self.statement(example) + if __name__ == "__main__": #import sys;sys.argv = ['', 'Test.test_assign']