X Tutup
Skip to content

Commit ed9fb64

Browse files
committed
More if/then detection in Python 3.x
1 parent d002c66 commit ed9fb64

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed
365 Bytes
Binary file not shown.

uncompyle6/scanners/scanner3.py

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None):
148148
"""
149149

150150
show_asm = self.show_asm if not show_asm else show_asm
151-
# show_asm = 'after'
151+
# show_asm = 'both'
152152
if show_asm in ('both', 'before'):
153153
bytecode = Bytecode(co, self.opc)
154154
for instr in bytecode.get_instructions(co):
@@ -600,7 +600,6 @@ def detect_structure(self, offset, targets):
600600
parent = struct
601601

602602
if op == self.opc.SETUP_LOOP:
603-
604603
# We categorize loop types: 'for', 'while', 'while 1' with
605604
# possibly suffixes '-loop' and '-else'
606605
# Try to find the jump_back instruction of the loop.
@@ -618,20 +617,30 @@ def detect_structure(self, offset, targets):
618617
jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE,
619618
next_line_byte, False)
620619

621-
if jump_back and jump_back != self.prev_op[end] and self.is_jump_forward(jump_back+3):
622-
if (code[self.prev_op[end]] == self.opc.RETURN_VALUE
623-
or (code[self.prev_op[end]] == self.opc.POP_BLOCK
624-
and code[self.prev_op[self.prev_op[end]]] == self.opc.RETURN_VALUE)):
620+
jump_forward_offset = jump_back+3
621+
return_val_offset1 = self.prev[self.prev[end]]
622+
623+
if (jump_back and jump_back != self.prev_op[end]
624+
and self.is_jump_forward(jump_forward_offset)):
625+
if (code[self.prev_op[end]] == self.opc.RETURN_VALUE or
626+
(code[self.prev_op[end]] == self.opc.POP_BLOCK
627+
and code[return_val_offset1] == self.opc.RETURN_VALUE)):
625628
jump_back = None
626-
if not jump_back: # loop suite ends in return. wtf right?
629+
if not jump_back:
630+
# loop suite ends in return
627631
jump_back = self.last_instr(start, end, self.opc.RETURN_VALUE) + 1
628632
if not jump_back:
629633
return
634+
635+
jump_back += 1
636+
if_offset = None
630637
if code[self.prev_op[next_line_byte]] not in POP_JUMP_TF:
631-
loop_type = 'for'
632-
else:
638+
if_offset = self.prev[next_line_byte]
639+
if if_offset:
633640
loop_type = 'while'
634-
self.ignore_if.add(self.prev_op[next_line_byte])
641+
self.ignore_if.add(if_offset)
642+
else:
643+
loop_type = 'for'
635644
target = next_line_byte
636645
end = jump_back + 3
637646
else:
@@ -645,13 +654,15 @@ def detect_structure(self, offset, targets):
645654
elif target < offset:
646655
self.fixed_jumps[offset] = jump_back+4
647656
end = jump_back+4
657+
648658
target = self.get_target(jump_back)
649659

650660
if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER):
651661
loop_type = 'for'
652662
else:
653663
loop_type = 'while'
654664
test = self.prev_op[next_line_byte]
665+
655666
if test == offset:
656667
loop_type = 'while 1'
657668
elif self.code[test] in op3.hasjabs+op3.hasjrel:
@@ -764,14 +775,15 @@ def detect_structure(self, offset, targets):
764775
if offset in self.ignore_if:
765776
return
766777

767-
if (code[prev_op[rtarget]] == self.opc.JUMP_ABSOLUTE and
768-
prev_op[rtarget] in self.stmts and
769-
prev_op[rtarget] != offset and
770-
prev_op[prev_op[rtarget]] != offset and
778+
rrtarget = prev_op[rtarget]
779+
if (code[rrtarget] == self.opc.JUMP_ABSOLUTE and
780+
rrtarget in self.stmts and
781+
rrtarget != offset and
782+
prev_op[rrtarget] != offset and
771783
not (code[rtarget] == self.opc.JUMP_ABSOLUTE and
772784
code[rtarget+3] == self.opc.POP_BLOCK and
773-
code[prev_op[prev_op[rtarget]]] != self.opc.JUMP_ABSOLUTE)):
774-
rtarget = prev_op[rtarget]
785+
code[prev_op[rrtarget]] != self.opc.JUMP_ABSOLUTE)):
786+
rtarget = rrtarget
775787

776788
# Does the "jump if" jump beyond a jump op?
777789
# That is, we have something like:
@@ -787,8 +799,7 @@ def detect_structure(self, offset, targets):
787799
# There are other contexts we may need to consider
788800
# like whether the target is "END_FINALLY"
789801
# or if the condition jump is to a forward location
790-
if self.is_jump_forward(prev_op[rtarget]):
791-
rrtarget = prev_op[rtarget]
802+
if self.is_jump_forward(rrtarget):
792803
if_end = self.get_target(rrtarget)
793804

794805
# If the jump target is back, we are looping
@@ -813,7 +824,13 @@ def detect_structure(self, offset, targets):
813824
'start': rtarget,
814825
'end': end})
815826
self.else_start[rtarget] = end
816-
elif code[prev_op[rtarget]] == self.opc.RETURN_VALUE:
827+
elif self.is_jump_back(rrtarget):
828+
if_end = rtarget
829+
self.structs.append({'type': 'if-then',
830+
'start': start,
831+
'end': rrtarget})
832+
self.not_continue.add(prev_op[rtarget])
833+
elif code[rrtarget] == self.opc.RETURN_VALUE:
817834
self.structs.append({'type': 'if-then',
818835
'start': start,
819836
'end': rtarget})
@@ -882,6 +899,16 @@ def detect_structure(self, offset, targets):
882899
pass
883900
return
884901

902+
def is_jump_back(self, offset):
903+
"""
904+
Return True if the code at offset is some sort of jump back.
905+
That is, it is ether "JUMP_FORWARD" or an absolute jump that
906+
goes forward.
907+
"""
908+
if self.code[offset] != self.opc.JUMP_ABSOLUTE:
909+
return False
910+
return offset > self.get_target(offset)
911+
885912
def next_except_jump(self, start):
886913
"""
887914
Return the next jump that was generated by an except SomeException:

0 commit comments

Comments
 (0)
X Tutup