You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
BIN
test/bytecode_3.6_run/01_try_else.pyc
Normal file
BIN
test/bytecode_3.6_run/01_try_else.pyc
Normal file
Binary file not shown.
23
test/simple_source/bug31/01_try_else.py
Normal file
23
test/simple_source/bug31/01_try_else.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Bug based on 2.7 test_itertools.py but mis-decompiled in Python 3.x bytecode
|
||||||
|
# The bug is confusing "try/else" with "try" as a result of the loop which causes
|
||||||
|
# the end of the except to jump back to the beginning of the loop, outside of the
|
||||||
|
# try. In 3.x we not distinguising this jump out of the loop with a jump to the
|
||||||
|
# end of the "try".
|
||||||
|
|
||||||
|
def testit(stmts):
|
||||||
|
|
||||||
|
# Bug was confusing When the except jumps back to the beginning of the block
|
||||||
|
# to the beginning of this for loop
|
||||||
|
x = 1
|
||||||
|
results = []
|
||||||
|
for stmt in stmts:
|
||||||
|
try:
|
||||||
|
x = eval(stmt)
|
||||||
|
except SyntaxError:
|
||||||
|
results.append(1)
|
||||||
|
else:
|
||||||
|
results.append(x)
|
||||||
|
return results
|
||||||
|
|
||||||
|
results = testit(["1 + 2", "1 +"])
|
||||||
|
assert results == [3, 1], "try with else failed"
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2018 Rocky Bernstein
|
# Copyright (c) 2015-2019 Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
# Copyright (c) 1999 John Aycock
|
# Copyright (c) 1999 John Aycock
|
||||||
@@ -185,23 +185,11 @@ class Python3Parser(PythonParser):
|
|||||||
# one COME_FROM for Python 2.7 seems to associate the
|
# one COME_FROM for Python 2.7 seems to associate the
|
||||||
# COME_FROM targets from the wrong places
|
# COME_FROM targets from the wrong places
|
||||||
|
|
||||||
try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
|
||||||
except_handler opt_come_from_except
|
|
||||||
|
|
||||||
# this is nested inside a try_except
|
# this is nested inside a try_except
|
||||||
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt
|
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt
|
||||||
POP_BLOCK LOAD_CONST
|
POP_BLOCK LOAD_CONST
|
||||||
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
|
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
|
||||||
|
|
||||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
|
||||||
except_handler else_suite come_from_except_clauses
|
|
||||||
|
|
||||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
|
||||||
except_handler else_suite come_froms
|
|
||||||
|
|
||||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
|
||||||
except_handler else_suitel come_from_except_clauses
|
|
||||||
|
|
||||||
except_handler ::= jmp_abs COME_FROM except_stmts
|
except_handler ::= jmp_abs COME_FROM except_stmts
|
||||||
END_FINALLY
|
END_FINALLY
|
||||||
except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts
|
except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts
|
||||||
@@ -564,9 +552,10 @@ class Python3Parser(PythonParser):
|
|||||||
# include instructions that don't need customization,
|
# include instructions that don't need customization,
|
||||||
# but we'll do a finer check after the rough breakout.
|
# but we'll do a finer check after the rough breakout.
|
||||||
customize_instruction_basenames = frozenset(
|
customize_instruction_basenames = frozenset(
|
||||||
('BUILD', 'CALL', 'CONTINUE', 'DELETE', 'GET',
|
('BUILD', 'CALL', 'CONTINUE', 'DELETE', 'GET',
|
||||||
'JUMP', 'LOAD', 'LOOKUP', 'MAKE',
|
'JUMP', 'LOAD', 'LOOKUP', 'MAKE',
|
||||||
'RETURN', 'RAISE', 'UNPACK'))
|
'RETURN', 'RAISE', 'SETUP',
|
||||||
|
'UNPACK'))
|
||||||
|
|
||||||
# Opcode names in the custom_ops_processed set have rules that get added
|
# Opcode names in the custom_ops_processed set have rules that get added
|
||||||
# unconditionally and the rules are constant. So they need to be done
|
# unconditionally and the rules are constant. So they need to be done
|
||||||
@@ -1119,6 +1108,26 @@ class Python3Parser(PythonParser):
|
|||||||
raise_stmt2 ::= expr expr RAISE_VARARGS_2
|
raise_stmt2 ::= expr expr RAISE_VARARGS_2
|
||||||
""", nop_func)
|
""", nop_func)
|
||||||
custom_ops_processed.add(opname)
|
custom_ops_processed.add(opname)
|
||||||
|
elif opname == 'SETUP_EXCEPT':
|
||||||
|
self.addRule("""
|
||||||
|
try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
|
except_handler opt_come_from_except
|
||||||
|
|
||||||
|
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
|
except_handler else_suite come_from_except_clauses
|
||||||
|
|
||||||
|
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
|
except_handler else_suite come_froms
|
||||||
|
|
||||||
|
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
|
except_handler else_suitel come_from_except_clauses
|
||||||
|
|
||||||
|
stmt ::= tryelsestmtl3
|
||||||
|
tryelsestmtl3 ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
|
except_handler COME_FROM else_suitel
|
||||||
|
opt_come_from_except
|
||||||
|
""", nop_func)
|
||||||
|
custom_ops_processed.add(opname)
|
||||||
elif opname_base in ('UNPACK_EX',):
|
elif opname_base in ('UNPACK_EX',):
|
||||||
before_count, after_count = token.attr
|
before_count, after_count = token.attr
|
||||||
rule = 'unpack ::= ' + opname + ' store' * (before_count + after_count + 1)
|
rule = 'unpack ::= ' + opname + ' store' * (before_count + after_count + 1)
|
||||||
@@ -1140,6 +1149,8 @@ class Python3Parser(PythonParser):
|
|||||||
self.check_reduce['ifelsestmt'] = 'AST'
|
self.check_reduce['ifelsestmt'] = 'AST'
|
||||||
self.check_reduce['annotate_tuple'] = 'noAST'
|
self.check_reduce['annotate_tuple'] = 'noAST'
|
||||||
self.check_reduce['kwarg'] = 'noAST'
|
self.check_reduce['kwarg'] = 'noAST'
|
||||||
|
self.check_reduce['try_except'] = 'AST'
|
||||||
|
|
||||||
# FIXME: remove parser errors caused by the below
|
# FIXME: remove parser errors caused by the below
|
||||||
# self.check_reduce['while1elsestmt'] = 'noAST'
|
# self.check_reduce['while1elsestmt'] = 'noAST'
|
||||||
return
|
return
|
||||||
@@ -1181,6 +1192,16 @@ class Python3Parser(PythonParser):
|
|||||||
if last == n:
|
if last == n:
|
||||||
return False
|
return False
|
||||||
return tokens[first].attr > tokens[last].offset
|
return tokens[first].attr > tokens[last].offset
|
||||||
|
elif rule == ('try_except',
|
||||||
|
('SETUP_EXCEPT', 'suite_stmts_opt', 'POP_BLOCK',
|
||||||
|
'except_handler', 'opt_come_from_except')):
|
||||||
|
come_from_except = ast[-1]
|
||||||
|
if come_from_except[0] == 'COME_FROM':
|
||||||
|
# There should be at last two COME_FROMs, one from an
|
||||||
|
# exception handler and one from the try. Otherwise
|
||||||
|
# we have a try/else.
|
||||||
|
return True
|
||||||
|
pass
|
||||||
elif lhs == 'while1stmt':
|
elif lhs == 'while1stmt':
|
||||||
|
|
||||||
# If there is a fall through to the COME_FROM_LOOP. then this is
|
# If there is a fall through to the COME_FROM_LOOP. then this is
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2016-2018 Rocky Bernstein
|
# Copyright (c) 2016-2019 Rocky Bernstein
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -122,6 +122,7 @@ class Python36Parser(Python35Parser):
|
|||||||
# """)
|
# """)
|
||||||
super(Python36Parser, self).customize_grammar_rules(tokens, customize)
|
super(Python36Parser, self).customize_grammar_rules(tokens, customize)
|
||||||
self.remove_rules("""
|
self.remove_rules("""
|
||||||
|
except_handler ::= JUMP_FORWARD COME_FROM_EXCEPT except_stmts END_FINALLY COME_FROM
|
||||||
async_for_stmt ::= SETUP_LOOP expr
|
async_for_stmt ::= SETUP_LOOP expr
|
||||||
GET_AITER
|
GET_AITER
|
||||||
LOAD_CONST YIELD_FROM SETUP_EXCEPT GET_ANEXT LOAD_CONST
|
LOAD_CONST YIELD_FROM SETUP_EXCEPT GET_ANEXT LOAD_CONST
|
||||||
@@ -344,7 +345,7 @@ class Python36Parser(Python35Parser):
|
|||||||
if nt[0] == 'call_kw':
|
if nt[0] == 'call_kw':
|
||||||
return True
|
return True
|
||||||
nt = nt[0]
|
nt = nt[0]
|
||||||
|
pass
|
||||||
return False
|
return False
|
||||||
class Python36ParserSingle(Python36Parser, PythonParserSingle):
|
class Python36ParserSingle(Python36Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2018 by Rocky Bernstein
|
# Copyright (c) 2015-2019 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
#
|
#
|
||||||
@@ -886,9 +886,10 @@ class Scanner2(Scanner):
|
|||||||
# or a conditional assignment like:
|
# or a conditional assignment like:
|
||||||
# x = 1 if x else 2
|
# x = 1 if x else 2
|
||||||
#
|
#
|
||||||
# There are other contexts we may need to consider
|
# There are other situations we may need to consider, like
|
||||||
# like whether the target is "END_FINALLY"
|
# if the condition jump is to a forward location.
|
||||||
# or if the condition jump is to a forward location
|
# Also the existence of a jump to the instruction after "END_FINALLY"
|
||||||
|
# will distinguish "try/else" from "try".
|
||||||
code_pre_rtarget = code[pre_rtarget]
|
code_pre_rtarget = code[pre_rtarget]
|
||||||
|
|
||||||
if code_pre_rtarget in self.jump_forward:
|
if code_pre_rtarget in self.jump_forward:
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2018 by Rocky Bernstein
|
# Copyright (c) 2015-2019 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
#
|
#
|
||||||
@@ -851,7 +851,7 @@ class Scanner3(Scanner):
|
|||||||
# For 3.5, in addition the JUMP_FORWARD above we could have
|
# For 3.5, in addition the JUMP_FORWARD above we could have
|
||||||
# JUMP_BACK or CONTINUE
|
# JUMP_BACK or CONTINUE
|
||||||
#
|
#
|
||||||
# There are other situations we may need to consider
|
# There are other situations we may need to consider, like
|
||||||
# if the condition jump is to a forward location.
|
# if the condition jump is to a forward location.
|
||||||
# Also the existence of a jump to the instruction after "END_FINALLY"
|
# Also the existence of a jump to the instruction after "END_FINALLY"
|
||||||
# will distinguish "try/else" from "try".
|
# will distinguish "try/else" from "try".
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2018 by Rocky Bernstein
|
# Copyright (c) 2018-2019 by Rocky Bernstein
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -263,6 +263,12 @@ def customize_for_version3(self, version):
|
|||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
self.n_mkfunc_annotate = n_mkfunc_annotate
|
self.n_mkfunc_annotate = n_mkfunc_annotate
|
||||||
|
|
||||||
|
TABLE_DIRECT.update({
|
||||||
|
'tryelsestmtl3': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-',
|
||||||
|
(1, 'suite_stmts_opt'),
|
||||||
|
(3, 'except_handler'),
|
||||||
|
(5, 'else_suitel') ),
|
||||||
|
})
|
||||||
if version >= 3.4:
|
if version >= 3.4:
|
||||||
########################
|
########################
|
||||||
# Python 3.4+ Additions
|
# Python 3.4+ Additions
|
||||||
|
Reference in New Issue
Block a user