diff options
author | mattip <matti.picus@gmail.com> | 2018-11-13 17:51:40 -0800 |
---|---|---|
committer | mattip <matti.picus@gmail.com> | 2018-11-13 17:51:40 -0800 |
commit | a6ec7fb9a6350611394a8955096df7f81238af5d (patch) | |
tree | 2e4f616535a48ff18c3aeab07496b9278b9f1b4a /Cython/Compiler | |
parent | fdddf34e099e8e8ede7c67ccf7ac3f09b4844d7c (diff) | |
download | cython-a6ec7fb9a6350611394a8955096df7f81238af5d.tar.gz |
ENH: handle c-level property decorator to produce a cfunc call
Diffstat (limited to 'Cython/Compiler')
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 11 | ||||
-rw-r--r-- | Cython/Compiler/Nodes.py | 7 | ||||
-rw-r--r-- | Cython/Compiler/ParseTreeTransforms.py | 17 | ||||
-rw-r--r-- | Cython/Compiler/Symtab.py | 25 |
4 files changed, 41 insertions, 19 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 2c7e025b8..612996503 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -6976,7 +6976,10 @@ class AttributeNode(ExprNode): self.obj = self.obj.analyse_types(env) self.analyse_attribute(env) if self.entry and self.entry.is_cmethod and not self.is_called: -# error(self.pos, "C method can only be called") + # It must be a property method. This should be done at a different level?? + self.is_called = 1 + self.op = '' + self.result_ctype = self.type.return_type pass ## Reference to C array turns into pointer to first element. #while self.type.is_array: @@ -7146,6 +7149,8 @@ class AttributeNode(ExprNode): obj_code = obj.result_as(obj.type) #print "...obj_code =", obj_code ### if self.entry and self.entry.is_cmethod: + if getattr(self.entry.type, 'is_cgetter', False): + return "%s(%s)" %(self.entry.func_cname, obj_code) if obj.type.is_extension_type and not self.entry.is_builtin_cmethod: if self.entry.final_func_cname: return self.entry.final_func_cname @@ -11223,6 +11228,10 @@ class NumBinopNode(BinopNode): self.operand2 = self.operand2.coerce_to(self.type, env) def compute_c_result_type(self, type1, type2): + if type1.is_cfunction and type1.is_cgetter: + type1 = type1.return_type + if type2.is_cfunction and type2.is_cgetter: + type2 = type2.return_type if self.c_types_okay(type1, type2): widest_type = PyrexTypes.widest_numeric_type(type1, type2) if widest_type is PyrexTypes.c_bint_type: diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index a1e390218..bbf0c9073 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -2422,11 +2422,16 @@ class CFuncDefNode(FuncDefNode): type.is_const_method = self.is_const_method type.is_static_method = self.is_static_method + property = False + if self.decorators: + for _node in self.decorators: + if _node.decorator.is_name and _node.decorator.name == 'property': + property = True self.entry = env.declare_cfunction( name, type, self.pos, cname=cname, visibility=self.visibility, api=self.api, defining=self.body is not None, modifiers=self.modifiers, - overridable=self.overridable) + overridable=self.overridable, property=property) self.entry.inline_func_in_pxd = self.inline_in_pxd self.return_type = type.return_type if self.return_type.is_array and self.visibility != 'extern': diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index aa5486631..85deda5d1 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -2243,21 +2243,20 @@ class ReplacePropertyNode(CythonTransform): def visit_CFuncDefNode(self, node): if not node.decorators: return node - - # transform @property decorators + # transform @property decorators on ctypedef class functions for decorator_node in node.decorators[::-1]: decorator = decorator_node.decorator if decorator.is_name and decorator.name == 'property': if len(node.decorators) > 1: return self._reject_decorated_property(node, decorator_node) - name = node.declarator.base.name - node.name = name #EncodedString('__get__') - newstats = node.body.analyse_expressions(node.local_scope) - newnode = newstats.stats[0].value - newnode.name = name + # Mark the node as a cgetter + node.type.is_cgetter = True + # Add a func_cname to be output instead of the attribute + node.entry.func_cname = node.body.stats[0].value.function.name + # done - remove the decorator node node.decorators.remove(decorator_node) - return [newnode] - # XXX still need to update everywhere that used the old node + return [node] + class FindInvalidUseOfFusedTypes(CythonTransform): diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index e9606b58d..504783b33 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -752,7 +752,8 @@ class Scope(object): def declare_cfunction(self, name, type, pos, cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + defining=0, modifiers=(), utility_code=None, + overridable=False, property=False): # Add an entry for a C function. if not cname: if visibility != 'private' or api: @@ -829,7 +830,8 @@ class Scope(object): type.entry = entry return entry - def add_cfunction(self, name, type, pos, cname, visibility, modifiers, inherited=False): + def add_cfunction(self, name, type, pos, cname, visibility, modifiers, + inherited=False, property=False): # Add a C function entry without giving it a func_cname. entry = self.declare(name, cname, type, pos, visibility) entry.is_cfunction = 1 @@ -837,6 +839,8 @@ class Scope(object): entry.func_modifiers = modifiers if inherited or type.is_fused: self.cfunc_entries.append(entry) + elif property: + self.property_entries.append(entry) else: # For backwards compatibility reasons, we must keep all non-fused methods # before all fused methods, but separately for each type. @@ -1435,7 +1439,8 @@ class ModuleScope(Scope): def declare_cfunction(self, name, type, pos, cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + defining=0, modifiers=(), utility_code=None, + overridable=False, property=False): if not defining and 'inline' in modifiers: # TODO(github/1736): Make this an error. warning(pos, "Declarations should not be declared inline.", 1) @@ -1459,7 +1464,7 @@ class ModuleScope(Scope): self, name, type, pos, cname=cname, visibility=visibility, api=api, in_pxd=in_pxd, defining=defining, modifiers=modifiers, utility_code=utility_code, - overridable=overridable) + overridable=overridable, property=property) return entry def declare_global(self, name, pos): @@ -2214,7 +2219,8 @@ class CClassScope(ClassScope): def declare_cfunction(self, name, type, pos, cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + defining=0, modifiers=(), utility_code=None, + overridable=False, property=False): if get_special_method_signature(name) and not self.parent_type.is_builtin_type: error(pos, "Special methods must be declared with 'def', not 'cdef'") args = type.args @@ -2258,7 +2264,8 @@ class CClassScope(ClassScope): error(pos, "C method '%s' not previously declared in definition part of" " extension type '%s'" % (name, self.class_name)) - entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) + entry = self.add_cfunction(name, type, pos, cname, visibility, + modifiers, property=property) if defining: entry.func_cname = self.mangle(Naming.func_prefix, name) entry.utility_code = utility_code @@ -2274,11 +2281,13 @@ class CClassScope(ClassScope): return entry - def add_cfunction(self, name, type, pos, cname, visibility, modifiers, inherited=False): + def add_cfunction(self, name, type, pos, cname, visibility, modifiers, + inherited=False, property=False): # Add a cfunction entry without giving it a func_cname. prev_entry = self.lookup_here(name) entry = ClassScope.add_cfunction(self, name, type, pos, cname, - visibility, modifiers, inherited=inherited) + visibility, modifiers, + inherited=inherited, property=property) entry.is_cmethod = 1 entry.prev_entry = prev_entry return entry |