You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Partial sync with decompyle3
This commit is contained in:
@@ -131,6 +131,7 @@ Python.
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from spark_parser import GenericASTTraversal
|
from spark_parser import GenericASTTraversal
|
||||||
from xdis import COMPILER_FLAG_BIT, iscode
|
from xdis import COMPILER_FLAG_BIT, iscode
|
||||||
@@ -159,7 +160,11 @@ from uncompyle6.semantics.consts import (
|
|||||||
)
|
)
|
||||||
from uncompyle6.semantics.customize import customize_for_version
|
from uncompyle6.semantics.customize import customize_for_version
|
||||||
from uncompyle6.semantics.gencomp import ComprehensionMixin
|
from uncompyle6.semantics.gencomp import ComprehensionMixin
|
||||||
from uncompyle6.semantics.helper import find_globals_and_nonlocals, print_docstring
|
from uncompyle6.semantics.helper import (
|
||||||
|
find_globals_and_nonlocals,
|
||||||
|
is_lambda_mode,
|
||||||
|
print_docstring,
|
||||||
|
)
|
||||||
from uncompyle6.semantics.make_function1 import make_function1
|
from uncompyle6.semantics.make_function1 import make_function1
|
||||||
from uncompyle6.semantics.make_function2 import make_function2
|
from uncompyle6.semantics.make_function2 import make_function2
|
||||||
from uncompyle6.semantics.make_function3 import make_function3
|
from uncompyle6.semantics.make_function3 import make_function3
|
||||||
@@ -213,7 +218,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
version,
|
version: tuple,
|
||||||
out,
|
out,
|
||||||
scanner,
|
scanner,
|
||||||
showast=TREE_DEFAULT_DEBUG,
|
showast=TREE_DEFAULT_DEBUG,
|
||||||
@@ -223,7 +228,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
linestarts={},
|
linestarts={},
|
||||||
tolerate_errors=False,
|
tolerate_errors=False,
|
||||||
):
|
):
|
||||||
"""`version' is the Python version (a float) of the Python dialect
|
"""`version' is the Python version of the Python dialect
|
||||||
of both the syntax tree and language we should produce.
|
of both the syntax tree and language we should produce.
|
||||||
|
|
||||||
`out' is IO-like file pointer to where the output should go. It
|
`out' is IO-like file pointer to where the output should go. It
|
||||||
@@ -235,9 +240,12 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
|
|
||||||
If `showast' is True, we print the syntax tree.
|
If `showast' is True, we print the syntax tree.
|
||||||
|
|
||||||
`compile_mode' is is either 'exec' or 'single'. It is the compile
|
`compile_mode` is is either `exec`, `single` or `lambda`.
|
||||||
mode that was used to create the Syntax Tree and specifies a
|
|
||||||
grammar variant within a Python version to use.
|
For `lambda`, the grammar that can be used in lambda
|
||||||
|
expressions is used. Otherwise, it is the compile mode that
|
||||||
|
was used to create the Syntax Tree and specifies a grammar
|
||||||
|
variant within a Python version to use.
|
||||||
|
|
||||||
`is_pypy` should be True if the Syntax Tree was generated for PyPy.
|
`is_pypy` should be True if the Syntax Tree was generated for PyPy.
|
||||||
|
|
||||||
@@ -262,10 +270,8 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
self.currentclass = None
|
self.currentclass = None
|
||||||
self.classes = []
|
self.classes = []
|
||||||
self.debug_parser = dict(debug_parser)
|
self.debug_parser = dict(debug_parser)
|
||||||
# Initialize p_lambda on demand
|
|
||||||
self.line_number = 1
|
self.line_number = 1
|
||||||
self.linemap = {}
|
self.linemap = {}
|
||||||
self.p_lambda = None
|
|
||||||
self.params = params
|
self.params = params
|
||||||
self.param_stack = []
|
self.param_stack = []
|
||||||
self.ERROR = None
|
self.ERROR = None
|
||||||
@@ -276,11 +282,15 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
self.pending_newlines = 0
|
self.pending_newlines = 0
|
||||||
self.linestarts = linestarts
|
self.linestarts = linestarts
|
||||||
self.treeTransform = TreeTransform(version=self.version, show_ast=showast)
|
self.treeTransform = TreeTransform(version=self.version, show_ast=showast)
|
||||||
|
|
||||||
# FIXME: have p.insts update in a better way
|
# FIXME: have p.insts update in a better way
|
||||||
# modularity is broken here
|
# modularity is broken here
|
||||||
self.insts = scanner.insts
|
self.insts = scanner.insts
|
||||||
self.offset2inst_index = scanner.offset2inst_index
|
self.offset2inst_index = scanner.offset2inst_index
|
||||||
|
|
||||||
|
# Initialize p_lambda on demand
|
||||||
|
self.p_lambda = None
|
||||||
|
|
||||||
# This is in Python 2.6 on. It changes the way
|
# This is in Python 2.6 on. It changes the way
|
||||||
# strings get interpreted. See n_LOAD_CONST
|
# strings get interpreted. See n_LOAD_CONST
|
||||||
self.FUTURE_UNICODE_LITERALS = False
|
self.FUTURE_UNICODE_LITERALS = False
|
||||||
@@ -507,19 +517,19 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
def pp_tuple(self, tup):
|
def pp_tuple(self, tup):
|
||||||
"""Pretty print a tuple"""
|
"""Pretty print a tuple"""
|
||||||
last_line = self.f.getvalue().split("\n")[-1]
|
last_line = self.f.getvalue().split("\n")[-1]
|
||||||
l = len(last_line) + 1
|
ll = len(last_line) + 1
|
||||||
indent = " " * l
|
indent = " " * ll
|
||||||
self.write("(")
|
self.write("(")
|
||||||
sep = ""
|
sep = ""
|
||||||
for item in tup:
|
for item in tup:
|
||||||
self.write(sep)
|
self.write(sep)
|
||||||
l += len(sep)
|
ll += len(sep)
|
||||||
s = better_repr(item, self.version)
|
s = better_repr(item, self.version)
|
||||||
l += len(s)
|
ll += len(s)
|
||||||
self.write(s)
|
self.write(s)
|
||||||
sep = ","
|
sep = ","
|
||||||
if l > LINE_LENGTH:
|
if ll > LINE_LENGTH:
|
||||||
l = 0
|
ll = 0
|
||||||
sep += "\n" + indent
|
sep += "\n" + indent
|
||||||
else:
|
else:
|
||||||
sep += " "
|
sep += " "
|
||||||
@@ -699,9 +709,10 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# print("-----")
|
# print("-----")
|
||||||
# print(startnode)
|
# print(startnode.kind)
|
||||||
# print(entry[0])
|
# print(entry[0])
|
||||||
# print('======')
|
# print('======')
|
||||||
|
|
||||||
fmt = entry[0]
|
fmt = entry[0]
|
||||||
arg = 1
|
arg = 1
|
||||||
i = 0
|
i = 0
|
||||||
@@ -794,13 +805,9 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
node[index].kind,
|
node[index].kind,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
assert (
|
assert node[tup[0]] in tup[1], (
|
||||||
node[tup[0]] in tup[1]
|
f"at {node.kind}[{tup[0]}], expected to be in '{tup[1]}' "
|
||||||
), "at %s[%d], expected to be in '%s' node; got '%s'" % (
|
f"node; got '{node[tup[0]].kind}'"
|
||||||
node.kind,
|
|
||||||
arg,
|
|
||||||
index[1],
|
|
||||||
node[index[0]].kind,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -869,7 +876,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
d = node.__dict__
|
d = node.__dict__
|
||||||
try:
|
try:
|
||||||
self.write(eval(expr, d, d))
|
self.write(eval(expr, d, d))
|
||||||
except:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
m = escape.search(fmt, i)
|
m = escape.search(fmt, i)
|
||||||
self.write(fmt[i:])
|
self.write(fmt[i:])
|
||||||
@@ -1190,7 +1197,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
is_lambda=False,
|
is_lambda=False,
|
||||||
noneInNames=False,
|
noneInNames=False,
|
||||||
is_top_level_module=False,
|
is_top_level_module=False,
|
||||||
):
|
) -> GenericASTTraversal:
|
||||||
# FIXME: DRY with fragments.py
|
# FIXME: DRY with fragments.py
|
||||||
|
|
||||||
# assert isinstance(tokens[0], Token)
|
# assert isinstance(tokens[0], Token)
|
||||||
@@ -1242,7 +1249,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
# Build a parse tree from a tokenized and massaged disassembly.
|
# Build a parse tree from a tokenized and massaged disassembly.
|
||||||
try:
|
try:
|
||||||
# FIXME: have p.insts update in a better way
|
# FIXME: have p.insts update in a better way
|
||||||
# modularity is broken here
|
# Modularity is broken here.
|
||||||
p_insts = self.p.insts
|
p_insts = self.p.insts
|
||||||
self.p.insts = self.scanner.insts
|
self.p.insts = self.scanner.insts
|
||||||
self.p.offset2inst_index = self.scanner.offset2inst_index
|
self.p.offset2inst_index = self.scanner.offset2inst_index
|
||||||
@@ -1255,6 +1262,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
checker(ast, False, self.ast_errors)
|
checker(ast, False, self.ast_errors)
|
||||||
|
|
||||||
self.customize(customize)
|
self.customize(customize)
|
||||||
|
|
||||||
transform_tree = self.treeTransform.transform(ast, code)
|
transform_tree = self.treeTransform.transform(ast, code)
|
||||||
|
|
||||||
self.maybe_show_tree(ast, phase="before")
|
self.maybe_show_tree(ast, phase="before")
|
||||||
@@ -1270,13 +1278,15 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
def code_deparse(
|
def code_deparse(
|
||||||
co,
|
co,
|
||||||
out=sys.stdout,
|
out=sys.stdout,
|
||||||
version=None,
|
version: Optional[tuple] = None,
|
||||||
debug_opts=DEFAULT_DEBUG_OPTS,
|
debug_opts=DEFAULT_DEBUG_OPTS,
|
||||||
code_objects={},
|
code_objects={},
|
||||||
compile_mode="exec",
|
compile_mode="exec",
|
||||||
is_pypy=IS_PYPY,
|
is_pypy=IS_PYPY,
|
||||||
walker=SourceWalker,
|
walker=SourceWalker,
|
||||||
):
|
start_offset: int = 0,
|
||||||
|
stop_offset: int = -1,
|
||||||
|
) -> Optional[SourceWalker]:
|
||||||
"""
|
"""
|
||||||
ingests and deparses a given code block 'co'. If version is None,
|
ingests and deparses a given code block 'co'. If version is None,
|
||||||
we will use the current Python interpreter version.
|
we will use the current Python interpreter version.
|
||||||
@@ -1284,6 +1294,9 @@ def code_deparse(
|
|||||||
|
|
||||||
assert iscode(co)
|
assert iscode(co)
|
||||||
|
|
||||||
|
if out is None:
|
||||||
|
out = sys.stdout
|
||||||
|
|
||||||
if version is None:
|
if version is None:
|
||||||
version = PYTHON_VERSION_TRIPLE
|
version = PYTHON_VERSION_TRIPLE
|
||||||
|
|
||||||
@@ -1294,6 +1307,21 @@ def code_deparse(
|
|||||||
co, code_objects=code_objects, show_asm=debug_opts["asm"]
|
co, code_objects=code_objects, show_asm=debug_opts["asm"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if start_offset > 0:
|
||||||
|
for i, t in enumerate(tokens):
|
||||||
|
# If t.offset is a string, we want to skip this.
|
||||||
|
if isinstance(t.offset, int) and t.offset >= start_offset:
|
||||||
|
tokens = tokens[i:]
|
||||||
|
break
|
||||||
|
|
||||||
|
if stop_offset > -1:
|
||||||
|
for i, t in enumerate(tokens):
|
||||||
|
# In contrast to the test for start_offset If t.offset is
|
||||||
|
# a string, we want to extract the integer offset value.
|
||||||
|
if t.off2int() >= stop_offset:
|
||||||
|
tokens = tokens[:i]
|
||||||
|
break
|
||||||
|
|
||||||
debug_parser = debug_opts.get("grammar", dict(PARSER_DEFAULT_DEBUG))
|
debug_parser = debug_opts.get("grammar", dict(PARSER_DEFAULT_DEBUG))
|
||||||
|
|
||||||
# Build Syntax Tree from disassembly.
|
# Build Syntax Tree from disassembly.
|
||||||
@@ -1317,7 +1345,7 @@ def code_deparse(
|
|||||||
tokens,
|
tokens,
|
||||||
customize,
|
customize,
|
||||||
co,
|
co,
|
||||||
is_lambda=(compile_mode == "lambda"),
|
is_lambda=is_lambda_mode(compile_mode),
|
||||||
is_top_level_module=is_top_level_module,
|
is_top_level_module=is_top_level_module,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1326,7 +1354,7 @@ def code_deparse(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# FIXME use a lookup table here.
|
# FIXME use a lookup table here.
|
||||||
if compile_mode == "lambda":
|
if is_lambda_mode(compile_mode):
|
||||||
expected_start = "lambda_start"
|
expected_start = "lambda_start"
|
||||||
elif compile_mode == "eval":
|
elif compile_mode == "eval":
|
||||||
expected_start = "expr_start"
|
expected_start = "expr_start"
|
||||||
@@ -1339,10 +1367,12 @@ def code_deparse(
|
|||||||
expected_start = None
|
expected_start = None
|
||||||
else:
|
else:
|
||||||
expected_start = None
|
expected_start = None
|
||||||
|
|
||||||
if expected_start:
|
if expected_start:
|
||||||
assert (
|
assert deparsed.ast == expected_start, (
|
||||||
deparsed.ast == expected_start
|
f"Should have parsed grammar start to '{expected_start}'; "
|
||||||
), f"Should have parsed grammar start to '{expected_start}'; got: {deparsed.ast.kind}"
|
f"got: {deparsed.ast.kind}"
|
||||||
|
)
|
||||||
# save memory
|
# save memory
|
||||||
del tokens
|
del tokens
|
||||||
|
|
||||||
@@ -1382,7 +1412,7 @@ def code_deparse(
|
|||||||
deparsed.ast,
|
deparsed.ast,
|
||||||
name=co.co_name,
|
name=co.co_name,
|
||||||
customize=customize,
|
customize=customize,
|
||||||
is_lambda=compile_mode == "lambda",
|
is_lambda=is_lambda_mode(compile_mode),
|
||||||
debug_opts=debug_opts,
|
debug_opts=debug_opts,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1410,9 +1440,12 @@ def deparse_code2str(
|
|||||||
compile_mode="exec",
|
compile_mode="exec",
|
||||||
is_pypy=IS_PYPY,
|
is_pypy=IS_PYPY,
|
||||||
walker=SourceWalker,
|
walker=SourceWalker,
|
||||||
):
|
start_offset: int = 0,
|
||||||
"""Return the deparsed text for a Python code object. `out` is where any intermediate
|
stop_offset: int = -1,
|
||||||
output for assembly or tree output will be sent.
|
) -> str:
|
||||||
|
"""
|
||||||
|
Return the deparsed text for a Python code object. `out` is where
|
||||||
|
any intermediate output for assembly or tree output will be sent.
|
||||||
"""
|
"""
|
||||||
return code_deparse(
|
return code_deparse(
|
||||||
code,
|
code,
|
||||||
@@ -1427,6 +1460,7 @@ def deparse_code2str(
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
def deparse_test(co):
|
def deparse_test(co):
|
||||||
"""This is a docstring"""
|
"""This is a docstring"""
|
||||||
s = deparse_code2str(co)
|
s = deparse_code2str(co)
|
||||||
@@ -1434,5 +1468,4 @@ if __name__ == "__main__":
|
|||||||
print(s)
|
print(s)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
deparse_test(deparse_test.__code__)
|
deparse_test(deparse_test.__code__)
|
||||||
|
Reference in New Issue
Block a user