You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Merge branch 'master' into python-2.4
This commit is contained in:
@@ -231,7 +231,7 @@ See Also
|
||||
* https://github.com/rocky/python-xdis : Cross Python version disassembler
|
||||
* https://github.com/rocky/python-xasm : Cross Python version assembler
|
||||
* https://github.com/rocky/python-uncompyle6/wiki : Wiki Documents which describe the code and aspects of it in more detail
|
||||
* https://github.com/zrax/pycdc : The README for this C++ code syas it aims to support all versions of Python. It is best for Python versions around 2.7 and 3.3 when the code was initially developed. Accuracy for current versions of Python3 and early versions of Python is lacking. Without major effort, it is unlikely it can be made to support current Python 3. See its `issue tracker <https://github.com/zrax/pycdc/issues>`_ for details. Currently lightly maintained.
|
||||
* https://github.com/zrax/pycdc : The README for this C++ code says it aims to support all versions of Python. It is best for Python versions around 2.7 and 3.3 when the code was initially developed. Accuracy for current versions of Python3 and early versions of Python is lacking. Without major effort, it is unlikely it can be made to support current Python 3. See its `issue tracker <https://github.com/zrax/pycdc/issues>`_ for details. Currently lightly maintained.
|
||||
|
||||
|
||||
.. _trepan: https://pypi.python.org/pypi/trepan2g
|
||||
|
@@ -48,7 +48,7 @@ case $PYVERSION in
|
||||
;;
|
||||
2.5)
|
||||
SKIP_TESTS=(
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
@@ -110,11 +110,9 @@ case $PYVERSION in
|
||||
[test_capi.py]=1
|
||||
[test_curses.py]=1 # Possibly fails on its own but not detected
|
||||
[test_cmd_line.py]=1 # Takes too long, maybe hangs, or looking for interactive input?
|
||||
[test_compilex.py]=1 # Probably complex literals again. Investigate
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_doctest.py]=1 # Fails on its own
|
||||
[test_exceptions.py]=1
|
||||
[test_format.py]=1 # control flow. uncompyle2 does not have problems here
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # test takes to long, works interactively though
|
||||
[test_io.py]=1 # Test takes too long to run
|
||||
@@ -137,7 +135,6 @@ case $PYVERSION in
|
||||
[test_unicode.py]=1 # Too long to run 11 seconds
|
||||
[test_xpickle.py]=1 # Runs ok but takes 72 seconds
|
||||
[test_zipfile64.py]=1 # Runs ok but takes 204 seconds
|
||||
[test_zipimport.py]=1 # FIXME: improper try from try/else ?
|
||||
)
|
||||
if (( batch )) ; then
|
||||
# Fails in crontab environment?
|
||||
@@ -232,9 +229,8 @@ case $PYVERSION in
|
||||
3.5)
|
||||
SKIP_TESTS=(
|
||||
[test_ast.py]=1 # line 379, in test_literal_eval self.assertEqual(ast.literal_eval('b"hi"'), 'hi')
|
||||
[test_atexit.py]=1 #
|
||||
[test_atexit.py]=1
|
||||
[test_builtin.py]=1 #
|
||||
[test_compare.py]=1
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
)
|
||||
if (( batch )) ; then
|
||||
@@ -247,11 +243,9 @@ case $PYVERSION in
|
||||
|
||||
3.6)
|
||||
SKIP_TESTS=(
|
||||
[test_ast.py]=1 #
|
||||
[test_atexit.py]=1 #
|
||||
[test_bdb.py]=1 #
|
||||
[test_builtin.py]=1 #
|
||||
[test_compare.py]=1
|
||||
[test_builtin.py]=1 # Fails on its own
|
||||
[test_compile.py]=1
|
||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||
[test_contextlib_async.py]=1 # Investigate
|
||||
@@ -263,7 +257,7 @@ case $PYVERSION in
|
||||
;;
|
||||
3.7)
|
||||
SKIP_TESTS=(
|
||||
[test_ast.py]=1 #
|
||||
[test_ast.py]=1 # test assertion error
|
||||
[test_atexit.py]=1 #
|
||||
[test_baseexception.py]=1 #
|
||||
[test_bdb.py]=1 #
|
||||
@@ -271,10 +265,9 @@ case $PYVERSION in
|
||||
[test_builtin.py]=1 # parser error
|
||||
[test_cmdline.py]=1 # Interactive?
|
||||
[test_collections.py]=1 # Fixed I think in decompyle3 - pull from there
|
||||
[test_compare.py]=1
|
||||
[test_compare.py]=1 # test assert fail - investigate
|
||||
[test_compile.py]=1
|
||||
[test_configparser.py]=1
|
||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||
[test_contextlib_async.py]=1 # Investigate
|
||||
[test_context.py]=1
|
||||
[test_coroutines.py]=1 # Parse error
|
||||
@@ -296,7 +289,6 @@ case $PYVERSION in
|
||||
;;
|
||||
3.8)
|
||||
SKIP_TESTS=(
|
||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||
[test_collections.py]=1 # Investigate
|
||||
[test_decorators.py]=1 # Control flow wrt "if elif"
|
||||
[test_exceptions.py]=1 # parse error
|
||||
|
@@ -159,6 +159,17 @@ class Python2Parser(PythonParser):
|
||||
except_handler ::= jmp_abs COME_FROM except_stmts
|
||||
END_FINALLY
|
||||
|
||||
# except_handler_else is intended to be used only in a
|
||||
# try_else. The disambiguation comes from reduction rule
|
||||
# checking where we make sure that the JUMP_FORWARD mismatches
|
||||
# the JUMP_FORWARD before the END_FINALLY
|
||||
except_handler_else ::= JUMP_FORWARD COME_FROM except_stmts
|
||||
END_FINALLY come_froms
|
||||
|
||||
except_handler_else ::= jmp_abs COME_FROM except_stmts
|
||||
END_FINALLY
|
||||
|
||||
|
||||
except_stmts ::= except_stmt+
|
||||
|
||||
except_stmt ::= except_cond1 except_suite
|
||||
@@ -635,6 +646,8 @@ class Python2Parser(PythonParser):
|
||||
self.addRule(rule, nop_func)
|
||||
pass
|
||||
|
||||
self.check_reduce["except_handler"] = "tokens"
|
||||
self.check_reduce["except_handler_else"] = "tokens"
|
||||
self.check_reduce["raise_stmt1"] = "tokens"
|
||||
self.check_reduce["assert_expr_and"] = "AST"
|
||||
self.check_reduce["tryelsestmt"] = "AST"
|
||||
@@ -666,6 +679,31 @@ class Python2Parser(PythonParser):
|
||||
jmp_false = ast[1]
|
||||
jump_target = jmp_false[0].attr
|
||||
return jump_target > tokens[last].off2int()
|
||||
elif lhs in ("except_handler, except_handler_else"):
|
||||
|
||||
# FIXME: expand this to other 2.x version
|
||||
if self.version != 2.7: return False
|
||||
|
||||
if tokens[first] in ("JUMP_FORWARD", "JUMP_ABSOLUTE"):
|
||||
first_jump_target = tokens[first].pattr
|
||||
last = min(last, len(tokens)-1)
|
||||
for i in range(last, first, -1):
|
||||
if tokens[i] == "END_FINALLY":
|
||||
i -= 1
|
||||
second_jump = tokens[i]
|
||||
if second_jump in ("JUMP_FORWARD", "JUMP_ABSOLUTE"):
|
||||
second_jump_target = second_jump.pattr
|
||||
equal_target = second_jump_target == first_jump_target
|
||||
if equal_target:
|
||||
return lhs != "except_handler"
|
||||
else:
|
||||
return lhs != "except_handler_else"
|
||||
pass
|
||||
else:
|
||||
return False
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
|
||||
for i in range(last-1, last-4, -1):
|
||||
t = tokens[i]
|
||||
|
@@ -60,13 +60,13 @@ class Python27Parser(Python2Parser):
|
||||
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
|
||||
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite COME_FROM
|
||||
except_handler_else else_suite COME_FROM
|
||||
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel JUMP_BACK COME_FROM
|
||||
except_handler_else else_suitel JUMP_BACK COME_FROM
|
||||
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel
|
||||
except_handler_else else_suitel
|
||||
|
||||
except_stmt ::= except_cond2 except_suite
|
||||
|
||||
@@ -216,6 +216,10 @@ class Python27Parser(Python2Parser):
|
||||
super(Python27Parser, self).customize_grammar_rules(tokens, customize)
|
||||
self.check_reduce["and"] = "AST"
|
||||
self.check_reduce["conditional"] = "AST"
|
||||
|
||||
self.check_reduce["except_handler"] = "tokens"
|
||||
self.check_reduce["except_handler_else"] = "tokens"
|
||||
|
||||
# self.check_reduce["or"] = "AST"
|
||||
self.check_reduce["raise_stmt1"] = "AST"
|
||||
self.check_reduce["iflaststmtl"] = "AST"
|
||||
|
@@ -18,6 +18,7 @@ All the crazy things we have to do to handle Python functions in Python before 3
|
||||
The saga of changes continues in 3.0 and above and in other files.
|
||||
"""
|
||||
from xdis.code import iscode, code_has_star_arg, code_has_star_star_arg
|
||||
from xdis.util import CO_GENERATOR
|
||||
from uncompyle6.scanner import Code
|
||||
from uncompyle6.parsers.treenode import SyntaxTree
|
||||
from uncompyle6 import PYTHON3
|
||||
@@ -178,7 +179,6 @@ def make_function2(self, node, is_lambda, nested=1, code_node=None):
|
||||
# docstring exists, dump it
|
||||
print_docstring(self, indent, code.co_consts[0])
|
||||
|
||||
code._tokens = None # save memory
|
||||
if not is_lambda:
|
||||
assert ast == "stmts"
|
||||
|
||||
@@ -199,5 +199,6 @@ def make_function2(self, node, is_lambda, nested=1, code_node=None):
|
||||
self.gen_source(
|
||||
ast, code.co_name, code._customize, is_lambda=is_lambda, returnNone=rn
|
||||
)
|
||||
code._tokens = None
|
||||
|
||||
code._tokens = None # save memory
|
||||
code._customize = None # save memory
|
||||
|
@@ -17,6 +17,7 @@ All the crazy things we have to do to handle Python functions in 3.0-3.5 or so.
|
||||
The saga of changes before and after is in other files.
|
||||
"""
|
||||
from xdis.code import iscode, code_has_star_arg, code_has_star_star_arg
|
||||
from xdis.util import CO_GENERATOR
|
||||
from uncompyle6.scanner import Code
|
||||
from uncompyle6.parsers.treenode import SyntaxTree
|
||||
from uncompyle6.semantics.parser_error import ParserError
|
||||
@@ -485,9 +486,8 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
||||
kwargs = list(scanner_code.co_varnames[argc : argc + kwonlyargcount])
|
||||
|
||||
# defaults are for last n parameters when not in a lambda, thus reverse
|
||||
if not is_lambda:
|
||||
paramnames.reverse()
|
||||
defparams.reverse()
|
||||
paramnames.reverse()
|
||||
defparams.reverse()
|
||||
|
||||
try:
|
||||
ast = self.build_ast(scanner_code._tokens,
|
||||
@@ -645,7 +645,6 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
||||
# docstring exists, dump it
|
||||
print_docstring(self, self.indent, code.co_consts[0])
|
||||
|
||||
scanner_code._tokens = None # save memory
|
||||
assert ast == "stmts"
|
||||
|
||||
all_globals = find_all_globals(ast, set())
|
||||
@@ -665,5 +664,21 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
||||
self.gen_source(
|
||||
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn
|
||||
)
|
||||
scanner_code._tokens = None
|
||||
|
||||
# In obscure cases, a function may be a generator but the "yield"
|
||||
# was optimized away. Here, we need to put in unreachable code to
|
||||
# add in "yield" just so that the compiler will mark
|
||||
# the GENERATOR bit of the function. See for example
|
||||
# Python 3.x's test_generator.py test program.
|
||||
if code.co_flags & CO_GENERATOR:
|
||||
need_bogus_yield = True
|
||||
for token in scanner_code._tokens:
|
||||
if token in ("YIELD_VALUE", "YIELD_FROM"):
|
||||
need_bogus_yield = False
|
||||
break
|
||||
pass
|
||||
if need_bogus_yield:
|
||||
self.template_engine(("%|if False:\n%+%|yield None%-",), node)
|
||||
|
||||
scanner_code._tokens = None # save memory
|
||||
scanner_code._customize = None # save memory
|
||||
|
@@ -17,6 +17,7 @@ All the crazy things we have to do to handle Python functions in 3.6 and above.
|
||||
The saga of changes before 3.6 is in other files.
|
||||
"""
|
||||
from xdis.code import iscode, code_has_star_arg, code_has_star_star_arg
|
||||
from xdis.util import CO_GENERATOR, CO_ASYNC_GENERATOR
|
||||
from uncompyle6.scanner import Code
|
||||
from uncompyle6.parsers.treenode import SyntaxTree
|
||||
from uncompyle6.semantics.parser_error import ParserError
|
||||
@@ -197,10 +198,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
||||
paramnames = list(scanner_code.co_varnames[:argc])
|
||||
kwargs = list(scanner_code.co_varnames[argc : argc + kwonlyargcount])
|
||||
|
||||
# defaults are for last n parameters when not in a lambda, thus reverse
|
||||
if not is_lambda:
|
||||
paramnames.reverse()
|
||||
defparams.reverse()
|
||||
paramnames.reverse()
|
||||
defparams.reverse()
|
||||
|
||||
try:
|
||||
ast = self.build_ast(
|
||||
@@ -372,7 +371,6 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
||||
# docstring exists, dump it
|
||||
self.println(self.traverse(node[-2]))
|
||||
|
||||
scanner_code._tokens = None # save memory
|
||||
assert ast == "stmts"
|
||||
|
||||
all_globals = find_all_globals(ast, set())
|
||||
@@ -393,5 +391,20 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
||||
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn
|
||||
)
|
||||
|
||||
scanner_code._tokens = None
|
||||
# In obscure cases, a function may be a generator but the "yield"
|
||||
# was optimized away. Here, we need to put in unreachable code to
|
||||
# add in "yield" just so that the compiler will mark
|
||||
# the GENERATOR bit of the function. See for example
|
||||
# Python 3.x's test_generator.py test program.
|
||||
if code.co_flags & (CO_GENERATOR | CO_ASYNC_GENERATOR):
|
||||
need_bogus_yield = True
|
||||
for token in scanner_code._tokens:
|
||||
if token == "YIELD_VALUE":
|
||||
need_bogus_yield = False
|
||||
break
|
||||
pass
|
||||
if need_bogus_yield:
|
||||
self.template_engine(("%|if False:\n%+%|yield None%-",), node)
|
||||
|
||||
scanner_code._tokens = None # save memory
|
||||
scanner_code._customize = None # save memory
|
||||
|
Reference in New Issue
Block a user