From fd44d2e19f1305f4e5850c0ed0f8826fb556cbaa Mon Sep 17 00:00:00 2001 From: Mysterie Date: Thu, 14 Jun 2012 14:48:08 +0200 Subject: [PATCH] fix for the with statement --- uncompyle2/Scanner25.py | 77 ++++++++++++++++++++++++++++++++--------- uncompyle2/Scanner26.py | 71 +++++++++++++++++++++++++++---------- uncompyle2/__init__.py | 6 ++-- 3 files changed, 117 insertions(+), 37 deletions(-) diff --git a/uncompyle2/Scanner25.py b/uncompyle2/Scanner25.py index 2f763d92..8e74051a 100755 --- a/uncompyle2/Scanner25.py +++ b/uncompyle2/Scanner25.py @@ -57,9 +57,9 @@ class Scanner: # linestarts contains bloc code adresse (addr,block) self.linestarts = list(dis.findlinestarts(co)) self.prev = [0] - pop_delet = 0 - i=0 + # change jump struct self.restructRelativeJump() + # class and names if classname: classname = '_' + classname.lstrip('_') + '__' @@ -78,15 +78,13 @@ class Scanner: self.names = names # add instruction to remonde in "toDel" list toDel = [] - while i < n-pop_delet: + # add instruction to change in "toChange" list + self.toChange = [] + for i in self.op_range(0, n): op = self.code[i] ret = self.getOpcodeToDel(i) if ret != None: toDel += ret - if op >= dis.HAVE_ARGUMENT: - i += 2 - i += 1 - if toDel: # degeu a revoir / repenser (tout faire d'un coup? chaud) toDel = sorted(list(set(toDel))) delta = 0 @@ -103,8 +101,9 @@ class Scanner: self.code.pop(x-delta) self.restructCode(x-delta) delta += 1 + # mapping adresses of prev instru - n = len(self.code) + n = len(self.code) for i in self.op_range(0, n): op = self.code[i] self.prev.append(i) @@ -152,19 +151,19 @@ class Scanner: if self.code[last_import] == IMPORT_NAME == self.code[i]: replace[i] = 'IMPORT_NAME_CONT' last_import = i - + extended_arg = 0 for offset in self.op_range(0, n): + op = self.code[offset] + opname = dis.opname[op] + oparg = None; pattr = None + if offset in cf: k = 0 for j in cf[offset]: rv.append(Token('COME_FROM', None, repr(j), offset="%s_%d" % (offset, k) )) k += 1 - - op = self.code[offset] - opname = dis.opname[op] - oparg = None; pattr = None if op >= HAVE_ARGUMENT: oparg = self.get_argument(offset) + extended_arg extended_arg = 0 @@ -204,7 +203,10 @@ class Scanner: pattr = dis.cmp_op[oparg] elif op in dis.hasfree: pattr = free[oparg] - + if offset in self.toChange: + if self.code[offset] == JA and self.code[oparg] == WITH_CLEANUP: + opname = 'SETUP_WITH' + cf[oparg] = cf.get(oparg, []) + [offset] if op in (BUILD_LIST, BUILD_TUPLE, BUILD_SLICE, UNPACK_SEQUENCE, MAKE_FUNCTION, CALL_FUNCTION, MAKE_CLOSURE, @@ -244,7 +246,7 @@ class Scanner: rv.append(Token(opname, oparg, pattr, offset, linestart = offset in linestartoffsets)) else: rv.append(Token(replace[offset], oparg, pattr, offset, linestart = offset in linestartoffsets)) - + if self.showasm: out = self.out # shortcut for t in rv: @@ -321,6 +323,46 @@ class Scanner: end = self.first_instr(i, end, YIELD_VALUE) if end and self.code[end+1] == POP_TOP and self.code[end+2] == JA and self.code[end+5] == POP_BLOCK: return [i,end+5] + # with stmt + if opcode == WITH_CLEANUP: + chckDel = i-self.op_size(DELETE_NAME) + assert self.code[chckDel] in (DELETE_NAME, DELETE_FAST) + toDel = [chckDel] + nameDel = self.get_argument(chckDel) + chckDel -= self.op_size(LOAD_NAME) + assert self.code[chckDel] in (LOAD_NAME, LOAD_FAST) + toDel += [chckDel] + + allStore = self.all_instr(0, i, (STORE_NAME,STORE_FAST)) + chckStore = -1 + for store in allStore: + if nameDel == self.get_argument(store): + if self.code[store+3] == LOAD_ATTR and self.code[store-3] == LOAD_ATTR \ + and self.code[store-4] == DUP_TOP: + chckStore = store + assert chckStore > 0 + toDel += [chckStore-4,chckStore-3,chckStore+3] + + chckStp = -1 + allSetup = self.all_instr(chckStore+3, i, (SETUP_FINALLY)) + for stp in allSetup: + if chckDel == self.get_target(stp): + chckStp = stp + assert chckStp > 0 + toDel += [chckStp] + chckDel = chckStore+3+self.op_size(self.code[chckStore+3]) + while chckDel < chckStp-3: + toDel += [chckDel] + chckDel += self.op_size(self.code[chckDel]) + if self.code[chckStp-3] in (STORE_NAME,STORE_FAST) and self.code[chckStp+3] in (LOAD_NAME,LOAD_FAST) \ + and self.code[chckStp+6] in (DELETE_NAME,DELETE_FAST): + toDel += [chckStp-3,chckStp+3,chckStp+6] + # SETUP_WITH opcode dosen't exist in 2.5 but is necessary for the grammar + self.code[chckStore] = JUMP_ABSOLUTE # ugly hack + self.code[chckStore+1] = i & 0xFF + self.code[chckStore+2] = (i >> 8) & 0xFF + self.toChange.append(chckStore) + return toDel return None def restructRelativeJump(self): @@ -358,7 +400,10 @@ class Scanner: else: result.append((item[0], item[1])) self.linestarts = result - + + for change in self.toChange: + if change > i: + self.toChange[self.toChange.index(change)] -= 1 for x in self.op_range(0, len(self.code)): op = self.code[x] if op >= HAVE_ARGUMENT: diff --git a/uncompyle2/Scanner26.py b/uncompyle2/Scanner26.py index d12b0890..9c3f6ea8 100755 --- a/uncompyle2/Scanner26.py +++ b/uncompyle2/Scanner26.py @@ -57,9 +57,9 @@ class Scanner: # linestarts contains bloc code adresse (addr,block) self.linestarts = list(dis.findlinestarts(co)) self.prev = [0] - pop_delet = 0 - i=0 + # change jump struct self.restructRelativeJump() + # class and names if classname: classname = '_' + classname.lstrip('_') + '__' @@ -78,15 +78,13 @@ class Scanner: self.names = names # add instruction to remonde in "toDel" list toDel = [] - while i < n-pop_delet: + # add instruction to change in "toChange" list + self.toChange = [] + for i in self.op_range(0, n): op = self.code[i] ret = self.getOpcodeToDel(i) if ret != None: toDel += ret - if op >= dis.HAVE_ARGUMENT: - i += 2 - i += 1 - if toDel: # degeu a revoir / repenser (tout faire d'un coup? chaud) toDel = sorted(list(set(toDel))) delta = 0 @@ -103,8 +101,9 @@ class Scanner: self.code.pop(x-delta) self.restructCode(x-delta) delta += 1 + # mapping adresses of prev instru - n = len(self.code) + n = len(self.code) for i in self.op_range(0, n): op = self.code[i] self.prev.append(i) @@ -152,19 +151,19 @@ class Scanner: if self.code[last_import] == IMPORT_NAME == self.code[i]: replace[i] = 'IMPORT_NAME_CONT' last_import = i - + extended_arg = 0 for offset in self.op_range(0, n): + op = self.code[offset] + opname = dis.opname[op] + oparg = None; pattr = None + if offset in cf: k = 0 for j in cf[offset]: rv.append(Token('COME_FROM', None, repr(j), offset="%s_%d" % (offset, k) )) k += 1 - - op = self.code[offset] - opname = dis.opname[op] - oparg = None; pattr = None if op >= HAVE_ARGUMENT: oparg = self.get_argument(offset) + extended_arg extended_arg = 0 @@ -204,7 +203,10 @@ class Scanner: pattr = dis.cmp_op[oparg] elif op in dis.hasfree: pattr = free[oparg] - + if offset in self.toChange: + if self.code[offset] == JA and self.code[oparg] == WITH_CLEANUP: + opname = 'SETUP_WITH' + cf[oparg] = cf.get(oparg, []) + [offset] if op in (BUILD_LIST, BUILD_TUPLE, BUILD_SLICE, UNPACK_SEQUENCE, MAKE_FUNCTION, CALL_FUNCTION, MAKE_CLOSURE, @@ -244,7 +246,7 @@ class Scanner: rv.append(Token(opname, oparg, pattr, offset, linestart = offset in linestartoffsets)) else: rv.append(Token(replace[offset], oparg, pattr, offset, linestart = offset in linestartoffsets)) - + if self.showasm: out = self.out # shortcut for t in rv: @@ -258,10 +260,10 @@ class Scanner: """ opcode = self.code[i] opsize = self.op_size(opcode) - + if i+opsize >= len(self.code): return None - + if opcode == EXTENDED_ARG: raise 'TODO' # del POP_TOP @@ -325,6 +327,36 @@ class Scanner: end = self.first_instr(i, end, YIELD_VALUE) if end and self.code[end+1] == POP_TOP and self.code[end+2] == JA and self.code[end+5] == POP_BLOCK: return [i,end+5] + # with stmt + if opcode == WITH_CLEANUP: + allRot = self.all_instr(0, i, (ROT_TWO)) + chckRot = -1 + for rot in allRot: + if self.code[rot+1] == LOAD_ATTR and self.code[rot-3] == LOAD_ATTR \ + and self.code[rot-4] == DUP_TOP: + chckRot = rot + assert chckRot > 0 + toDel = [chckRot-4,chckRot-3,chckRot] + chckStp = -1 + allSetup = self.all_instr(chckRot+1, i, (SETUP_FINALLY)) + for stp in allSetup: + if i == self.get_target(stp): + chckStp = stp + assert chckStp > 0 + toDel += [chckStp] + chckDel = chckRot+1+self.op_size(self.code[chckRot+1]) + while chckDel < chckStp-3: + toDel += [chckDel] + chckDel += self.op_size(self.code[chckDel]) + if self.code[chckStp-3] in (STORE_NAME,STORE_FAST) and self.code[chckStp+3] in (LOAD_NAME,LOAD_FAST) \ + and self.code[chckStp+6] in (DELETE_NAME,DELETE_FAST): + toDel += [chckStp-3,chckStp+3,chckStp+6] + # SETUP_WITH opcode dosen't exist in 2.6 but is necessary for the grammar + self.code[chckRot+1] = JUMP_ABSOLUTE # ugly hack + self.code[chckRot+2] = i & 0xFF + self.code[chckRot+3] = (i >> 8) & 0xFF + self.toChange.append(chckRot+1) + return toDel return None def restructRelativeJump(self): @@ -362,7 +394,10 @@ class Scanner: else: result.append((item[0], item[1])) self.linestarts = result - + + for change in self.toChange: + if change > i: + self.toChange[self.toChange.index(change)] -= 1 for x in self.op_range(0, len(self.code)): op = self.code[x] if op >= HAVE_ARGUMENT: diff --git a/uncompyle2/__init__.py b/uncompyle2/__init__.py index 7a82e45e..5d1ed81e 100755 --- a/uncompyle2/__init__.py +++ b/uncompyle2/__init__.py @@ -206,7 +206,7 @@ def main(in_base, out_base, files, codes, outfile=None, raise except: failed_files += 1 - sys.stderr.write("### Can't uncompyle %s\n" % infile) + sys.stderr.write("\n# Can't uncompyle %s\n" % infile) if outfile: outstream.close() os.rename(outfile, outfile + '_failed') @@ -219,7 +219,7 @@ def main(in_base, out_base, files, codes, outfile=None, if do_verify: try: verify.compare_code_with_srcfile(infile, outfile) - print '# okay decompyling', infile, __memUsage() + print '\n# okay decompyling', infile, __memUsage() okay_files += 1 except verify.VerifyCmpError, e: verify_failed_files += 1 @@ -228,5 +228,5 @@ def main(in_base, out_base, files, codes, outfile=None, print >>sys.stderr, e else: okay_files += 1 - print '# okay decompyling', infile, __memUsage() + print '\n# okay decompyling', infile, __memUsage() return (tot_files, okay_files, failed_files, verify_failed_files)