From f5eeed675959bc6665db99b23b58b3cb69e89e90 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 1 Sep 2016 20:44:17 -0400 Subject: [PATCH] 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. In Python 2.7+ it's a single op. --- .../04_while_and_stmt_one_line.pyc | Bin 0 -> 230 bytes .../bug26/04_while_and_stmt_one_line.py | 9 +++++++ uncompyle6/scanners/scanner2.py | 25 ++++++++++++------ uncompyle6/scanners/scanner26.py | 21 +++++++++------ 4 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 test/bytecode_2.7/04_while_and_stmt_one_line.pyc create mode 100644 test/simple_source/bug26/04_while_and_stmt_one_line.py diff --git a/test/bytecode_2.7/04_while_and_stmt_one_line.pyc b/test/bytecode_2.7/04_while_and_stmt_one_line.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b65d9e169ed7a7a0301284c3e9c899b8e23ea09 GIT binary patch literal 230 zcmZSn%*$1J>O^=l0~9a;X$K%KHUbi<3=CO}3@Ho@&5R6DObit=45>^EMY= 2.3 and - code[j] == self.opc.LIST_APPEND): # list comprehension + self.opc.opname[code[j]] == 'LIST_APPEND'): # list comprehension + stmts.remove(s) + continue + elif code[s] == self.opc.POP_TOP: + prev = code[self.prev[s]] + if (prev == self.opc.ROT_TWO or + self.version <= 2.6 and prev == self.opc.JUMP_IF_FALSE): stmts.remove(s) continue - elif code[s] == self.opc.POP_TOP and code[self.prev[s]] == self.opc.ROT_TWO: - stmts.remove(s) - continue elif code[s] in self.designator_ops: j = self.prev[s] while code[j] in self.designator_ops: @@ -654,7 +663,7 @@ class Scanner2(scan.Scanner): 'end': pre[target]}) return - # Is it an "and" inside an "if" block + # Is it an "and" inside an "if" or "while" block if op == self.opc.PJIF: # Search for other POP_JUMP_IF_FALSE targetting the same op, # in current statement, starting from current offset, and filter diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 5284d45c..12f3c0c2 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -71,12 +71,20 @@ class Scanner26(scan.Scanner2): return def disassemble(self, co, classname=None, code_objects={}, show_asm=None): - ''' - Disassemble a code object, returning a list of 'Token'. + """ + Pick out tokens from an uncompyle6 code object, and transform them, + returning a list of uncompyle6 'Token's. - The main part of this procedure is modelled after - dis.disassemble(). - ''' + The tranformations are made to assist the deparsing grammar. + Specificially: + - various types of LOAD_CONST's are categorized in terms of what they load + - COME_FROM instructions are added to assist parsing control structures + - MAKE_FUNCTION and FUNCTION_CALLS append the number of positional arguments + + Also, when we encounter certain tokens, we add them to a set which will cause custom + grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST + cause specific rules for the specific number of arguments they take. + """ show_asm = self.show_asm if not show_asm else show_asm # show_asm = 'both' @@ -102,9 +110,6 @@ class Scanner26(scan.Scanner2): self.build_lines_data(co, n) self.build_prev_op(n) - # linestarts contains block code adresses (addr,block) - self.linestarts = list(self.opc.findlinestarts(co)) - # class and names if classname: classname = '_' + classname.lstrip('_') + '__'