X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=Cython%2FCompiler%2FNodes.py;h=28ec47ef48c9e5a9a96f4adee119bae673750f04;hb=9ce66875046c03b6123280ab56149c1536d3edff;hp=9ec19ad390512961650f02b1d39e60ec612134a9;hpb=56e2c80a2c410c83a1805172937ea2850bc7f1f4;p=cython.git diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 9ec19ad3..28ec47ef 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") @@ -607,9 +618,6 @@ class CFuncDeclaratorNode(CDeclaratorNode): error(self.exception_value.pos, "Exception value incompatible with function return type") exc_check = self.exception_check - if return_type.is_array: - error(self.pos, - "Function cannot return an array") if return_type.is_cfunction: error(self.pos, "Function cannot return a function") @@ -651,6 +659,9 @@ class CArgDeclNode(Node): is_self_arg = 0 is_type_arg = 0 is_generic = 1 + kw_only = 0 + not_none = 0 + or_none = 0 type = None name_declarator = None default_value = None @@ -736,6 +747,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode): child_attrs = [] arg_name = None # in case the argument name was interpreted as a type + module_path = [] + is_basic_c_type = False + complex = False def analyse(self, env, could_be_name = False): # Return type descriptor. @@ -922,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 @@ -941,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, @@ -959,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") @@ -967,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 @@ -977,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 @@ -992,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 @@ -1060,6 +1081,8 @@ class CppClassNode(CStructOrUnionDefNode): self.entry = env.declare_cpp_class( self.name, scope, self.pos, self.cname, base_class_types, visibility = self.visibility, templates = template_types) + if self.entry is None: + return self.entry.is_cpp_class = 1 if self.attributes is not None: if self.in_pxd and not env.in_cinclude: @@ -1073,6 +1096,7 @@ class CEnumDefNode(StatNode): # items [CEnumDefItemNode] # typedef_flag boolean # visibility "public" or "private" + # api boolean # in_pxd boolean # entry Entry @@ -1081,7 +1105,7 @@ class CEnumDefNode(StatNode): 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 @@ -1092,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" % ( @@ -1124,7 +1148,7 @@ class CEnumDefItemNode(StatNode): self.value.analyse_const_expression(env) 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) @@ -1132,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"] @@ -1142,7 +1167,7 @@ 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 @@ -1188,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 @@ -1248,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 @@ -1300,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() @@ -1543,7 +1586,6 @@ class FuncDefNode(StatNode, BlockNode): def generate_arg_none_check(self, arg, code): # Generate None check for one argument. - code.globalstate.use_utility_code(arg_type_test_utility_code) code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % arg.entry.cname) code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % ( arg.name, @@ -1581,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("}") @@ -1620,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") @@ -1644,9 +1697,12 @@ 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 + if type_arg.type.is_buffer and 'inline' in self.modifiers: + warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1) name = name_declarator.name cname = name_declarator.cname self.entry = env.declare_cfunction( @@ -1656,6 +1712,9 @@ class CFuncDefNode(FuncDefNode): api = self.api, modifiers = self.modifiers) self.entry.inline_func_in_pxd = self.inline_in_pxd self.return_type = type.return_type + if self.return_type.is_array and visibility != 'extern': + error(self.pos, + "Function cannot return an array") if self.overridable and not env.is_module_scope: if len(self.args) < 1 or not self.args[0].type.is_pyobject: @@ -1733,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: @@ -1747,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: @@ -1898,6 +1952,9 @@ class DefNode(FuncDefNode): entry = None acquire_gil = 0 self_in_stararg = 0 + star_arg = None + starstar_arg = None + doc = None def __init__(self, pos, **kwds): FuncDefNode.__init__(self, pos, **kwds) @@ -1975,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: @@ -2008,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 @@ -2174,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 @@ -2280,6 +2331,8 @@ class DefNode(FuncDefNode): arg.hdr_type.declaration_code(arg.hdr_cname)) if not self.entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]: arg_code_list.append("CYTHON_UNUSED PyObject *unused") + if (self.entry.scope.is_c_class_scope and self.entry.name == "__ipow__"): + arg_code_list.append("CYTHON_UNUSED PyObject *unused") if sig.has_generic_args: arg_code_list.append( "PyObject *%s, PyObject *%s" @@ -2652,7 +2705,7 @@ class DefNode(FuncDefNode): max_positional_args, Naming.args_cname)) code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname) if self.starstar_arg: - code.put_decref(self.starstar_arg.entry.cname, py_object_type) + code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type) if self.needs_closure: code.put_decref(Naming.cur_scope_cname, self.local_scope.scope_class.type) code.put_finish_refcount_context() @@ -2913,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 @@ -2947,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=[], @@ -2981,8 +3032,6 @@ class GeneratorBodyDefNode(DefNode): # Generate closure function definitions self.body.generate_function_definitions(lenv, code) - # generate lambda function definitions - self.generate_lambda_definitions(lenv, code) # Generate C code for header and body of function code.enter_cfunc_scope() @@ -3019,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) @@ -3307,6 +3355,7 @@ class CClassDefNode(ClassDefNode): objstruct_name = None typeobj_name = None decorators = None + shadow = False def analyse_declarations(self, env): #print "CClassDefNode.analyse_declarations:", self.class_name @@ -3380,7 +3429,9 @@ class CClassDefNode(ClassDefNode): home_scope = env if self.visibility == 'extern': - if self.module_name == '__builtin__' and self.class_name in Builtin.builtin_types: + if (self.module_name == '__builtin__' and + self.class_name in Builtin.builtin_types and + env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1) self.entry = home_scope.declare_c_class( @@ -3395,7 +3446,10 @@ class CClassDefNode(ClassDefNode): visibility = self.visibility, typedef_flag = self.typedef_flag, api = self.api, - buffer_defaults = buffer_defaults) + buffer_defaults = buffer_defaults, + shadow = self.shadow) + if self.shadow: + home_scope.lookup(self.class_name).as_variable = self.entry if home_scope is not env and self.visibility == 'extern': env.add_imported_entry(self.class_name, self.entry, self.pos) self.scope = scope = self.entry.type.scope @@ -4118,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 @@ -4507,7 +4563,12 @@ class ForInStatNode(LoopNode, StatNode): self.target.analyse_target_types(env) self.iterator.analyse_expressions(env) self.item = ExprNodes.NextNode(self.iterator, env) - self.item = self.item.coerce_to(self.target.type, env) + if (self.iterator.type.is_ptr or self.iterator.type.is_array) and \ + self.target.type.assignable_from(self.iterator.type): + # C array slice optimization. + pass + else: + self.item = self.item.coerce_to(self.target.type, env) self.body.analyse_expressions(env) if self.else_clause: self.else_clause.analyse_expressions(env) @@ -4876,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) @@ -4890,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) @@ -4901,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) @@ -5306,7 +5371,7 @@ class GILStatNode(TryFinallyStatNode): code.putln("#endif") else: code.putln("#ifdef WITH_THREAD") - code.putln("PyThreadState *_save;") + code.putln("PyThreadState *_save = NULL;") code.putln("#endif") code.putln("Py_UNBLOCK_THREADS") TryFinallyStatNode.generate_execution_code(self, code) @@ -6040,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,