Specialize "classdef" nonterminal for 3.6+

This commit is contained in:
rocky
2020-01-21 04:56:11 -05:00
parent 67c37f1a03
commit f4e6382cc1
3 changed files with 118 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2018-2019 by Rocky Bernstein
# Copyright (c) 2018-2020 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
@@ -188,6 +188,10 @@ def customize_for_version3(self, version):
self.listcomp_closure3 = listcomp_closure3
def n_classdef3(node):
"""Handle "classdef" nonterminal for 3.0 >= version 3.0 <= 3.5
"""
assert 3.0 <= self.version <= 3.5
# class definition ('class X(A,B,C):')
cclass = self.currentclass
@@ -200,34 +204,15 @@ def customize_for_version3(self, version):
# * subclass_code - the code for the subclass body
subclass_info = None
if node == "classdefdeco2":
if self.version >= 3.6 and isinstance(node[1][1].attr, str):
class_name = node[1][1].attr
elif self.version <= 3.3:
if self.version <= 3.3:
class_name = node[2][0].attr
else:
class_name = node[1][2].attr
build_class = node
else:
build_class = node[0]
if self.version >= 3.6:
if build_class == "build_class_kw":
mkfunc = build_class[1]
assert mkfunc == "mkfunc"
subclass_info = build_class
if hasattr(mkfunc[0], "attr") and iscode(mkfunc[0].attr):
subclass_code = mkfunc[0].attr
else:
assert mkfunc[0] == "load_closure"
subclass_code = mkfunc[1].attr
assert iscode(subclass_code)
if build_class[1][0] == "load_closure":
code_node = build_class[1][1]
else:
code_node = build_class[1][0]
class_name = code_node.attr.co_name
else:
class_name = node[1][0].attr
build_class = node[0]
class_name = node[1][0].attr
build_class = node[0]
assert "mkfunc" == build_class[1]
mkfunc = build_class[1]
@@ -272,9 +257,6 @@ def customize_for_version3(self, version):
subclass_info = build_class[2]
else:
raise "Internal Error n_classdef: cannot superclass name"
elif self.version >= 3.6 and node == "classdefdeco2":
subclass_info = node
subclass_code = build_class[1][0].attr
elif not subclass_info:
if mkfunc[0] in ("no_kwargs", "kwargs"):
subclass_code = mkfunc[1].attr

View File

@@ -15,6 +15,7 @@
"""Isolate Python 3.6 version-specific semantic actions here.
"""
from xdis.code import iscode
from spark_parser.ast import GenericASTTraversalPruningException
from uncompyle6.scanners.tok import Token
from uncompyle6.semantics.helper import flatten_list, escape_string, strip_quotes
@@ -132,6 +133,112 @@ def customize_for_version36(self, version):
self.n_build_map_unpack_with_call = build_unpack_map_with_call
def n_classdef36(node):
# class definition ('class X(A,B,C):')
cclass = self.currentclass
# Pick out various needed bits of information
# * class_name - the name of the class
# * subclass_info - the parameters to the class e.g.
# class Foo(bar, baz)
# ----------
# * subclass_code - the code for the subclass body
subclass_info = None
if node == "classdefdeco2":
if isinstance(node[1][1].attr, str):
class_name = node[1][1].attr
else:
class_name = node[1][2].attr
build_class = node
else:
build_class = node[0]
if build_class == "build_class_kw":
mkfunc = build_class[1]
assert mkfunc == "mkfunc"
subclass_info = build_class
if hasattr(mkfunc[0], "attr") and iscode(mkfunc[0].attr):
subclass_code = mkfunc[0].attr
else:
assert mkfunc[0] == "load_closure"
subclass_code = mkfunc[1].attr
assert iscode(subclass_code)
if build_class[1][0] == "load_closure":
code_node = build_class[1][1]
else:
code_node = build_class[1][0]
class_name = code_node.attr.co_name
assert "mkfunc" == build_class[1]
mkfunc = build_class[1]
if mkfunc[0] in ("kwargs", "no_kwargs"):
for n in mkfunc:
if hasattr(n, "attr") and iscode(n.attr):
subclass_code = n.attr
break
pass
if node == "classdefdeco2":
subclass_info = node
else:
subclass_info = node[0]
elif build_class[1][0] == "load_closure":
# Python 3 with closures not functions
load_closure = build_class[1]
if hasattr(load_closure[-3], "attr"):
# Python 3.3 classes with closures work like this.
# Note have to test before 3.2 case because
# index -2 also has an attr.
subclass_code = load_closure[-3].attr
elif hasattr(load_closure[-2], "attr"):
# Python 3.2 works like this
subclass_code = load_closure[-2].attr
else:
raise "Internal Error n_classdef: cannot find class body"
if hasattr(build_class[3], "__len__"):
if not subclass_info:
subclass_info = build_class[3]
elif hasattr(build_class[2], "__len__"):
subclass_info = build_class[2]
else:
raise "Internal Error n_classdef: cannot superclass name"
elif node == "classdefdeco2":
subclass_info = node
subclass_code = build_class[1][0].attr
elif not subclass_info:
if mkfunc[0] in ("no_kwargs", "kwargs"):
subclass_code = mkfunc[1].attr
else:
subclass_code = mkfunc[0].attr
if node == "classdefdeco2":
subclass_info = node
else:
subclass_info = node[0]
if node == "classdefdeco2":
self.write("\n")
else:
self.write("\n\n")
self.currentclass = str(class_name)
self.write(self.indent, "class ", self.currentclass)
self.print_super_classes3(subclass_info)
self.println(":")
# class body
self.indent_more()
self.build_class(subclass_code)
self.indent_less()
self.currentclass = cclass
if len(self.param_stack) > 1:
self.write("\n\n")
else:
self.write("\n\n\n")
self.prune()
self.n_classdef36 = n_classdef36
def call_ex_kw(node):
"""Handle CALL_FUNCTION_EX 1 (have KW) but with
BUILD_MAP_UNPACK_WITH_CALL"""

View File

@@ -1410,7 +1410,9 @@ class SourceWalker(GenericASTTraversal, object):
def n_classdef(self, node):
if self.version >= 3.0:
if self.version >= 3.6:
self.n_classdef36(node)
elif self.version >= 3.0:
self.n_classdef3(node)
# class definition ('class X(A,B,C):')