You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Fix up linemap option
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018-2023 Rocky Bernstein <rocky@gnu.org>
|
||||
# Copyright (C) 2018-2024 Rocky Bernstein <rocky@gnu.org>
|
||||
#
|
||||
# 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
|
||||
@@ -35,12 +35,15 @@ from uncompyle6.version import __version__
|
||||
|
||||
|
||||
def _get_outstream(outfile: str) -> Any:
|
||||
dir = os.path.dirname(outfile)
|
||||
"""
|
||||
Return an opened output file descriptor for ``outfile``.
|
||||
"""
|
||||
dir_name = os.path.dirname(outfile)
|
||||
failed_file = outfile + "_failed"
|
||||
if os.path.exists(failed_file):
|
||||
os.remove(failed_file)
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
os.makedirs(dir_name)
|
||||
except OSError:
|
||||
pass
|
||||
return open(outfile, mode="w", encoding="utf-8")
|
||||
@@ -118,13 +121,12 @@ def decompile(
|
||||
if isinstance(mapstream, str):
|
||||
mapstream = _get_outstream(mapstream)
|
||||
|
||||
debug_opts = {"asm": showasm, "tree": showast, "grammar": showgrammar}
|
||||
|
||||
deparsed = deparse_code_with_map(
|
||||
bytecode_version,
|
||||
co,
|
||||
out,
|
||||
showasm,
|
||||
showast,
|
||||
showgrammar,
|
||||
co=co,
|
||||
out=out,
|
||||
version=bytecode_version,
|
||||
code_objects=code_objects,
|
||||
is_pypy=is_pypy,
|
||||
)
|
||||
|
@@ -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
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -75,7 +75,6 @@ from xdis import iscode
|
||||
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
|
||||
|
||||
import uncompyle6.parser as python_parser
|
||||
from uncompyle6 import parser
|
||||
from uncompyle6.parsers.treenode import SyntaxTree
|
||||
from uncompyle6.scanner import Code, Token, get_scanner
|
||||
from uncompyle6.semantics import pysource
|
||||
@@ -89,7 +88,7 @@ from uncompyle6.semantics.consts import (
|
||||
TABLE_DIRECT,
|
||||
escape,
|
||||
)
|
||||
from uncompyle6.semantics.pysource import ParserError, StringIO
|
||||
from uncompyle6.semantics.pysource import DEFAULT_DEBUG_OPTS, ParserError, StringIO
|
||||
from uncompyle6.show import maybe_show_asm, maybe_show_tree
|
||||
|
||||
NodeInfo = namedtuple("NodeInfo", "node start finish")
|
||||
@@ -1118,7 +1117,13 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
n_classdefdeco2 = n_classdef
|
||||
|
||||
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"""
|
||||
|
||||
@@ -1204,7 +1209,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
self.p.insts = self.scanner.insts
|
||||
self.p.offset2inst_index = self.scanner.offset2inst_index
|
||||
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
|
||||
except (python_parser.ParserError, AssertionError) as e:
|
||||
raise ParserError(e, tokens, {})
|
||||
@@ -2065,11 +2070,11 @@ def code_deparse(
|
||||
|
||||
# Build Syntax Tree from tokenized and massaged disassembly.
|
||||
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
|
||||
show_ast = debug_opts.get("ast", None)
|
||||
show_tree = debug_opts.get("tree", False)
|
||||
deparsed = walker(
|
||||
version,
|
||||
scanner,
|
||||
showast=show_ast,
|
||||
showast=show_tree,
|
||||
debug_parser=debug_parser,
|
||||
compile_mode=compile_mode,
|
||||
is_pypy=is_pypy,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018 by Rocky Bernstein
|
||||
# Copyright (c) 2018, 2024 by Rocky Bernstein
|
||||
#
|
||||
# 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
|
||||
@@ -12,96 +12,97 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from uncompyle6.semantics.fragments import FragmentsWalker, code_deparse as fragments_code_deparse
|
||||
from uncompyle6.semantics.pysource import SourceWalker, code_deparse
|
||||
import uncompyle6.semantics.fragments as fragments
|
||||
|
||||
|
||||
# FIXME: does this handle nested code, and lambda properly
|
||||
class LineMapWalker(SourceWalker):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LineMapWalker, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.source_linemap = {}
|
||||
self.current_line_number = 1
|
||||
|
||||
def write(self, *data):
|
||||
"""Augment write routine to keep track of current line"""
|
||||
for l in data:
|
||||
for line in data:
|
||||
## print("XXX write: '%s'" % l)
|
||||
for i in str(l):
|
||||
if i == '\n':
|
||||
for i in str(line):
|
||||
if i == "\n":
|
||||
self.current_line_number += 1
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
return super(LineMapWalker, self).write(*data)
|
||||
return super().write(*data)
|
||||
|
||||
# Note n_expr needs treatment too
|
||||
|
||||
def default(self, node):
|
||||
"""Augment write default routine to record line number changes"""
|
||||
if hasattr(node, 'linestart'):
|
||||
if hasattr(node, "linestart"):
|
||||
if node.linestart:
|
||||
self.source_linemap[self.current_line_number] = node.linestart
|
||||
return super(LineMapWalker, self).default(node)
|
||||
return super().default(node)
|
||||
|
||||
def n_LOAD_CONST(self, node):
|
||||
if hasattr(node, 'linestart'):
|
||||
if hasattr(node, "linestart"):
|
||||
if node.linestart:
|
||||
self.source_linemap[self.current_line_number] = node.linestart
|
||||
return super(LineMapWalker, self).n_LOAD_CONST(node)
|
||||
return super().n_LOAD_CONST(node)
|
||||
|
||||
|
||||
class LineMapFragmentWalker(fragments.FragmentsWalker, LineMapWalker):
|
||||
class LineMapFragmentWalker(LineMapWalker, FragmentsWalker):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LineMapFragmentWalker, self).__init__(*args, **kwargs)
|
||||
self.source_linemap = {}
|
||||
self.current_line_number = 0
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def deparse_code_with_map(*args, **kwargs):
|
||||
"""
|
||||
Like deparse_code but saves line number correspondences.
|
||||
Deprecated. Use code_deparse_with_map
|
||||
"""
|
||||
kwargs['walker'] = LineMapWalker
|
||||
kwargs["walker"] = LineMapWalker
|
||||
return code_deparse(*args, **kwargs)
|
||||
|
||||
|
||||
def code_deparse_with_map(*args, **kwargs):
|
||||
"""
|
||||
Like code_deparse but saves line number correspondences.
|
||||
"""
|
||||
kwargs['walker'] = LineMapWalker
|
||||
kwargs["walker"] = LineMapWalker
|
||||
return code_deparse(*args, **kwargs)
|
||||
|
||||
def deparse_code_with_fragments_and_map(*args, **kwargs):
|
||||
"""
|
||||
Like deparse_code_with_map but saves fragments.
|
||||
Deprecated. Use code_deparse_with_fragments_and_map
|
||||
"""
|
||||
kwargs['walker'] = LineMapFragmentWalker
|
||||
return fragments.deparse_code(*args, **kwargs)
|
||||
|
||||
def code_deparse_with_fragments_and_map(*args, **kwargs):
|
||||
"""
|
||||
Like code_deparse_with_map but saves fragments.
|
||||
"""
|
||||
kwargs['walker'] = LineMapFragmentWalker
|
||||
return fragments.code_deparse(*args, **kwargs)
|
||||
kwargs["walker"] = LineMapFragmentWalker
|
||||
return fragments_code_deparse(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if __name__ == '__main__':
|
||||
def deparse_test(co):
|
||||
"This is a docstring"
|
||||
deparsed = code_deparse_with_map(co)
|
||||
a = 1; b = 2
|
||||
a = 1
|
||||
b = 2
|
||||
print("\n")
|
||||
linemap = [(line_no, deparsed.source_linemap[line_no])
|
||||
for line_no in
|
||||
sorted(deparsed.source_linemap.keys())]
|
||||
linemap = [
|
||||
(line_no, deparsed.source_linemap[line_no])
|
||||
for line_no in sorted(deparsed.source_linemap.keys())
|
||||
]
|
||||
print(linemap)
|
||||
deparsed = code_deparse_with_fragments_and_map(co)
|
||||
print("\n")
|
||||
linemap2 = [(line_no, deparsed.source_linemap[line_no])
|
||||
for line_no in
|
||||
sorted(deparsed.source_linemap.keys())]
|
||||
linemap2 = [
|
||||
(line_no, deparsed.source_linemap[line_no])
|
||||
for line_no in sorted(deparsed.source_linemap.keys())
|
||||
]
|
||||
print(linemap2)
|
||||
# assert linemap == linemap2
|
||||
return
|
||||
|
||||
deparse_test(deparse_test.__code__)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2023 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2024 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -196,6 +196,10 @@ class SourceWalkerError(Exception):
|
||||
|
||||
|
||||
class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
||||
"""
|
||||
Class to traverses a Parse Tree of the bytecode instruction built from parsing to produce some sort of source text.
|
||||
The Parse tree may be turned an Abstract Syntax tree as an intermediate step.
|
||||
"""
|
||||
stacked_params = ("f", "indent", "is_lambda", "_globals")
|
||||
|
||||
def __init__(
|
||||
@@ -245,24 +249,24 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
||||
is_pypy=is_pypy,
|
||||
)
|
||||
|
||||
# Initialize p_lambda on demand
|
||||
self.p_lambda = None
|
||||
|
||||
self.treeTransform = TreeTransform(version=self.version, show_ast=showast)
|
||||
self.ast_errors = []
|
||||
self.currentclass = None
|
||||
self.classes = []
|
||||
self.debug_parser = dict(debug_parser)
|
||||
self.showast = showast
|
||||
# Initialize p_lambda on demand
|
||||
self.line_number = 1
|
||||
self.linemap = {}
|
||||
self.p_lambda = None
|
||||
self.params = params
|
||||
self.param_stack = []
|
||||
self.ERROR = None
|
||||
self.prec = 100
|
||||
self.return_none = False
|
||||
self.mod_globs = set()
|
||||
self.currentclass = None
|
||||
self.classes = []
|
||||
self.showast = showast
|
||||
self.pending_newlines = 0
|
||||
self.linestarts = linestarts
|
||||
self.line_number = 1
|
||||
self.ast_errors = []
|
||||
self.treeTransform = TreeTransform(version=self.version, show_ast=showast)
|
||||
# FIXME: have p.insts update in a better way
|
||||
# modularity is broken here
|
||||
self.insts = scanner.insts
|
||||
@@ -1257,7 +1261,6 @@ def code_deparse(
|
||||
|
||||
assert iscode(co)
|
||||
|
||||
|
||||
if version is None:
|
||||
version = PYTHON_VERSION_TRIPLE
|
||||
|
||||
|
Reference in New Issue
Block a user