Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'hotfix/nested_while' into develop

  • Loading branch information...
commit 49f7bd618e95fc3347d8c451105a54aada75837c 2 parents a948dba + 28d165c
srossross authored
View
2  meta/asttools/visitors/pysourcegen.py
@@ -685,6 +685,8 @@ def visitWhile(self, node):
with self.indenter:
for expr in node.orelse:
self.visit(expr)
+ self.print('\n')
+ self.print('\n')
def visitExpr(self, node):
View
80 meta/decompiler/control_flow_instructions.py
@@ -561,44 +561,52 @@ def while_loop(self, instr, loop_block):
loop_block_map = {instr.i:instr.op for instr in loop_block}
- #Find the last conditional that will exit the loop
- func = lambda instr: opname[instr.op] == 'POP_JUMP_IF_FALSE' and (instr.oparg in loop_block_map) and opname[loop_block_map[instr.oparg]] == 'POP_BLOCK'
-
- idx = rfind_index(loop_block, func)
-
-
- # in python this would be while 1:
- if idx is None:
- body_block = loop_block
- body_ = self.decompile_block(body_block[:-1]).stmnt()
- while_ = _ast.While(test=_ast.Num(1, **kw), body=body_, orelse=[], **kw)
- self.ast_stack.append(while_)
- return
-
- cond_block = loop_block[:idx]
- instr = loop_block[idx]
- body_block = loop_block[idx + 1:]
-
- first_cond_ = cond_block[0]
- iter_stmnt = self.decompile_block(cond_block).stmnt()
-
- assert len(iter_stmnt) == 1
-
- iter = iter_stmnt[0]
-
- body_block, _POP_BLOCK, else_block = split_cond(body_block, func=lambda new_instr: instr.oparg == new_instr.i)
-
- assert opname[_POP_BLOCK.op] == 'POP_BLOCK'
+ first_i = loop_block[0].i
+
+ func = lambda instr: instr.opname == 'JUMP_ABSOLUTE' and instr.oparg == first_i
+ body_index = rfind_index(loop_block[:-1], func)
+
+ if body_index is None:
+ const_while = True
+ body_index = len(loop_block) - 1
+ else:
+ if body_index + 1 < len(loop_block):
+ pop_block = loop_block[body_index + 1]
+ const_while = pop_block.opname != 'POP_BLOCK'
+ const_else = True
+ else:
+ const_while = True
+ const_else = False
+
+ if const_while:
+ test = _ast.Num(1, **kw)
+ body_ = self.decompile_block(loop_block[:body_index]).stmnt()
+
+ else_block = loop_block[body_index + 1:]
+ if else_block:
+ else_ = self.decompile_block(else_block).stmnt()
+ else:
+ else_ = []
+ else:
+ pop_block = loop_block[body_index + 1]
+
+ func = lambda instr: instr.opname in ['POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE'] and instr.oparg == pop_block.i
+ idx = rfind_index(loop_block[:body_index], func)
+ cond_block = loop_block[:idx]
- assert opname[body_block[-1].op] == 'JUMP_ABSOLUTE' and body_block[-1].oparg == first_cond_.i
- body_ = self.decompile_block(body_block[:-1]).stmnt()
+ iter_stmnt = self.decompile_block(cond_block).stmnt()
+ assert len(iter_stmnt) == 1
+ test = iter_stmnt[0]
+
+ body_ = self.decompile_block(loop_block[idx + 1:body_index]).stmnt()
- if else_block[:-1]:
- else_ = self.decompile_block(else_block[:]).stmnt()
- else:
- else_ = []
+ else_block = loop_block[body_index + 2:]
+ if else_block:
+ else_ = self.decompile_block(else_block[:]).stmnt()
+ else:
+ else_ = []
- while_ = _ast.While(test=iter, body=body_, orelse=else_, **kw)
+ while_ = _ast.While(test=test, body=body_, orelse=else_, **kw)
self.ast_stack.append(while_)
@@ -662,7 +670,7 @@ def process_logic(self, logic_block):
if idx is None:
stmnts = self.decompile_block(logic_block).stmnt()
- assert len(stmnts) == 1
+# assert len(stmnts) == 1
return stmnts[0]
else:
right = logic_block[idx:]
View
2  meta/decompiler/simple_instructions.py
@@ -66,7 +66,9 @@ def UNARY_OP(self, instr):
'>' :_ast.Gt,
'<' :_ast.Lt,
'==': _ast.Eq,
+ '!=': _ast.NotEq,
'in': _ast.In,
+ 'not in': _ast.NotIn,
'is':_ast.Is,
'is not':_ast.IsNot,
}
View
9 meta/decompiler/tests/test_decompiler.py
@@ -353,6 +353,15 @@ def test_loop_bug(self):
'''
self.statement(stmnt)
+ def test_while_bug(self):
+ stmnt = '''
+while a:
+ q
+ while b:
+ w
+'''
+ self.statement(stmnt)
+
class Complex(Base):
def test_if_in_for(self):
Please sign in to comment.
Something went wrong with that request. Please try again.