Commit 9831142c authored by Stefan Behnel's avatar Stefan Behnel

merge DecoratorTransform and PropertyTransform

parent ac48e447
...@@ -1270,12 +1270,12 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -1270,12 +1270,12 @@ class WithTransform(CythonTransform, SkipDeclarations):
return node return node
class PropertyTransform(ScopeTrackingTransform): class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations):
""" """
This pass transforms Python-style decorator properties into a Transforms method decorators in cdef classes into nested calls or properties.
PropertyNode with up to the three getter, setter and deleter
DefNode.
Python-style decorator properties are transformed into a PropertyNode
with up to the three getter, setter and deleter DefNodes.
The functional style isn't supported yet. The functional style isn't supported yet.
""" """
_properties = None _properties = None
...@@ -1295,9 +1295,12 @@ class PropertyTransform(ScopeTrackingTransform): ...@@ -1295,9 +1295,12 @@ class PropertyTransform(ScopeTrackingTransform):
return node return node
def visit_DefNode(self, node): def visit_DefNode(self, node):
self.visitchildren(node) scope_type = self.scope_type
if self.scope_type != 'cclass' or not node.decorators: node = self.visit_FuncDefNode(node)
if scope_type != 'cclass' or not node.decorators:
return node return node
# transform @property decorators
properties = self._properties[-1] properties = self._properties[-1]
for decorator_node in node.decorators[::-1]: for decorator_node in node.decorators[::-1]:
decorator = decorator_node.decorator decorator = decorator_node.decorator
...@@ -1326,16 +1329,20 @@ class PropertyTransform(ScopeTrackingTransform): ...@@ -1326,16 +1329,20 @@ class PropertyTransform(ScopeTrackingTransform):
if len(node.decorators) > 1: if len(node.decorators) > 1:
return self._reject_decorated_property(node, decorator_node) return self._reject_decorated_property(node, decorator_node)
return self._add_to_property(properties, node, handler_name, decorator_node) return self._add_to_property(properties, node, handler_name, decorator_node)
return node
def _reject_decorated_property(self, node, decorator_node): # transform normal decorators
return self._chain_decorators(node, node.decorators, node.name)
@staticmethod
def _reject_decorated_property(node, decorator_node):
# restrict transformation to outermost decorator as wrapped properties will probably not work # restrict transformation to outermost decorator as wrapped properties will probably not work
for deco in node.decorators: for deco in node.decorators:
if deco != decorator_node: if deco != decorator_node:
error(deco.pos, "Property methods with additional decorators are not supported") error(deco.pos, "Property methods with additional decorators are not supported")
return node return node
def _add_to_property(self, properties, node, name, decorator): @staticmethod
def _add_to_property(properties, node, name, decorator):
prop = properties[node.name] prop = properties[node.name]
node.name = name node.name = name
node.decorators.remove(decorator) node.decorators.remove(decorator)
...@@ -1348,39 +1355,28 @@ class PropertyTransform(ScopeTrackingTransform): ...@@ -1348,39 +1355,28 @@ class PropertyTransform(ScopeTrackingTransform):
stats.append(node) stats.append(node)
return [] return []
@staticmethod
def _chain_decorators(node, decorators, name):
"""
Decorators are applied directly in DefNode and PyClassDefNode to avoid
reassignments to the function/class name - except for cdef class methods.
For those, the reassignment is required as methods are originally
defined in the PyMethodDef struct.
class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations): The IndirectionNode allows DefNode to override the decorator.
"""Originally, this was the only place where decorators were """
transformed into the corresponding calling code. Now, this is decorator_result = ExprNodes.NameNode(node.pos, name=name)
done directly in DefNode and PyClassDefNode to avoid reassignments
to the function/class name - except for cdef class methods. For
those, the reassignment is required as methods are originally
defined in the PyMethodDef struct.
The IndirectionNode allows DefNode to override the decorator
"""
def visit_DefNode(self, func_node):
scope_type = self.scope_type
func_node = self.visit_FuncDefNode(func_node)
if scope_type != 'cclass' or not func_node.decorators:
return func_node
return self.handle_decorators(func_node, func_node.decorators,
func_node.name)
def handle_decorators(self, node, decorators, name):
decorator_result = ExprNodes.NameNode(node.pos, name = name)
for decorator in decorators[::-1]: for decorator in decorators[::-1]:
decorator_result = ExprNodes.SimpleCallNode( decorator_result = ExprNodes.SimpleCallNode(
decorator.pos, decorator.pos,
function = decorator.decorator, function=decorator.decorator,
args = [decorator_result]) args=[decorator_result])
name_node = ExprNodes.NameNode(node.pos, name = name) name_node = ExprNodes.NameNode(node.pos, name=name)
reassignment = Nodes.SingleAssignmentNode( reassignment = Nodes.SingleAssignmentNode(
node.pos, node.pos,
lhs = name_node, lhs=name_node,
rhs = decorator_result) rhs=decorator_result)
reassignment = Nodes.IndirectionNode([reassignment]) reassignment = Nodes.IndirectionNode([reassignment])
node.decorator_indirection = reassignment node.decorator_indirection = reassignment
......
...@@ -171,7 +171,7 @@ def create_pipeline(context, mode, exclude_classes=()): ...@@ -171,7 +171,7 @@ def create_pipeline(context, mode, exclude_classes=()):
from .ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform from .ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from .ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods from .ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from .ParseTreeTransforms import ExpandInplaceOperators, ParallelRangeTransform from .ParseTreeTransforms import ExpandInplaceOperators, ParallelRangeTransform
from .ParseTreeTransforms import CalculateQualifiedNamesTransform, PropertyTransform from .ParseTreeTransforms import CalculateQualifiedNamesTransform
from .TypeInference import MarkParallelAssignments, MarkOverflowingArithmetic from .TypeInference import MarkParallelAssignments, MarkOverflowingArithmetic
from .ParseTreeTransforms import AdjustDefByDirectives, AlignFunctionDefinitions from .ParseTreeTransforms import AdjustDefByDirectives, AlignFunctionDefinitions
from .ParseTreeTransforms import RemoveUnreachableCode, GilCheck from .ParseTreeTransforms import RemoveUnreachableCode, GilCheck
...@@ -216,7 +216,6 @@ def create_pipeline(context, mode, exclude_classes=()): ...@@ -216,7 +216,6 @@ def create_pipeline(context, mode, exclude_classes=()):
RemoveUnreachableCode(context), RemoveUnreachableCode(context),
ConstantFolding(), ConstantFolding(),
FlattenInListTransform(), FlattenInListTransform(),
PropertyTransform(context),
DecoratorTransform(context), DecoratorTransform(context),
ForwardDeclareTypes(context), ForwardDeclareTypes(context),
AnalyseDeclarationsTransform(context), AnalyseDeclarationsTransform(context),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment