X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=Cython%2FCompiler%2FNodes.py;h=977447dc3f9c2e6fcb2105a93d5cda9c720a494e;hb=5b9d3022e7940db30f8dfc2b424d148acc0dbee1;hp=ab8612a24e6cc0134db4dff095fc969bb8af4a0b;hpb=231b6b6467da73089a1a5d67613b79d897b891c0;p=cython.git diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index ab8612a2..977447dc 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -535,7 +535,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): 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 = [] @@ -543,6 +543,17 @@ class CFuncDeclaratorNode(CDeclaratorNode): 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") @@ -925,9 +936,11 @@ class CVarDefNode(StatNode): 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 @@ -944,7 +957,10 @@ class CVarDefNode(StatNode): 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, @@ -962,7 +978,7 @@ class CVarDefNode(StatNode): 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") @@ -970,7 +986,7 @@ class CVarDefNode(StatNode): error(self.pos, "Only 'extern' C variable declaration allowed in .pxd file") entry = dest_scope.declare_var(name, type, declarator.pos, - cname = cname, visibility = visibility, is_cdef = 1) + cname=cname, visibility=visibility, api=self.api, is_cdef=1) entry.needs_property = need_property @@ -980,6 +996,7 @@ class CStructOrUnionDefNode(StatNode): # kind "struct" or "union" # typedef_flag boolean # visibility "public" or "private" + # api boolean # in_pxd boolean # attributes [CVarDefNode] or None # entry Entry @@ -995,7 +1012,8 @@ class CStructOrUnionDefNode(StatNode): scope = StructOrUnionScope(self.name) self.entry = env.declare_struct_or_union( self.name, self.kind, scope, self.typedef_flag, self.pos, - self.cname, visibility = self.visibility, packed = self.packed) + self.cname, visibility = self.visibility, api = self.api, + packed = self.packed) if self.attributes is not None: if self.in_pxd and not env.in_cinclude: self.entry.defined_in_pxd = 1 @@ -1078,15 +1096,16 @@ class CEnumDefNode(StatNode): # items [CEnumDefItemNode] # typedef_flag boolean # visibility "public" or "private" + # api boolean # in_pxd boolean # entry Entry - + child_attrs = ["items"] def analyse_declarations(self, env): self.entry = env.declare_enum(self.name, self.pos, cname = self.cname, typedef_flag = self.typedef_flag, - visibility = self.visibility) + visibility = self.visibility, api = self.api) if self.items is not None: if self.in_pxd and not env.in_cinclude: self.entry.defined_in_pxd = 1 @@ -1097,7 +1116,7 @@ class CEnumDefNode(StatNode): pass def generate_execution_code(self, code): - if self.visibility == 'public': + if self.visibility == 'public' or self.api: temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) for item in self.entry.enum_values: code.putln("%s = PyInt_FromLong(%s); %s" % ( @@ -1127,9 +1146,9 @@ class CEnumDefItemNode(StatNode): if not self.value.type.is_int: self.value = self.value.coerce_to(PyrexTypes.c_int_type, env) self.value.analyse_const_expression(env) - entry = env.declare_const(self.name, enum_entry.type, + entry = env.declare_const(self.name, enum_entry.type, self.value, self.pos, cname = self.cname, - visibility = enum_entry.visibility) + visibility = enum_entry.visibility, api = enum_entry.api) enum_entry.enum_values.append(entry) @@ -1137,6 +1156,7 @@ class CTypeDefNode(StatNode): # base_type CBaseTypeNode # declarator CDeclaratorNode # visibility "public" or "private" + # api boolean # in_pxd boolean child_attrs = ["base_type", "declarator"] @@ -1147,10 +1167,10 @@ class CTypeDefNode(StatNode): name = name_declarator.name cname = name_declarator.cname entry = env.declare_typedef(name, type, self.pos, - cname = cname, visibility = self.visibility) + cname = cname, visibility = self.visibility, api = self.api) if self.in_pxd and not env.in_cinclude: entry.defined_in_pxd = 1 - + def analyse_expressions(self, env): pass def generate_execution_code(self, code): @@ -1193,6 +1213,22 @@ class FuncDefNode(StatNode, BlockNode): 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 @@ -1253,9 +1289,10 @@ class FuncDefNode(StatNode, BlockNode): 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 @@ -1305,7 +1342,8 @@ class FuncDefNode(StatNode, BlockNode): (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() @@ -1585,20 +1623,24 @@ class FuncDefNode(StatNode, BlockNode): 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("}") @@ -1624,16 +1666,23 @@ class CFuncDefNode(FuncDefNode): 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") @@ -1648,6 +1697,7 @@ class CFuncDefNode(FuncDefNode): 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 @@ -1742,7 +1792,6 @@ class CFuncDefNode(FuncDefNode): def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None): arg_decls = [] type = self.type - visibility = self.entry.visibility for arg in type.args[:len(type.args)-type.optional_arg_count]: arg_decls.append(arg.declaration_code()) if with_dispatch and self.overridable: @@ -1756,24 +1805,20 @@ class CFuncDefNode(FuncDefNode): if cname is None: cname = self.entry.func_cname entity = type.function_header_code(cname, ', '.join(arg_decls)) - if visibility == 'public': - dll_linkage = "DL_EXPORT" + if self.entry.visibility == 'private': + storage_class = "static " else: - dll_linkage = None - header = self.return_type.declaration_code(entity, - dll_linkage = dll_linkage) - if visibility == 'extern': - storage_class = "%s " % Naming.extern_c_macro - elif visibility == 'public': storage_class = "" - else: - storage_class = "static " + dll_linkage = None + modifiers = "" if 'inline' in self.modifiers: self.modifiers[self.modifiers.index('inline')] = 'cython_inline' - code.putln("%s%s %s {" % ( - storage_class, - ' '.join(self.modifiers).upper(), # macro forms - header)) + if self.modifiers: + modifiers = "%s " % ' '.join(self.modifiers).upper() + + header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage) + #print (storage_class, modifiers, header) + code.putln("%s%s%s {" % (storage_class, modifiers, header)) def generate_argument_declarations(self, env, code): for arg in self.args: @@ -1987,6 +2032,17 @@ class DefNode(FuncDefNode): 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: @@ -2020,28 +2076,18 @@ class DefNode(FuncDefNode): 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 @@ -2186,14 +2232,7 @@ class DefNode(FuncDefNode): 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 @@ -2927,7 +2966,7 @@ class GeneratorDefNode(DefNode): 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 @@ -2961,8 +3000,6 @@ class GeneratorBodyDefNode(DefNode): 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=[], @@ -3031,7 +3068,6 @@ class GeneratorBodyDefNode(DefNode): 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) @@ -4136,7 +4172,9 @@ class RaiseStatNode(StatNode): 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 @@ -4899,7 +4937,8 @@ class TryExceptStatNode(StatNode): 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) @@ -4913,7 +4952,8 @@ class TryExceptStatNode(StatNode): 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) @@ -4924,14 +4964,16 @@ class TryExceptStatNode(StatNode): 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) @@ -6063,6 +6105,31 @@ static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) #------------------------------------------------------------------------------------ +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,