Commit b86de8ba authored by Robert Bradshaw's avatar Robert Bradshaw

Some work on cpdef static methods, not complete.

Getting assignment synthesis for the created py_func is troublesome;
it would be nicer if cdef and def functions were truely unified.

Dissallowed for now.
parent ee80d4b8
...@@ -4449,7 +4449,14 @@ class SimpleCallNode(CallNode): ...@@ -4449,7 +4449,14 @@ class SimpleCallNode(CallNode):
self.type = error_type self.type = error_type
return return
if self.self and not self.function.type.is_static_method: if self.function.type.is_static_method:
if self.self and self.self.type.is_extension_type:
# To support this we'd need to pass self to determine whether
# it was overloaded in Python space (possibly via a Cython
# superclass turning a cdef method into a cpdef one).
error(self.pos, "Cannot call a static method on an instance variable.")
args = self.args
elif self.self:
args = [self.self] + self.args args = [self.self] + self.args
else: else:
args = self.args args = self.args
...@@ -4475,7 +4482,6 @@ class SimpleCallNode(CallNode): ...@@ -4475,7 +4482,6 @@ class SimpleCallNode(CallNode):
else: else:
alternatives = overloaded_entry.all_alternatives() alternatives = overloaded_entry.all_alternatives()
print self.function.type, args
entry = PyrexTypes.best_match(args, alternatives, self.pos, env) entry = PyrexTypes.best_match(args, alternatives, self.pos, env)
if not entry: if not entry:
......
...@@ -617,8 +617,6 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -617,8 +617,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
for i, arg_node in enumerate(self.args): for i, arg_node in enumerate(self.args):
name_declarator, type = arg_node.analyse( name_declarator, type = arg_node.analyse(
env, nonempty=nonempty, is_self_arg=(i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives)) env, nonempty=nonempty, is_self_arg=(i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives))
print arg_node
print name_declarator, type, (i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives)
name = name_declarator.name name = name_declarator.name
if name in directive_locals: if name in directive_locals:
type_node = directive_locals[name] type_node = directive_locals[name]
...@@ -797,7 +795,6 @@ class CArgDeclNode(Node): ...@@ -797,7 +795,6 @@ class CArgDeclNode(Node):
is_dynamic = 0 is_dynamic = 0
def analyse(self, env, nonempty = 0, is_self_arg = False): def analyse(self, env, nonempty = 0, is_self_arg = False):
print "is_self_arg", is_self_arg, "type", self.type, "self.base_type", self.base_type, "self.base_type.is_self_arg", self.base_type.is_self_arg
if is_self_arg: if is_self_arg:
self.base_type.is_self_arg = self.is_self_arg = True self.base_type.is_self_arg = self.is_self_arg = True
if self.type is None: if self.type is None:
...@@ -818,7 +815,6 @@ class CArgDeclNode(Node): ...@@ -818,7 +815,6 @@ class CArgDeclNode(Node):
could_be_name = False could_be_name = False
self.base_type.is_arg = True self.base_type.is_arg = True
base_type = self.base_type.analyse(env, could_be_name=could_be_name) base_type = self.base_type.analyse(env, could_be_name=could_be_name)
print "base_type", base_type
if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name: if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name self.declarator.name = self.base_type.arg_name
...@@ -2146,7 +2142,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -2146,7 +2142,7 @@ class CFuncDefNode(FuncDefNode):
# is_const_method whether this is a const method # is_const_method whether this is a const method
# is_static_method whether this is a static method # is_static_method whether this is a static method
child_attrs = ["base_type", "declarator", "body", "py_func"] child_attrs = ["base_type", "declarator", "body", "py_func_stat"]
inline_in_pxd = False inline_in_pxd = False
decorators = None decorators = None
...@@ -2155,6 +2151,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -2155,6 +2151,7 @@ class CFuncDefNode(FuncDefNode):
override = None override = None
template_declaration = None template_declaration = None
is_const_method = False is_const_method = False
py_func_stat = None
def unqualified_name(self): def unqualified_name(self):
return self.entry.name return self.entry.name
...@@ -2170,7 +2167,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -2170,7 +2167,7 @@ class CFuncDefNode(FuncDefNode):
base_type = PyrexTypes.error_type base_type = PyrexTypes.error_type
else: else:
base_type = self.base_type.analyse(env) base_type = self.base_type.analyse(env)
self.is_static_method = 'staticmethod' in env.directives self.is_static_method = 'staticmethod' in env.directives and not env.lookup_here('staticmethod')
# The 2 here is because we need both function and argument names. # The 2 here is because we need both function and argument names.
if isinstance(self.declarator, CFuncDeclaratorNode): if isinstance(self.declarator, CFuncDeclaratorNode):
name_declarator, type = self.declarator.analyse(base_type, env, name_declarator, type = self.declarator.analyse(base_type, env,
...@@ -2185,7 +2182,6 @@ class CFuncDefNode(FuncDefNode): ...@@ -2185,7 +2182,6 @@ class CFuncDefNode(FuncDefNode):
# written here, because the type in the symbol table entry # written here, because the type in the symbol table entry
# may be different if we're overriding a C method inherited # may be different if we're overriding a C method inherited
# from the base type of an extension type. # from the base type of an extension type.
print "type", type
self.type = type self.type = type
type.is_overridable = self.overridable type.is_overridable = self.overridable
declarator = self.declarator declarator = self.declarator
...@@ -2256,8 +2252,17 @@ class CFuncDefNode(FuncDefNode): ...@@ -2256,8 +2252,17 @@ class CFuncDefNode(FuncDefNode):
def declare_cpdef_wrapper(self, env): def declare_cpdef_wrapper(self, env):
if self.overridable: if self.overridable:
if self.is_static_method:
# TODO(robertwb): Finish this up, perhaps via more function refactoring.
error(self.pos, "static cpdef methods not yet supported")
name = self.entry.name name = self.entry.name
py_func_body = self.call_self_node(is_module_scope = env.is_module_scope) py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
if self.is_static_method:
from .ExprNodes import NameNode
decorators = [DecoratorNode(self.pos, decorator=NameNode(self.pos, name='staticmethod'))]
decorators[0].decorator.analyse_types(env)
else:
decorators = []
self.py_func = DefNode(pos = self.pos, self.py_func = DefNode(pos = self.pos,
name = self.entry.name, name = self.entry.name,
args = self.args, args = self.args,
...@@ -2265,9 +2270,12 @@ class CFuncDefNode(FuncDefNode): ...@@ -2265,9 +2270,12 @@ class CFuncDefNode(FuncDefNode):
starstar_arg = None, starstar_arg = None,
doc = self.doc, doc = self.doc,
body = py_func_body, body = py_func_body,
decorators = decorators,
is_wrapper = 1) is_wrapper = 1)
self.py_func.is_module_scope = env.is_module_scope self.py_func.is_module_scope = env.is_module_scope
self.py_func.analyse_declarations(env) self.py_func.analyse_declarations(env)
self.py_func_stat = StatListNode(pos = self.pos, stats = [self.py_func])
self.py_func.type = PyrexTypes.py_object_type
self.entry.as_variable = self.py_func.entry self.entry.as_variable = self.py_func.entry
self.entry.used = self.entry.as_variable.used = True self.entry.used = self.entry.as_variable.used = True
# Reset scope entry the above cfunction # Reset scope entry the above cfunction
...@@ -2298,11 +2306,23 @@ class CFuncDefNode(FuncDefNode): ...@@ -2298,11 +2306,23 @@ class CFuncDefNode(FuncDefNode):
arg_names = [arg.name for arg in args] arg_names = [arg.name for arg in args]
if is_module_scope: if is_module_scope:
cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name) cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name)
call_arg_names = arg_names
skip_dispatch = Options.lookup_module_cpdef
elif self.type.is_static_method:
class_entry = self.entry.scope.parent_type.entry
self_arg = ExprNodes.NameNode(self.pos, name=class_entry.name)
self_arg.entry = class_entry
cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name)
call_arg_names = arg_names
# Calling static c(p)def methods on an instance disallowed.
# TODO(robertwb): Support by passing self to check for override?
skip_dispatch = True
else: else:
self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0]) self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0])
cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name) cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name)
skip_dispatch = not is_module_scope or Options.lookup_module_cpdef call_arg_names = arg_names[1:]
c_call = ExprNodes.SimpleCallNode(self.pos, function=cfunc, args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names[1-is_module_scope:]], wrapper_call=skip_dispatch) skip_dispatch = False
c_call = ExprNodes.SimpleCallNode(self.pos, function=cfunc, args=[ExprNodes.NameNode(self.pos, name=n) for n in call_arg_names], wrapper_call=skip_dispatch)
return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call) return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
def declare_arguments(self, env): def declare_arguments(self, env):
...@@ -2427,6 +2447,11 @@ class CFuncDefNode(FuncDefNode): ...@@ -2427,6 +2447,11 @@ class CFuncDefNode(FuncDefNode):
elif arg.type.is_pyobject and not arg.accept_none: elif arg.type.is_pyobject and not arg.accept_none:
self.generate_arg_none_check(arg, code) self.generate_arg_none_check(arg, code)
def generate_execution_code(self, code):
super(CFuncDefNode, self).generate_execution_code(code)
if self.py_func_stat:
self.py_func_stat.generate_execution_code(code)
def error_value(self): def error_value(self):
if self.return_type.is_pyobject: if self.return_type.is_pyobject:
return "0" return "0"
...@@ -2882,10 +2907,10 @@ class DefNode(FuncDefNode): ...@@ -2882,10 +2907,10 @@ class DefNode(FuncDefNode):
return self return self
def needs_assignment_synthesis(self, env, code=None): def needs_assignment_synthesis(self, env, code=None):
if self.is_wrapper or self.specialized_cpdefs or self.entry.is_fused_specialized:
return False
if self.is_staticmethod: if self.is_staticmethod:
return True return True
if self.is_wrapper or self.specialized_cpdefs or self.entry.is_fused_specialized:
return False
if self.no_assignment_synthesis: if self.no_assignment_synthesis:
return False return False
# Should enable for module level as well, that will require more testing... # Should enable for module level as well, that will require more testing...
......
...@@ -678,9 +678,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -678,9 +678,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
self.parallel_directives = {} self.parallel_directives = {}
def check_directive_scope(self, pos, directive, scope): def check_directive_scope(self, pos, directive, scope):
print 'check_directive_scope', pos, directive, scope
legal_scopes = Options.directive_scopes.get(directive, None) legal_scopes = Options.directive_scopes.get(directive, None)
print legal_scopes
if legal_scopes and scope not in legal_scopes: if legal_scopes and scope not in legal_scopes:
self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive ' self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive '
'is not allowed in %s scope' % (directive, scope))) 'is not allowed in %s scope' % (directive, scope)))
......
...@@ -2315,7 +2315,7 @@ class CFuncType(CType): ...@@ -2315,7 +2315,7 @@ class CFuncType(CType):
# is_strict_signature boolean function refuses to accept coerced arguments # is_strict_signature boolean function refuses to accept coerced arguments
# (used for optimisation overrides) # (used for optimisation overrides)
# is_const_method boolean # is_const_method boolean
# is_static_method boolean # is_static_method boolean
is_cfunction = 1 is_cfunction = 1
original_sig = None original_sig = None
......
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