You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Handle Python 3.3 > dotted class names
This commit is contained in:
BIN
test/bytecode_3.4/05_class.pyc
Normal file
BIN
test/bytecode_3.4/05_class.pyc
Normal file
Binary file not shown.
13
test/simple_source/def/05_class.py
Normal file
13
test/simple_source/def/05_class.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# Tests:
|
||||
# importstmt ::= LOAD_CONST LOAD_CONST import_as
|
||||
# import_as ::= IMPORT_NAME designator
|
||||
|
||||
# Since Python 3.3:
|
||||
# classdef ::= buildclass designator
|
||||
# designator ::= STORE_NAME
|
||||
# buildclass ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST expr CALL_FUNCTION_3
|
||||
# mkfunc ::= LOAD_CONST LOAD_CONST MAKE_FUNCTION_0
|
||||
|
||||
import io
|
||||
class BZ2File(io.BufferedIOBase):
|
||||
pass
|
@@ -680,7 +680,11 @@ class Python3Parser(PythonParser):
|
||||
def custom_buildclass_rule(self, opname, i, token, tokens, customize):
|
||||
"""
|
||||
Python >= 3.3:
|
||||
buildclass ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST LOAD_CLASSNAME CALL_FUNCTION_3
|
||||
buildclass ::= LOAD_BUILD_CLASS mkfunc
|
||||
LOAD_CLASSNAME expr CALL_FUNCTION_3
|
||||
or
|
||||
buildclass ::= LOAD_BUILD_CLASS mkfunc
|
||||
LOAD_CONST CALL_FUNCTION_3
|
||||
Python < 3.3
|
||||
buildclass ::= LOAD_BUILD_CLASS LOAD_CONST MAKE_FUNCTION_0 LOAD_CONST
|
||||
CALL_FUNCTION_n
|
||||
@@ -693,28 +697,29 @@ class Python3Parser(PythonParser):
|
||||
break
|
||||
pass
|
||||
assert i < len(tokens)
|
||||
if self.version >= 3.3:
|
||||
assert tokens[i+1].type == 'LOAD_CONST'
|
||||
load_check = 'LOAD_NAME'
|
||||
else:
|
||||
load_check = 'LOAD_CONST'
|
||||
assert tokens[i+1].type == 'LOAD_CONST'
|
||||
# find load names
|
||||
have_loadname = False
|
||||
for i in range(i+1, len(tokens)):
|
||||
if tokens[i].type == load_check:
|
||||
tokens[i].type = 'LOAD_CLASSNAME'
|
||||
if tokens[i].type == 'LOAD_NAME':
|
||||
if tokens[i+1].type != 'LOAD_ATTR':
|
||||
tokens[i].type = 'LOAD_CLASSNAME'
|
||||
have_loadname = True
|
||||
break
|
||||
if tokens[i].type in 'CALL_FUNCTION':
|
||||
break
|
||||
pass
|
||||
assert i < len(tokens)
|
||||
have_load_attr = False
|
||||
if have_loadname:
|
||||
j = 1
|
||||
for i in range(i+1, len(tokens)):
|
||||
if tokens[i].type in 'CALL_FUNCTION':
|
||||
if tokens[i].type in ['CALL_FUNCTION', 'LOAD_ATTR']:
|
||||
if tokens[i].type == 'LOAD_ATTR':
|
||||
have_load_attr = True
|
||||
break
|
||||
assert tokens[i].type == 'LOAD_NAME'
|
||||
assert tokens[i].type == 'LOAD_NAME', \
|
||||
'Expecting LOAD_NAME after CALL_FUNCTION'
|
||||
tokens[i].type = 'LOAD_CLASSNAME'
|
||||
j += 1
|
||||
pass
|
||||
@@ -724,9 +729,13 @@ class Python3Parser(PythonParser):
|
||||
load_names = ''
|
||||
# customize CALL_FUNCTION
|
||||
if self.version >= 3.3:
|
||||
call_function = 'CALL_FUNCTION_%d' % (j + 2)
|
||||
rule = ("buildclass ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST %s%s" %
|
||||
(load_names, call_function))
|
||||
if not have_load_attr:
|
||||
call_function = 'CALL_FUNCTION_%d' % (j + 2)
|
||||
rule = ("buildclass ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST "
|
||||
"%s%s" % (load_names, call_function))
|
||||
else:
|
||||
rule = ("buildclass ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST expr "
|
||||
"CALL_FUNCTION_3")
|
||||
else:
|
||||
call_function = 'CALL_FUNCTION_%d' % (j + 1)
|
||||
rule = ("buildclass ::= LOAD_BUILD_CLASS mkfunc %s%s" %
|
||||
|
@@ -588,21 +588,23 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
cclass = self.currentclass
|
||||
|
||||
if self.version > 3.0:
|
||||
buildclass = node[1]
|
||||
build_list = node[0]
|
||||
subclass = build_list[1][0].attr
|
||||
currentclass = node[1][0].pattr
|
||||
buildclass = node[0]
|
||||
subclass = buildclass[1][0].attr
|
||||
subclass_info = node[0]
|
||||
else:
|
||||
buildclass = node[0]
|
||||
build_list = buildclass[1][0]
|
||||
subclass = buildclass[-3][0].attr
|
||||
currentclass = buildclass[0].pattr
|
||||
|
||||
self.write('\n\n')
|
||||
self.currentclass = str(buildclass[0].pattr)
|
||||
self.currentclass = str(currentclass)
|
||||
start = len(self.f.getvalue())
|
||||
self.write(self.indent, 'class ', self.currentclass)
|
||||
|
||||
if self.version > 3.0:
|
||||
self.print_super_classes3(build_list)
|
||||
self.print_super_classes3(subclass_info)
|
||||
else:
|
||||
self.print_super_classes(build_list)
|
||||
self.print_(':')
|
||||
@@ -888,7 +890,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
n = len(node)-1
|
||||
assert node[n].type.startswith('CALL_FUNCTION')
|
||||
for i in range(n-1, 0, -1):
|
||||
if node[i].type != 'LOAD_CLASSNAME':
|
||||
if not node[i].type in ['expr', 'LOAD_CLASSNAME']:
|
||||
break
|
||||
pass
|
||||
|
||||
|
@@ -1072,20 +1072,22 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
cclass = self.currentclass
|
||||
|
||||
if self.version > 3.0:
|
||||
buildclass = node[1]
|
||||
build_list = node[0]
|
||||
subclass = build_list[1][0].attr
|
||||
currentclass = node[1][0].pattr
|
||||
buildclass = node[0]
|
||||
subclass = buildclass[1][0].attr
|
||||
subclass_info = node[0]
|
||||
else:
|
||||
buildclass = node[0]
|
||||
build_list = buildclass[1][0]
|
||||
subclass = buildclass[-3][0].attr
|
||||
currentclass = buildclass[0].pattr
|
||||
|
||||
self.write('\n\n')
|
||||
self.currentclass = str(buildclass[0].pattr)
|
||||
self.currentclass = str(currentclass)
|
||||
self.write(self.indent, 'class ', self.currentclass)
|
||||
|
||||
if self.version > 3.0:
|
||||
self.print_super_classes3(build_list)
|
||||
self.print_super_classes3(subclass_info)
|
||||
else:
|
||||
self.print_super_classes(build_list)
|
||||
self.print_(':')
|
||||
@@ -1125,8 +1127,9 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
# as a custom rule
|
||||
n = len(node)-1
|
||||
assert node[n].type.startswith('CALL_FUNCTION')
|
||||
|
||||
for i in range(n-1, 0, -1):
|
||||
if node[i].type != 'LOAD_CLASSNAME':
|
||||
if not node[i].type in ['expr', 'LOAD_CLASSNAME']:
|
||||
break
|
||||
pass
|
||||
|
||||
|
Reference in New Issue
Block a user