overridable = 0
optional_arg_count = 0
- def analyse(self, return_type, env, nonempty = 0):
+ def analyse(self, return_type, env, nonempty = 0, directive_locals = {}):
if nonempty:
nonempty -= 1
func_type_args = []
name_declarator, type = arg_node.analyse(env, nonempty = nonempty,
is_self_arg = (i == 0 and env.is_c_class_scope))
name = name_declarator.name
+ if name in directive_locals:
+ type_node = directive_locals[name]
+ other_type = type_node.analyse_as_type(env)
+ if other_type is None:
+ error(type_node.pos, "Not a type")
+ elif (type is not PyrexTypes.py_object_type
+ and not type.same_as(other_type)):
+ error(self.base.pos, "Signature does not agree with previous declaration")
+ error(type_node.pos, "Previous declaration here")
+ else:
+ type = other_type
if name_declarator.cname:
error(self.pos,
"Function argument cannot have C name specification")
child_attrs = ["base_type", "declarators"]
decorators = None
- directive_locals = {}
+ directive_locals = None
def analyse_declarations(self, env, dest_scope = None):
+ if self.directive_locals is None:
+ self.directive_locals = {}
if not dest_scope:
dest_scope = env
self.dest_scope = dest_scope
visibility = self.visibility
for declarator in self.declarators:
- name_declarator, type = declarator.analyse(base_type, env)
+ if isinstance(declarator, CFuncDeclaratorNode):
+ name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
+ else:
+ name_declarator, type = declarator.analyse(base_type, env)
if not type.is_complete():
if not (self.visibility == 'extern' and type.is_array):
error(declarator.pos,
cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
api = self.api)
if entry is not None:
- entry.directive_locals = self.directive_locals
+ entry.directive_locals = copy.copy(self.directive_locals)
else:
if self.directive_locals:
error(self.pos, "Decorators can only be followed by functions")
elif default_seen:
error(arg.pos, "Non-default argument following default argument")
+ def align_argument_type(self, env, arg):
+ directive_locals = self.directive_locals
+ type = arg.type
+ if arg.name in directive_locals:
+ type_node = directive_locals[arg.name]
+ other_type = type_node.analyse_as_type(env)
+ if other_type is None:
+ error(type_node.pos, "Not a type")
+ elif (type is not PyrexTypes.py_object_type
+ and not type.same_as(other_type)):
+ error(arg.base_type.pos, "Signature does not agree with previous declaration")
+ error(type_node.pos, "Previous declaration here")
+ else:
+ arg.type = other_type
+ return arg
+
def need_gil_acquisition(self, lenv):
return 0
preprocessor_guard = None
profile = code.globalstate.directives['profile']
+ if profile and lenv.nogil:
+ warning(self.pos, "Cannot profile nogil function.", 1)
+ profile = False
if profile:
- if lenv.nogil:
- error(self.pos, "Cannot profile nogil function.")
code.globalstate.use_utility_code(profile_utility_code)
# Generate C code for header and body of function
(self.return_type.declaration_code(Naming.retval_cname),
init))
tempvardecl_code = code.insertion_point()
- code.put_declare_refcount_context()
+ if not lenv.nogil:
+ code.put_declare_refcount_context()
self.generate_keyword_list(code)
if profile:
code.put_trace_declarations()
info = self.local_scope.arg_entries[1].cname
# Python 3.0 betas have a bug in memoryview which makes it call
# getbuffer with a NULL parameter. For now we work around this;
- # the following line should be removed when this bug is fixed.
- code.putln("if (%s == NULL) return 0;" % info)
+ # the following block should be removed when this bug is fixed.
+ code.putln("if (%s != NULL) {" % info)
code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
+ code.putln("}")
def getbuffer_error_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
+ code.putln("if (%s != NULL && %s->obj != NULL) {"
+ % (info, info))
code.put_gotref("%s->obj" % info)
- code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;" %
- (info, info))
+ code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;"
+ % (info, info))
+ code.putln("}")
def getbuffer_normal_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
- code.putln("if (%s->obj == Py_None) {" % info)
+ code.putln("if (%s != NULL && %s->obj == Py_None) {" % (info, info))
code.put_gotref("Py_None")
code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
code.putln("}")
inline_in_pxd = False
decorators = None
- directive_locals = {}
+ directive_locals = None
def unqualified_name(self):
return self.entry.name
def analyse_declarations(self, env):
+ if self.directive_locals is None:
+ self.directive_locals = {}
self.directive_locals.update(env.directives['locals'])
base_type = self.base_type.analyse(env)
# The 2 here is because we need both function and argument names.
- name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
+ if isinstance(self.declarator, CFuncDeclaratorNode):
+ name_declarator, type = self.declarator.analyse(base_type, env,
+ nonempty = 2 * (self.body is not None),
+ directive_locals = self.directive_locals)
+ else:
+ name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
if not type.is_cfunction:
error(self.pos,
"Suite attached to non-function declaration")
declarator = declarator.base
self.args = declarator.args
for formal_arg, type_arg in zip(self.args, type.args):
+ self.align_argument_type(env, type_arg)
formal_arg.type = type_arg.type
formal_arg.name = type_arg.name
formal_arg.cname = type_arg.cname
api = False,
directive_locals = getattr(cfunc, 'directive_locals', {}))
+ def is_cdef_func_compatible(self):
+ """Determines if the function's signature is compatible with a
+ cdef function. This can be used before calling
+ .as_cfunction() to see if that will be successful.
+ """
+ if self.needs_closure:
+ return False
+ if self.star_arg or self.starstar_arg:
+ return False
+ return True
+
def analyse_declarations(self, env):
self.is_classmethod = self.is_staticmethod = False
if self.decorators:
allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
for arg in self.args:
if hasattr(arg, 'name'):
- type = arg.type
name_declarator = None
else:
base_type = arg.base_type.analyse(env)
name_declarator, type = \
arg.declarator.analyse(base_type, env)
arg.name = name_declarator.name
- if arg.name in directive_locals:
- type_node = directive_locals[arg.name]
- other_type = type_node.analyse_as_type(env)
- if other_type is None:
- error(type_node.pos, "Not a type")
- elif (type is not PyrexTypes.py_object_type
- and not type.same_as(other_type)):
- error(arg.base_type.pos, "Signature does not agree with previous declaration")
- error(type_node.pos, "Previous declaration here")
- else:
- type = other_type
+ arg.type = type
+ self.align_argument_type(env, arg)
if name_declarator and name_declarator.cname:
error(self.pos,
"Python function argument cannot have C name specification")
- arg.type = type.as_argument_type()
+ arg.type = arg.type.as_argument_type()
arg.hdr_type = None
arg.needs_conversion = 0
arg.needs_type_test = 0
entry.doc = None
def declare_lambda_function(self, env):
- name = self.name
- prefix = env.scope_prefix
- func_cname = \
- Naming.lambda_func_prefix + u'funcdef' + prefix + self.lambda_name
- entry = env.declare_lambda_function(func_cname, self.pos)
- entry.pymethdef_cname = \
- Naming.lambda_func_prefix + u'methdef' + prefix + self.lambda_name
- entry.qualified_name = env.qualify_name(self.lambda_name)
+ entry = env.declare_lambda_function(self.lambda_name, self.pos)
entry.doc = None
self.entry = entry
is_generator = True
needs_closure = True
- child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators", "gbody"]
+ child_attrs = DefNode.child_attrs + ["gbody"]
def __init__(self, **kwargs):
# XXX: don't actually needs a body
is_generator_body = True
- child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
-
def __init__(self, pos=None, name=None, body=None):
super(GeneratorBodyDefNode, self).__init__(pos=pos, body=body, name=name, doc=None,
args=[],
for cname, type in code.funcstate.all_managed_temps():
code.put_xdecref(cname, type)
code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
- # XXX: ^^^ is this enough?
# ----- Non-error return cleanup
code.put_label(code.return_label)
if self.exc_type and not self.exc_value and not self.exc_tb:
exc = self.exc_type
import ExprNodes
- if isinstance(exc, ExprNodes.SimpleCallNode) and not exc.args:
+ if (isinstance(exc, ExprNodes.SimpleCallNode) and
+ not (exc.args or (exc.arg_tuple is not None and
+ exc.arg_tuple.args))):
exc = exc.function # extract the exception type
if exc.is_name and exc.entry.is_builtin:
self.builtin_exc_name = exc.name
code.put_goto(try_end_label)
if code.label_used(try_return_label):
code.put_label(try_return_label)
- for var in exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(exc_save_vars))
code.put_goto(old_return_label)
if error_label_used or not self.has_default_clause:
if error_label_used:
code.put_label(except_error_label)
- for var in exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(exc_save_vars))
code.put_goto(old_error_label)
if code.label_used(exit_label):
code.put_label(exit_label)
- for var in exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(exc_save_vars))
code.put_goto(old_label)
if code.label_used(except_end_label):
code.put_label(except_end_label)
- for var in exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(exc_save_vars))
code.put_label(try_end_label)
#------------------------------------------------------------------------------------
+swap_exception_utility_code = UtilityCode(
+proto = """
+static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+""",
+impl = """
+static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) {
+ PyObject *tmp_type, *tmp_value, *tmp_tb;
+ PyThreadState *tstate = PyThreadState_GET();
+
+ tmp_type = tstate->exc_type;
+ tmp_value = tstate->exc_value;
+ tmp_tb = tstate->exc_traceback;
+
+ tstate->exc_type = *type;
+ tstate->exc_value = *value;
+ tstate->exc_traceback = *tb;
+
+ *type = tmp_type;
+ *value = tmp_value;
+ *tb = tmp_tb;
+}
+""")
+
+#------------------------------------------------------------------------------------
+
arg_type_test_utility_code = UtilityCode(
proto = """
static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,