You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
Partial merge
This commit is contained in:
@@ -597,12 +597,12 @@ class PythonParser(GenericASTBuilder):
|
|||||||
compare ::= compare_single
|
compare ::= compare_single
|
||||||
compare_single ::= expr expr COMPARE_OP
|
compare_single ::= expr expr COMPARE_OP
|
||||||
|
|
||||||
# A compare_chained is two comparisions, as in: x <= y <= z
|
# A compare_chained is two comparisons, as in: x <= y <= z
|
||||||
compare_chained ::= expr compared_chained_middle ROT_TWO POP_TOP
|
compare_chained ::= expr compared_chained_middle ROT_TWO POP_TOP
|
||||||
_come_froms
|
_come_froms
|
||||||
compare_chained_right ::= expr COMPARE_OP JUMP_FORWARD
|
compare_chained_right ::= expr COMPARE_OP JUMP_FORWARD
|
||||||
|
|
||||||
# Non-null kvlist items are broken out in the indiviual grammars
|
# Non-null kvlist items are broken out in the individual grammars
|
||||||
kvlist ::=
|
kvlist ::=
|
||||||
|
|
||||||
# Positional arguments in make_function
|
# Positional arguments in make_function
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2019, 2021-2023 by Rocky Bernstein
|
# Copyright (c) 2015-2019, 2021-2024 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
|
||||||
@@ -74,7 +74,6 @@ from xdis import iscode
|
|||||||
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
|
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
|
||||||
|
|
||||||
import uncompyle6.parser as python_parser
|
import uncompyle6.parser as python_parser
|
||||||
from uncompyle6 import parser
|
|
||||||
from uncompyle6.parsers.treenode import SyntaxTree
|
from uncompyle6.parsers.treenode import SyntaxTree
|
||||||
from uncompyle6.scanner import Code, Token, get_scanner
|
from uncompyle6.scanner import Code, Token, get_scanner
|
||||||
from uncompyle6.semantics import pysource
|
from uncompyle6.semantics import pysource
|
||||||
@@ -88,7 +87,12 @@ from uncompyle6.semantics.consts import (
|
|||||||
TABLE_DIRECT,
|
TABLE_DIRECT,
|
||||||
escape,
|
escape,
|
||||||
)
|
)
|
||||||
from uncompyle6.semantics.pysource import ParserError, StringIO
|
from uncompyle6.semantics.pysource import (
|
||||||
|
DEFAULT_DEBUG_OPTS,
|
||||||
|
TREE_DEFAULT_DEBUG,
|
||||||
|
ParserError,
|
||||||
|
StringIO,
|
||||||
|
)
|
||||||
from uncompyle6.show import maybe_show_asm, maybe_show_tree
|
from uncompyle6.show import maybe_show_asm, maybe_show_tree
|
||||||
|
|
||||||
NodeInfo = namedtuple("NodeInfo", "node start finish")
|
NodeInfo = namedtuple("NodeInfo", "node start finish")
|
||||||
@@ -152,10 +156,11 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self,
|
self,
|
||||||
version,
|
version,
|
||||||
scanner,
|
scanner,
|
||||||
showast=False,
|
showast=TREE_DEFAULT_DEBUG,
|
||||||
debug_parser=PARSER_DEFAULT_DEBUG,
|
debug_parser=PARSER_DEFAULT_DEBUG,
|
||||||
compile_mode="exec",
|
compile_mode="exec",
|
||||||
is_pypy=False,
|
is_pypy=IS_PYPY,
|
||||||
|
linestarts={},
|
||||||
tolerate_errors=True,
|
tolerate_errors=True,
|
||||||
):
|
):
|
||||||
pysource.SourceWalker.__init__(
|
pysource.SourceWalker.__init__(
|
||||||
@@ -167,18 +172,17 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
debug_parser=debug_parser,
|
debug_parser=debug_parser,
|
||||||
compile_mode=compile_mode,
|
compile_mode=compile_mode,
|
||||||
is_pypy=is_pypy,
|
is_pypy=is_pypy,
|
||||||
|
linestarts=linestarts,
|
||||||
tolerate_errors=tolerate_errors,
|
tolerate_errors=tolerate_errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Hide_internal suppresses displaying the additional instructions that sometimes
|
# hide_internal suppresses displaying the additional instructions that sometimes
|
||||||
# exist in code but but were not written in the source code.
|
# exist in code but but were not written in the source code.
|
||||||
# An example is:
|
# An example is:
|
||||||
# __module__ = __name__
|
# __module__ = __name__
|
||||||
#
|
# If showing source code we generally don't want to show this. However in fragment
|
||||||
# If showing source code we generally don't want to show this. However
|
# deparsing we generally do need to see these instructions since we may be stopped
|
||||||
# in fragment deparsing we generally do need to see these instructions
|
# at one. So here we do not want to suppress showing such instructions.
|
||||||
# since we may be stopped at one. So here we do not want to suppress
|
|
||||||
# showing such instructions.
|
|
||||||
self.hide_internal = False
|
self.hide_internal = False
|
||||||
self.offsets = {}
|
self.offsets = {}
|
||||||
self.last_finish = -1
|
self.last_finish = -1
|
||||||
@@ -659,7 +663,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
n = ast[iter_index]
|
n = ast[iter_index]
|
||||||
|
|
||||||
assert n == "comp_iter"
|
assert n == "comp_iter", n.kind
|
||||||
# Find the comprehension body. It is the inner-most
|
# Find the comprehension body. It is the inner-most
|
||||||
# node that is not list_.. .
|
# node that is not list_.. .
|
||||||
while n == "comp_iter": # list_iter
|
while n == "comp_iter": # list_iter
|
||||||
@@ -718,7 +722,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
assert iscode(code), node[code_index]
|
assert iscode(code), node[code_index]
|
||||||
code_name = code.co_name
|
code_name = code.co_name
|
||||||
code = Code(code, self.scanner, self.currentclass)
|
code = Code(code, self.scanner, self.currentclass, self.debug_opts["asm"])
|
||||||
|
|
||||||
ast = self.build_ast(code._tokens, code._customize, code)
|
ast = self.build_ast(code._tokens, code._customize, code)
|
||||||
|
|
||||||
@@ -1065,13 +1069,17 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
# Python 3.2 works like this
|
# Python 3.2 works like this
|
||||||
subclass = load_closure[-2].attr
|
subclass = load_closure[-2].attr
|
||||||
else:
|
else:
|
||||||
raise "Internal Error n_classdef: cannot find class body"
|
raise RuntimeError(
|
||||||
|
"Internal Error n_classdef: cannot find class body"
|
||||||
|
)
|
||||||
if hasattr(buildclass[3], "__len__"):
|
if hasattr(buildclass[3], "__len__"):
|
||||||
subclass_info = buildclass[3]
|
subclass_info = buildclass[3]
|
||||||
elif hasattr(buildclass[2], "__len__"):
|
elif hasattr(buildclass[2], "__len__"):
|
||||||
subclass_info = buildclass[2]
|
subclass_info = buildclass[2]
|
||||||
else:
|
else:
|
||||||
raise "Internal Error n_classdef: cannot superclass name"
|
raise RuntimeError(
|
||||||
|
"Internal Error n_classdef: cannot superclass name"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
subclass = buildclass[1][0].attr
|
subclass = buildclass[1][0].attr
|
||||||
subclass_info = node[0]
|
subclass_info = node[0]
|
||||||
@@ -1119,7 +1127,13 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
n_classdefdeco2 = n_classdef
|
n_classdefdeco2 = n_classdef
|
||||||
|
|
||||||
def gen_source(
|
def gen_source(
|
||||||
self, ast, name, customize, is_lambda=False, returnNone=False, debug_opts=None
|
self,
|
||||||
|
ast,
|
||||||
|
name,
|
||||||
|
customize,
|
||||||
|
is_lambda=False,
|
||||||
|
returnNone=False,
|
||||||
|
debug_opts=DEFAULT_DEBUG_OPTS,
|
||||||
):
|
):
|
||||||
"""convert parse tree to Python source code"""
|
"""convert parse tree to Python source code"""
|
||||||
|
|
||||||
@@ -1205,7 +1219,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
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
|
||||||
self.p.opc = self.scanner.opc
|
self.p.opc = self.scanner.opc
|
||||||
ast = parser.parse(self.p, tokens, customize, code)
|
ast = python_parser.parse(self.p, tokens, customize, code)
|
||||||
self.p.insts = p_insts
|
self.p.insts = p_insts
|
||||||
except (python_parser.ParserError, AssertionError) as e:
|
except (python_parser.ParserError, AssertionError) as e:
|
||||||
raise ParserError(e, tokens, {})
|
raise ParserError(e, tokens, {})
|
||||||
@@ -1348,7 +1362,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
selectedText = text[start:finish]
|
selectedText = text[start:finish]
|
||||||
|
|
||||||
# Compute offsets relative to the beginning of the
|
# Compute offsets relative to the beginning of the
|
||||||
# line rather than the beinning of the text
|
# line rather than the beginning of the text.
|
||||||
try:
|
try:
|
||||||
lineStart = text[:start].rindex("\n") + 1
|
lineStart = text[:start].rindex("\n") + 1
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -1356,7 +1370,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
adjustedStart = start - lineStart
|
adjustedStart = start - lineStart
|
||||||
|
|
||||||
# If selected text is greater than a single line
|
# If selected text is greater than a single line
|
||||||
# just show the first line plus elipses.
|
# just show the first line plus ellipsis.
|
||||||
lines = selectedText.split("\n")
|
lines = selectedText.split("\n")
|
||||||
if len(lines) > 1:
|
if len(lines) > 1:
|
||||||
adjustedEnd = len(lines[0]) - adjustedStart
|
adjustedEnd = len(lines[0]) - adjustedStart
|
||||||
@@ -1429,7 +1443,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
p = node.parent
|
p = node.parent
|
||||||
orig_parent = p
|
orig_parent = p
|
||||||
# If we can get different text, use that as the parent,
|
# If we can get different text, use that as the parent,
|
||||||
# otherwise we'll use the immeditate parent
|
# otherwise we'll use the immediatate parent.
|
||||||
while p and (
|
while p and (
|
||||||
hasattr(p, "parent") and p.start == node.start and p.finish == node.finish
|
hasattr(p, "parent") and p.start == node.start and p.finish == node.finish
|
||||||
):
|
):
|
||||||
@@ -1566,19 +1580,19 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
if node[0].kind.startswith("kvlist"):
|
if node[0].kind.startswith("kvlist"):
|
||||||
# Python 3.5+ style key/value list in dict
|
# Python 3.5+ style key/value list in dict
|
||||||
kv_node = node[0]
|
kv_node = node[0]
|
||||||
l = list(kv_node)
|
ll = list(kv_node)
|
||||||
length = len(l)
|
length = len(ll)
|
||||||
if kv_node[-1].kind.startswith("BUILD_MAP"):
|
if kv_node[-1].kind.startswith("BUILD_MAP"):
|
||||||
length -= 1
|
length -= 1
|
||||||
i = 0
|
i = 0
|
||||||
while i < length:
|
while i < length:
|
||||||
self.write(sep)
|
self.write(sep)
|
||||||
name = self.traverse(l[i], indent="")
|
name = self.traverse(ll[i], indent="")
|
||||||
l[i].parent = kv_node
|
ll[i].parent = kv_node
|
||||||
l[i + 1].parent = kv_node
|
ll[i + 1].parent = kv_node
|
||||||
self.write(name, ": ")
|
self.write(name, ": ")
|
||||||
value = self.traverse(
|
value = self.traverse(
|
||||||
l[i + 1], indent=self.indent + (len(name) + 2) * " "
|
ll[i + 1], indent=self.indent + (len(name) + 2) * " "
|
||||||
)
|
)
|
||||||
self.write(sep, name, ": ", value)
|
self.write(sep, name, ": ", value)
|
||||||
sep = line_seperator
|
sep = line_seperator
|
||||||
@@ -1588,25 +1602,25 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
elif len(node) > 1 and node[1].kind.startswith("kvlist"):
|
elif len(node) > 1 and node[1].kind.startswith("kvlist"):
|
||||||
# Python 3.0..3.4 style key/value list in dict
|
# Python 3.0..3.4 style key/value list in dict
|
||||||
kv_node = node[1]
|
kv_node = node[1]
|
||||||
l = list(kv_node)
|
ll = list(kv_node)
|
||||||
if len(l) > 0 and l[0].kind == "kv3":
|
if len(ll) > 0 and ll[0].kind == "kv3":
|
||||||
# Python 3.2 does this
|
# Python 3.2 does this
|
||||||
kv_node = node[1][0]
|
kv_node = node[1][0]
|
||||||
l = list(kv_node)
|
ll = list(kv_node)
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(l):
|
while i < len(ll):
|
||||||
l[i].parent = kv_node
|
ll[i].parent = kv_node
|
||||||
l[i + 1].parent = kv_node
|
ll[i + 1].parent = kv_node
|
||||||
key_start = len(self.f.getvalue()) + len(sep)
|
key_start = len(self.f.getvalue()) + len(sep)
|
||||||
name = self.traverse(l[i + 1], indent="")
|
name = self.traverse(ll[i + 1], indent="")
|
||||||
key_finish = key_start + len(name)
|
key_finish = key_start + len(name)
|
||||||
val_start = key_finish + 2
|
val_start = key_finish + 2
|
||||||
value = self.traverse(
|
value = self.traverse(
|
||||||
l[i], indent=self.indent + (len(name) + 2) * " "
|
ll[i], indent=self.indent + (len(name) + 2) * " "
|
||||||
)
|
)
|
||||||
self.write(sep, name, ": ", value)
|
self.write(sep, name, ": ", value)
|
||||||
self.set_pos_info_recurse(l[i + 1], key_start, key_finish)
|
self.set_pos_info_recurse(ll[i + 1], key_start, key_finish)
|
||||||
self.set_pos_info_recurse(l[i], val_start, val_start + len(value))
|
self.set_pos_info_recurse(ll[i], val_start, val_start + len(value))
|
||||||
sep = line_seperator
|
sep = line_seperator
|
||||||
i += 3
|
i += 3
|
||||||
pass
|
pass
|
||||||
@@ -1779,7 +1793,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
n_set = n_tuple = n_build_set = n_list
|
n_set = n_tuple = n_build_set = n_list
|
||||||
|
|
||||||
def template_engine(self, entry, startnode):
|
def template_engine(self, entry, startnode):
|
||||||
"""The format template interpetation engine. See the comment at the
|
"""The format template interpretation engine. See the comment at the
|
||||||
beginning of this module for the how we interpret format
|
beginning of this module for the how we interpret format
|
||||||
specifications such as %c, %C, and so on.
|
specifications such as %c, %C, and so on.
|
||||||
"""
|
"""
|
||||||
@@ -1810,7 +1824,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
if m.group("child"):
|
if m.group("child"):
|
||||||
node = node[int(m.group("child"))]
|
node = node[int(m.group("child"))]
|
||||||
node.parent = startnode
|
node.parent = startnode
|
||||||
except:
|
except Exception:
|
||||||
print(node.__dict__)
|
print(node.__dict__)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -1947,7 +1961,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
start = len(self.f.getvalue())
|
start = len(self.f.getvalue())
|
||||||
self.write(eval(expr, d, d))
|
self.write(eval(expr, d, d))
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
except:
|
except Exception:
|
||||||
print(node)
|
print(node)
|
||||||
raise
|
raise
|
||||||
m = escape.search(fmt, i)
|
m = escape.search(fmt, i)
|
||||||
@@ -1962,7 +1976,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
# FIXME figure out how to get these cases to be table driven.
|
# FIXME figure out how to get these cases to be table driven.
|
||||||
# 2. subroutine calls. It the last op is the call and for purposes of printing
|
# 2. subroutine calls. It the last op is the call and for purposes of printing
|
||||||
# we don't need to print anything special there. However it encompases the
|
# we don't need to print anything special there. However it encompasses the
|
||||||
# entire string of the node fn(...)
|
# entire string of the node fn(...)
|
||||||
if startnode.kind == "call":
|
if startnode.kind == "call":
|
||||||
last_node = startnode[-1]
|
last_node = startnode[-1]
|
||||||
@@ -1997,7 +2011,7 @@ def deparse_code(
|
|||||||
showgrammar=False,
|
showgrammar=False,
|
||||||
code_objects={},
|
code_objects={},
|
||||||
compile_mode="exec",
|
compile_mode="exec",
|
||||||
is_pypy=None,
|
is_pypy=IS_PYPY,
|
||||||
walker=FragmentsWalker,
|
walker=FragmentsWalker,
|
||||||
):
|
):
|
||||||
debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar}
|
debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar}
|
||||||
@@ -2050,7 +2064,7 @@ def code_deparse(
|
|||||||
is_pypy = IS_PYPY
|
is_pypy = IS_PYPY
|
||||||
|
|
||||||
# store final output stream for case of error
|
# store final output stream for case of error
|
||||||
scanner = get_scanner(version, is_pypy=is_pypy)
|
scanner = get_scanner(version, is_pypy=is_pypy, show_asm=debug_opts["asm"])
|
||||||
|
|
||||||
show_asm = debug_opts.get("asm", None)
|
show_asm = debug_opts.get("asm", None)
|
||||||
tokens, customize = scanner.ingest(co, code_objects=code_objects, show_asm=show_asm)
|
tokens, customize = scanner.ingest(co, code_objects=code_objects, show_asm=show_asm)
|
||||||
@@ -2066,14 +2080,15 @@ def code_deparse(
|
|||||||
|
|
||||||
# Build Syntax Tree from tokenized and massaged disassembly.
|
# Build Syntax Tree from tokenized and massaged disassembly.
|
||||||
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
|
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
|
||||||
show_ast = debug_opts.get("ast", None)
|
show_tree = debug_opts.get("tree", False)
|
||||||
deparsed = walker(
|
deparsed = walker(
|
||||||
version,
|
version,
|
||||||
scanner,
|
scanner,
|
||||||
showast=show_ast,
|
showast=show_tree,
|
||||||
debug_parser=debug_parser,
|
debug_parser=debug_parser,
|
||||||
compile_mode=compile_mode,
|
compile_mode=compile_mode,
|
||||||
is_pypy=is_pypy,
|
is_pypy=is_pypy,
|
||||||
|
linestarts=linestarts,
|
||||||
)
|
)
|
||||||
|
|
||||||
is_top_level_module = co.co_name == "<module>"
|
is_top_level_module = co.co_name == "<module>"
|
||||||
@@ -2094,7 +2109,7 @@ def code_deparse(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Just when you think we've forgotten about what we
|
# Just when you think we've forgotten about what we
|
||||||
# were supposed to to: Generate source from the Syntax ree!
|
# were supposed to do: Generate source from the Syntax tree!
|
||||||
deparsed.gen_source(deparsed.ast, co.co_name, customize)
|
deparsed.gen_source(deparsed.ast, co.co_name, customize)
|
||||||
|
|
||||||
deparsed.set_pos_info(deparsed.ast, 0, len(deparsed.text))
|
deparsed.set_pos_info(deparsed.ast, 0, len(deparsed.text))
|
||||||
@@ -2149,7 +2164,7 @@ def code_deparse_around_offset(
|
|||||||
assert iscode(co)
|
assert iscode(co)
|
||||||
|
|
||||||
if version is None:
|
if version is None:
|
||||||
version = sys.version_info[:3]
|
version = PYTHON_VERSION_TRIPLE
|
||||||
if is_pypy is None:
|
if is_pypy is None:
|
||||||
is_pypy = IS_PYPY
|
is_pypy = IS_PYPY
|
||||||
|
|
||||||
@@ -2167,7 +2182,7 @@ def code_deparse_around_offset(
|
|||||||
return deparsed
|
return deparsed
|
||||||
|
|
||||||
|
|
||||||
# Deprecated. Here still for compatability
|
# Deprecated. Here still for compatibility
|
||||||
def deparse_code_around_offset(
|
def deparse_code_around_offset(
|
||||||
name,
|
name,
|
||||||
offset,
|
offset,
|
||||||
@@ -2176,7 +2191,7 @@ def deparse_code_around_offset(
|
|||||||
out=StringIO(),
|
out=StringIO(),
|
||||||
showasm=False,
|
showasm=False,
|
||||||
showast=False,
|
showast=False,
|
||||||
showgrammar=False,
|
showgrammar=PARSER_DEFAULT_DEBUG,
|
||||||
is_pypy=False,
|
is_pypy=False,
|
||||||
):
|
):
|
||||||
debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar}
|
debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar}
|
||||||
@@ -2313,6 +2328,5 @@ def deparsed_find(tup, deparsed, code):
|
|||||||
# # deparse_test(get_code_for_fn(FragmentsWalker.fixup_offsets))
|
# # deparse_test(get_code_for_fn(FragmentsWalker.fixup_offsets))
|
||||||
# # deparse_test(get_code_for_fn(FragmentsWalker.n_list))
|
# # deparse_test(get_code_for_fn(FragmentsWalker.n_list))
|
||||||
# print("=" * 30)
|
# print("=" * 30)
|
||||||
# # deparse_test_around(408, 'n_list',
|
# # deparse_test_around(408, 'n_list', get_code_for_fn(FragmentsWalker.n_build_list))
|
||||||
# get_code_for_fn(FragmentsWalker.n_build_list))
|
|
||||||
# # deparse_test(inspect.currentframe().f_code)
|
# # deparse_test(inspect.currentframe().f_code)
|
||||||
|
Reference in New Issue
Block a user