You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Start 3.6+ var type annotations and decompyle3 merge...
Although overall an improvement, some new breakage has occurred and should be fixed.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017, 2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2019-2020 Rocky Bernstein
|
||||
"""
|
||||
Python 3.7 base code. We keep non-custom-generated grammar rules out of this file.
|
||||
"""
|
||||
@@ -581,6 +581,18 @@ class Python37BaseParser(PythonParser):
|
||||
elif opname == "LOAD_LISTCOMP":
|
||||
self.add_unique_rule("expr ::= listcomp", opname, token.attr, customize)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname == "LOAD_NAME":
|
||||
if token.attr == "__annotations__" and "SETUP_ANNOTATIONS" in self.seen_ops:
|
||||
token.kind = "LOAD_ANNOTATION"
|
||||
self.addRule(
|
||||
"""
|
||||
stmt ::= SETUP_ANNOTATIONS
|
||||
stmt ::= ann_assign
|
||||
ann_assign ::= expr LOAD_ANNOTATION LOAD_STR STORE_SUBSCR
|
||||
""",
|
||||
nop_func,
|
||||
)
|
||||
pass
|
||||
elif opname == "LOAD_SETCOMP":
|
||||
# Should this be generalized and put under MAKE_FUNCTION?
|
||||
if has_get_iter_call_function1:
|
||||
@@ -1103,8 +1115,13 @@ class Python37BaseParser(PythonParser):
|
||||
# FIXME: This is a cheap test. Should we do something with an AST like we
|
||||
# do with "and"?
|
||||
# "or"s with constants like this will have "COME_FROM" at the end
|
||||
return tokens[last] in ("LOAD_ASSERT", "LOAD_STR", "LOAD_CODE", "LOAD_CONST",
|
||||
"RAISE_VARARGS_1")
|
||||
return tokens[last] in (
|
||||
"LOAD_ASSERT",
|
||||
"LOAD_STR",
|
||||
"LOAD_CODE",
|
||||
"LOAD_CONST",
|
||||
"RAISE_VARARGS_1",
|
||||
)
|
||||
elif lhs == "while1elsestmt":
|
||||
|
||||
if last == n:
|
||||
@@ -1143,7 +1160,7 @@ class Python37BaseParser(PythonParser):
|
||||
for i in range(cfl - 1, first, -1):
|
||||
if tokens[i] != "POP_BLOCK":
|
||||
break
|
||||
if tokens[i].kind not in ("JUMP_BACK", "RETURN_VALUE"):
|
||||
if tokens[i].kind not in ("JUMP_BACK", "RETURN_VALUE", "RAISE_VARARGS_1"):
|
||||
if not tokens[i].kind.startswith("COME_FROM"):
|
||||
return True
|
||||
|
||||
@@ -1156,9 +1173,8 @@ class Python37BaseParser(PythonParser):
|
||||
last -= 1
|
||||
offset = tokens[last].off2int()
|
||||
assert tokens[first] == "SETUP_LOOP"
|
||||
if offset != tokens[first].attr:
|
||||
return True
|
||||
return False
|
||||
# SETUP_LOOP location must jump either to the last token or the token after the last one
|
||||
return tokens[first].attr not in (offset, offset + 2)
|
||||
elif lhs == "_ifstmts_jump" and len(rule[1]) > 1 and ast:
|
||||
come_froms = ast[-1]
|
||||
# Make sure all of the "come froms" offset at the
|
||||
@@ -1192,6 +1208,10 @@ class Python37BaseParser(PythonParser):
|
||||
return False
|
||||
|
||||
if isinstance(come_froms, Token):
|
||||
if tokens[pop_jump_index].attr < tokens[pop_jump_index].offset and ast[0] != "pass":
|
||||
# This is a jump backwards to a loop. All bets are off here when there the
|
||||
# unless statement is "pass" which has no instructions associated with it.
|
||||
return False
|
||||
return (
|
||||
come_froms.attr is not None
|
||||
and tokens[pop_jump_index].offset > come_froms.attr
|
||||
@@ -1210,7 +1230,7 @@ class Python37BaseParser(PythonParser):
|
||||
if last == n:
|
||||
last -= 1
|
||||
pass
|
||||
if (tokens[last].attr and isinstance(tokens[last].attr, int)):
|
||||
if tokens[last].attr and isinstance(tokens[last].attr, int):
|
||||
return tokens[first].offset < tokens[last].attr
|
||||
pass
|
||||
|
||||
@@ -1225,7 +1245,14 @@ class Python37BaseParser(PythonParser):
|
||||
for i in range(first, l):
|
||||
t = tokens[i]
|
||||
if t.kind == "POP_JUMP_IF_FALSE":
|
||||
if t.attr > last_offset:
|
||||
pjif_target = t.attr
|
||||
if pjif_target > last_offset:
|
||||
# In come cases, where we have long bytecode, a
|
||||
# "POP_JUMP_IF_FALSE" offset might be too
|
||||
# large for the instruction; so instead it
|
||||
# jumps to a JUMP_FORWARD. Allow that here.
|
||||
if tokens[l] == "JUMP_FORWARD":
|
||||
return tokens[l].attr != pjif_target
|
||||
return True
|
||||
pass
|
||||
pass
|
||||
@@ -1244,7 +1271,11 @@ class Python37BaseParser(PythonParser):
|
||||
if last == n:
|
||||
last -= 1
|
||||
jmp_target = test[1][0].attr
|
||||
if tokens[first].off2int() <= jmp_target < tokens[last].off2int():
|
||||
if (
|
||||
tokens[first].off2int()
|
||||
<= jmp_target
|
||||
< tokens[last].off2int()
|
||||
):
|
||||
return True
|
||||
# jmp_target less than tokens[first] is okay - is to a loop
|
||||
# jmp_target equal tokens[last] is also okay: normal non-optimized non-loop jump
|
||||
@@ -1279,7 +1310,11 @@ class Python37BaseParser(PythonParser):
|
||||
# jmp_target less than tokens[first] is okay - is to a loop
|
||||
# jmp_target equal tokens[last] is also okay: normal non-optimized non-loop jump
|
||||
|
||||
if (last + 1) < n and tokens[last - 1] != "JUMP_BACK" and tokens[last + 1] == "COME_FROM_LOOP":
|
||||
if (
|
||||
(last + 1) < n
|
||||
and tokens[last - 1] != "JUMP_BACK"
|
||||
and tokens[last + 1] == "COME_FROM_LOOP"
|
||||
):
|
||||
# iflastsmtl is not at the end of a loop, but jumped outside of loop. No good.
|
||||
# FIXME: check that tokens[last] == "POP_BLOCK"? Or allow for it not to appear?
|
||||
return True
|
||||
@@ -1323,6 +1358,36 @@ class Python37BaseParser(PythonParser):
|
||||
"_come_froms",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
"testexpr",
|
||||
"c_stmts_opt",
|
||||
"jump_forward_else",
|
||||
"else_suite",
|
||||
'\\e__come_froms'
|
||||
),
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
"testexpr",
|
||||
"c_stmts_opt",
|
||||
"jf_cfs",
|
||||
"else_suite",
|
||||
'\\e_opt_come_from_except',
|
||||
),
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
"testexpr",
|
||||
"c_stmts_opt",
|
||||
"come_froms",
|
||||
"else_suite",
|
||||
'come_froms',
|
||||
),
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
@@ -1345,7 +1410,8 @@ class Python37BaseParser(PythonParser):
|
||||
if come_froms == "opt_come_from_except" and len(come_froms) > 0:
|
||||
come_froms = come_froms[0]
|
||||
if not isinstance(come_froms, Token):
|
||||
return tokens[first].offset > come_froms[-1].attr
|
||||
if len(come_froms):
|
||||
return tokens[first].offset > come_froms[-1].attr
|
||||
elif tokens[first].offset > come_froms.attr:
|
||||
return True
|
||||
|
||||
@@ -1363,16 +1429,34 @@ class Python37BaseParser(PythonParser):
|
||||
|
||||
# Check that the condition portion of the "if"
|
||||
# jumps to the "else" part.
|
||||
# Compare with parse30.py of uncompyle6
|
||||
if testexpr[0] in ("testtrue", "testfalse"):
|
||||
test = testexpr[0]
|
||||
|
||||
else_suite = ast[3]
|
||||
assert else_suite == "else_suite"
|
||||
|
||||
if len(test) > 1 and test[1].kind.startswith("jmp_"):
|
||||
if last == n:
|
||||
last -= 1
|
||||
jmp = test[1]
|
||||
jmp_target = jmp[0].attr
|
||||
|
||||
# FIXME: the jump inside "else" check below should be added.
|
||||
#
|
||||
# add this until we can find out what's wrong with
|
||||
# not being able to parse:
|
||||
# if a and b or c:
|
||||
# x = 1
|
||||
# else:
|
||||
# x = 2
|
||||
|
||||
# FIXME: add this
|
||||
# if jmp_target < else_suite.first_child().off2int():
|
||||
# return True
|
||||
|
||||
if tokens[first].off2int() > jmp_target:
|
||||
return True
|
||||
|
||||
return (jmp_target > tokens[last].off2int()) and tokens[
|
||||
last
|
||||
] != "JUMP_FORWARD"
|
||||
|
Reference in New Issue
Block a user