You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Sync with decompyle3
This commit is contained in:
@@ -210,7 +210,8 @@ class SourceWalkerError(Exception):
|
|||||||
|
|
||||||
class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
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.
|
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.
|
The Parse tree may be turned an Abstract Syntax tree as an intermediate step.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -318,7 +319,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
customize_for_version(self, is_pypy, version)
|
customize_for_version(self, is_pypy, version)
|
||||||
return
|
return
|
||||||
|
|
||||||
def maybe_show_tree(self, ast, phase):
|
def maybe_show_tree(self, tree, phase):
|
||||||
if self.showast.get("before", False):
|
if self.showast.get("before", False):
|
||||||
self.println(
|
self.println(
|
||||||
"""
|
"""
|
||||||
@@ -334,7 +335,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin):
|
|||||||
+ " "
|
+ " "
|
||||||
)
|
)
|
||||||
if self.showast.get(phase, False):
|
if self.showast.get(phase, False):
|
||||||
maybe_show_tree(self, ast)
|
maybe_show_tree(self, tree)
|
||||||
|
|
||||||
def str_with_template(self, ast):
|
def str_with_template(self, ast):
|
||||||
stream = sys.stdout
|
stream = sys.stdout
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2019-2023 by Rocky Bernstein
|
# Copyright (c) 2019-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
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from spark_parser import GenericASTTraversal, GenericASTTraversalPruningException
|
from spark_parser import GenericASTTraversal, GenericASTTraversalPruningException
|
||||||
|
|
||||||
@@ -56,29 +57,34 @@ def is_docstring(node, version, co_consts):
|
|||||||
return node == ASSIGN_DOC_STRING(co_consts[0], doc_load)
|
return node == ASSIGN_DOC_STRING(co_consts[0], doc_load)
|
||||||
|
|
||||||
|
|
||||||
def is_not_docstring(call_stmt_node):
|
def is_not_docstring(call_stmt_node) -> bool:
|
||||||
try:
|
try:
|
||||||
return (
|
return (
|
||||||
call_stmt_node == "call_stmt"
|
call_stmt_node == "call_stmt"
|
||||||
and call_stmt_node[0][0] == "LOAD_STR"
|
and call_stmt_node[0][0] == "LOAD_STR"
|
||||||
and call_stmt_node[1] == "POP_TOP"
|
and call_stmt_node[1] == "POP_TOP"
|
||||||
)
|
)
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class TreeTransform(GenericASTTraversal, object):
|
class TreeTransform(GenericASTTraversal, object):
|
||||||
def __init__(self, version, show_ast=None, is_pypy=False):
|
def __init__(
|
||||||
|
self,
|
||||||
|
version: tuple,
|
||||||
|
is_pypy=False,
|
||||||
|
show_ast: Optional[dict] = None,
|
||||||
|
):
|
||||||
self.version = version
|
self.version = version
|
||||||
self.showast = show_ast
|
self.showast = show_ast
|
||||||
self.is_pypy = is_pypy
|
self.is_pypy = is_pypy
|
||||||
return
|
return
|
||||||
|
|
||||||
def maybe_show_tree(self, ast):
|
def maybe_show_tree(self, tree):
|
||||||
if isinstance(self.showast, dict) and (
|
if isinstance(self.showast, dict) and (
|
||||||
self.showast.get("before") or self.showast.get("after")
|
self.showast.get("before") or self.showast.get("after")
|
||||||
):
|
):
|
||||||
maybe_show_tree(self, ast)
|
maybe_show_tree(self, tree)
|
||||||
|
|
||||||
def preorder(self, node=None):
|
def preorder(self, node=None):
|
||||||
"""Walk the tree in roughly 'preorder' (a bit of a lie explained below).
|
"""Walk the tree in roughly 'preorder' (a bit of a lie explained below).
|
||||||
@@ -122,6 +128,7 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
|
|
||||||
mkfunc_pattr = node[-1].pattr
|
mkfunc_pattr = node[-1].pattr
|
||||||
if isinstance(mkfunc_pattr, tuple):
|
if isinstance(mkfunc_pattr, tuple):
|
||||||
|
assert isinstance(mkfunc_pattr, tuple)
|
||||||
assert len(mkfunc_pattr) == 4 and isinstance(mkfunc_pattr, int)
|
assert len(mkfunc_pattr) == 4 and isinstance(mkfunc_pattr, int)
|
||||||
|
|
||||||
if len(code.co_consts) > 0 and isinstance(code.co_consts[0], str):
|
if len(code.co_consts) > 0 and isinstance(code.co_consts[0], str):
|
||||||
@@ -216,6 +223,7 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
return node
|
return node
|
||||||
if isinstance(call[1], SyntaxTree):
|
if isinstance(call[1], SyntaxTree):
|
||||||
expr = call[1][0]
|
expr = call[1][0]
|
||||||
|
assert_expr.transformed_by = "n_ifstmt"
|
||||||
node = SyntaxTree(
|
node = SyntaxTree(
|
||||||
kind,
|
kind,
|
||||||
[
|
[
|
||||||
@@ -225,8 +233,8 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
expr,
|
expr,
|
||||||
RAISE_VARARGS_1,
|
RAISE_VARARGS_1,
|
||||||
],
|
],
|
||||||
|
transformed_by="n_ifstmt",
|
||||||
)
|
)
|
||||||
node.transformed_by = "n_ifstmt"
|
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@@ -254,9 +262,10 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
|
|
||||||
LOAD_ASSERT = expr[0]
|
LOAD_ASSERT = expr[0]
|
||||||
node = SyntaxTree(
|
node = SyntaxTree(
|
||||||
kind, [assert_expr, jump_cond, LOAD_ASSERT, RAISE_VARARGS_1]
|
kind,
|
||||||
|
[assert_expr, jump_cond, LOAD_ASSERT, RAISE_VARARGS_1],
|
||||||
|
transformed_by="n_ifstmt",
|
||||||
)
|
)
|
||||||
node.transformed_by = ("n_ifstmt",)
|
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
return node
|
return node
|
||||||
@@ -416,6 +425,12 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
list_for_node.transformed_by = ("n_list_for",)
|
list_for_node.transformed_by = ("n_list_for",)
|
||||||
return list_for_node
|
return list_for_node
|
||||||
|
|
||||||
|
def n_negated_testtrue(self, node):
|
||||||
|
assert node[0] == "testtrue"
|
||||||
|
test_node = node[0][0]
|
||||||
|
test_node.transformed_by = "n_negated_testtrue"
|
||||||
|
return test_node
|
||||||
|
|
||||||
def n_stmts(self, node):
|
def n_stmts(self, node):
|
||||||
if node.first_child() == "SETUP_ANNOTATIONS":
|
if node.first_child() == "SETUP_ANNOTATIONS":
|
||||||
prev = node[0][0]
|
prev = node[0][0]
|
||||||
@@ -448,26 +463,28 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
node = self.preorder(node)
|
node = self.preorder(node)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def transform(self, ast, code):
|
def transform(self, parse_tree: GenericASTTraversal, code) -> GenericASTTraversal:
|
||||||
self.maybe_show_tree(ast)
|
self.maybe_show_tree(parse_tree)
|
||||||
self.ast = copy(ast)
|
self.ast = copy(parse_tree)
|
||||||
|
del parse_tree
|
||||||
self.ast = self.traverse(self.ast, is_lambda=False)
|
self.ast = self.traverse(self.ast, is_lambda=False)
|
||||||
|
n = len(self.ast)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Disambiguate a string (expression) which appears as a "call_stmt" at
|
# Disambiguate a string (expression) which appears as a "call_stmt" at
|
||||||
# the beginning of a function versus a docstring. Seems pretty academic,
|
# the beginning of a function versus a docstring. Seems pretty academic,
|
||||||
# but this is Python.
|
# but this is Python.
|
||||||
call_stmt = ast[0][0]
|
call_stmt = self.ast[0][0]
|
||||||
if is_not_docstring(call_stmt):
|
if is_not_docstring(call_stmt):
|
||||||
call_stmt.kind = "string_at_beginning"
|
call_stmt.kind = "string_at_beginning"
|
||||||
call_stmt.transformed_by = "transform"
|
call_stmt.transformed_by = "transform"
|
||||||
pass
|
pass
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for i in range(len(self.ast)):
|
for i in range(n):
|
||||||
sstmt = ast[i]
|
sstmt = self.ast[i]
|
||||||
if len(sstmt) == 1 and sstmt == "sstmt":
|
if len(sstmt) == 1 and sstmt == "sstmt":
|
||||||
self.ast[i] = self.ast[i][0]
|
self.ast[i] = self.ast[i][0]
|
||||||
|
|
||||||
@@ -493,7 +510,7 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
if self.ast[-1] == RETURN_NONE:
|
if self.ast[-1] == RETURN_NONE:
|
||||||
self.ast.pop() # remove last node
|
self.ast.pop() # remove last node
|
||||||
# todo: if empty, add 'pass'
|
# todo: if empty, add 'pass'
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return self.ast
|
return self.ast
|
||||||
|
Reference in New Issue
Block a user