X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=Cython%2FCompiler%2FExprNodes.py;h=27f0ccb9e86fd12de97b5718ddf5e3f11b020bde;hb=HEAD;hp=4c23ef4037054937fb3b298a47081cc567fc19d1;hpb=4abd0ca80f8d7902d96ad27ab227d3be7b43a9fe;p=cython.git diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 4c23ef40..27f0ccb9 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -368,6 +368,11 @@ class ExprNode(Node): else: self.not_implemented("infer_type") + def nonlocally_immutable(self): + # Returns whether this variable is a safe reference, i.e. + # can't be modified as part of globals or closures. + return self.is_temp or self.type.is_array or self.type.is_cfunction + # --------------- Type Analysis ------------------ def analyse_as_module(self, env): @@ -757,6 +762,9 @@ class ConstNode(AtomicExprNode): def is_simple(self): return 1 + def nonlocally_immutable(self): + return 1 + def may_be_none(self): return False @@ -859,9 +867,8 @@ class IntNode(ConstNode): return self elif dst_type.is_float: if self.constant_result is not not_a_constant: - float_value = float(self.constant_result) - return FloatNode(self.pos, value=repr(float_value), type=dst_type, - constant_result=float_value) + return FloatNode(self.pos, value='%d.0' % int(self.constant_result), type=dst_type, + constant_result=float(self.constant_result)) else: return FloatNode(self.pos, value=self.value, type=dst_type, constant_result=not_a_constant) @@ -1108,16 +1115,6 @@ class StringNode(PyConstNode): if not dst_type.is_pyobject: return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env) self.check_for_coercion_error(dst_type, fail=True) - - # this will be a unicode string in Py3, so make sure we can decode it - if self.value.encoding and isinstance(self.value, StringEncoding.BytesLiteral): - try: - self.value.decode(self.value.encoding) - except UnicodeDecodeError: - error(self.pos, ("Decoding unprefixed string literal from '%s' failed. Consider using" - "a byte string or unicode string explicitly, " - "or adjust the source code encoding.") % self.value.encoding) - return self def can_coerce_to_char_literal(self): @@ -1125,7 +1122,8 @@ class StringNode(PyConstNode): def generate_evaluation_code(self, code): self.result_code = code.get_py_string_const( - self.value, identifier=self.is_identifier, is_str=True) + self.value, identifier=self.is_identifier, is_str=True, + unicode_value=self.unicode_value) def get_constant_c_result_code(self): return None @@ -1332,7 +1330,7 @@ class NameNode(AtomicExprNode): if entry and entry.is_cfunction: var_entry = entry.as_variable if var_entry: - if var_entry.is_builtin and Options.cache_builtins: + if var_entry.is_builtin and var_entry.is_const: var_entry = env.declare_builtin(var_entry.name, self.pos) node = NameNode(self.pos, name = self.name) node.entry = var_entry @@ -1429,7 +1427,7 @@ class NameNode(AtomicExprNode): if entry.is_declared_generic: self.result_ctype = py_object_type if entry.is_pyglobal or entry.is_builtin: - if Options.cache_builtins and entry.is_builtin: + if entry.is_builtin and entry.is_const: self.is_temp = 0 else: self.is_temp = 1 @@ -1440,7 +1438,7 @@ class NameNode(AtomicExprNode): if self.is_used_as_rvalue: entry = self.entry if entry.is_builtin: - if not Options.cache_builtins: # cached builtins are ok + if not entry.is_const: # cached builtins are ok self.gil_error() elif entry.is_pyglobal: self.gil_error() @@ -1474,6 +1472,12 @@ class NameNode(AtomicExprNode): # If it's not a C variable, it'll be in a temp. return 1 + def nonlocally_immutable(self): + if ExprNode.nonlocally_immutable(self): + return True + entry = self.entry + return entry and (entry.is_local or entry.is_arg) and not entry.in_closure + def calculate_target_results(self, env): pass @@ -1512,7 +1516,7 @@ class NameNode(AtomicExprNode): entry = self.entry if entry is None: return # There was an error earlier - if entry.is_builtin and Options.cache_builtins: + if entry.is_builtin and entry.is_const: return # Lookup already cached elif entry.is_pyclass_attr: assert entry.type.is_pyobject, "Python global or builtin not a Python object" @@ -1669,20 +1673,22 @@ class NameNode(AtomicExprNode): def generate_deletion_code(self, code): if self.entry is None: return # There was an error earlier - if not self.entry.is_pyglobal: - error(self.pos, "Deletion of local or C global name not supported") - return - if self.entry.is_pyclass_attr: + elif self.entry.is_pyclass_attr: namespace = self.entry.scope.namespace_cname code.put_error_if_neg(self.pos, 'PyMapping_DelItemString(%s, "%s")' % ( namespace, self.entry.name)) - else: + elif self.entry.is_pyglobal: code.put_error_if_neg(self.pos, '__Pyx_DelAttrString(%s, "%s")' % ( Naming.module_cname, self.entry.name)) + elif self.entry.type.is_pyobject: + # Fake it until we can do it for real... + self.generate_assignment_code(NoneNode(self.pos), code) + else: + error(self.pos, "Deletion of C names not supported") def annotate(self, code): if hasattr(self, 'is_called') and self.is_called: @@ -1720,20 +1726,33 @@ class BackquoteNode(ExprNode): code.put_gotref(self.py_result()) - class ImportNode(ExprNode): # Used as part of import statement implementation. # Implements result = - # __import__(module_name, globals(), None, name_list) + # __import__(module_name, globals(), None, name_list, level) # - # module_name StringNode dotted name of module + # module_name StringNode dotted name of module. Empty module + # name means importing the parent package accourding + # to level # name_list ListNode or None list of names to be imported + # level int relative import level: + # -1: attempt both relative import and absolute import; + # 0: absolute import; + # >0: the number of parent directories to search + # relative to the current module. + # None: decide the level according to language level and + # directives type = py_object_type subexprs = ['module_name', 'name_list'] def analyse_types(self, env): + if self.level is None: + if env.directives['language_level'] < 3 or env.directives['py2_import']: + self.level = -1 + else: + self.level = 0 self.module_name.analyse_types(env) self.module_name = self.module_name.coerce_to_pyobject(env) if self.name_list: @@ -1750,10 +1769,11 @@ class ImportNode(ExprNode): else: name_list_code = "0" code.putln( - "%s = __Pyx_Import(%s, %s); %s" % ( + "%s = __Pyx_Import(%s, %s, %d); %s" % ( self.result(), self.module_name.py_result(), name_list_code, + self.level, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) @@ -1890,6 +1910,40 @@ class NextNode(AtomicExprNode): code.putln("}") +class WithExitCallNode(ExprNode): + # The __exit__() call of a 'with' statement. Used in both the + # except and finally clauses. + + # with_stat WithStatNode the surrounding 'with' statement + # args TupleNode or ResultStatNode the exception info tuple + + subexprs = ['args'] + + def analyse_types(self, env): + self.args.analyse_types(env) + self.type = PyrexTypes.c_bint_type + self.is_temp = True + + def generate_result_code(self, code): + if isinstance(self.args, TupleNode): + # call only if it was not already called (and decref-cleared) + code.putln("if (%s) {" % self.with_stat.exit_var) + result_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False) + code.putln("%s = PyObject_Call(%s, %s, NULL);" % ( + result_var, + self.with_stat.exit_var, + self.args.result())) + code.put_decref_clear(self.with_stat.exit_var, type=py_object_type) + code.putln(code.error_goto_if_null(result_var, self.pos)) + code.put_gotref(result_var) + code.putln("%s = __Pyx_PyObject_IsTrue(%s);" % (self.result(), result_var)) + code.put_decref_clear(result_var, type=py_object_type) + code.putln(code.error_goto_if_neg(self.result(), self.pos)) + code.funcstate.release_temp(result_var) + if isinstance(self.args, TupleNode): + code.putln("}") + + class ExcValueNode(AtomicExprNode): # Node created during analyse_types phase # of an ExceptClauseNode to fetch the current @@ -1924,7 +1978,7 @@ class TempNode(ExprNode): subexprs = [] - def __init__(self, pos, type, env): + def __init__(self, pos, type, env=None): ExprNode.__init__(self, pos) self.type = type if type.is_pyobject: @@ -1934,6 +1988,9 @@ class TempNode(ExprNode): def analyse_types(self, env): return self.type + def analyse_target_declaration(self, env): + pass + def generate_result_code(self, code): pass @@ -2073,14 +2130,17 @@ class IndexNode(ExprNode): if index_type and index_type.is_int or isinstance(self.index, (IntNode, LongNode)): # indexing! if base_type is unicode_type: - # Py_UNICODE will automatically coerce to a unicode string - # if required, so this is safe. We only infer Py_UNICODE - # when the index is a C integer type. Otherwise, we may + # Py_UCS4 will automatically coerce to a unicode string + # if required, so this is safe. We only infer Py_UCS4 + # when the index is a C integer type. Otherwise, we may # need to use normal Python item access, in which case # it's faster to return the one-char unicode string than # to receive it, throw it away, and potentially rebuild it # on a subsequent PyObject coercion. - return PyrexTypes.c_py_unicode_type + return PyrexTypes.c_py_ucs4_type + elif base_type is str_type: + # always returns str - Py2: bytes, Py3: unicode + return base_type elif isinstance(self.base, BytesNode): #if env.global_scope().context.language_level >= 3: # # infering 'char' can be made to work in Python 3 mode @@ -2091,8 +2151,8 @@ class IndexNode(ExprNode): return base_type.base_type # may be slicing or indexing, we don't know - if base_type is unicode_type: - # this type always returns its own type on Python indexing/slicing + if base_type in (unicode_type, str_type): + # these types always returns their own type on Python indexing/slicing return base_type else: # TODO: Handle buffers (hopefully without too much redundancy). @@ -2200,7 +2260,7 @@ class IndexNode(ExprNode): if self.index.type.is_int and base_type is unicode_type: # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string # if required, so this is fast and safe - self.type = PyrexTypes.c_py_unicode_type + self.type = PyrexTypes.c_py_ucs4_type elif is_slice and base_type in (bytes_type, str_type, unicode_type, list_type, tuple_type): self.type = base_type else: @@ -2482,6 +2542,8 @@ class SliceIndexNode(ExprNode): elif base_type in (bytes_type, str_type, unicode_type, list_type, tuple_type): return base_type + elif base_type.is_ptr or base_type.is_array: + return PyrexTypes.c_array_type(base_type.base_type, None) return py_object_type def calculate_constant_result(self): @@ -2994,7 +3056,7 @@ class SimpleCallNode(CallNode): if i == 0 and self.self is not None: # a method's cloned "self" argument is ok pass - elif arg.is_name and arg.entry and arg.entry.is_local and not arg.entry.in_closure: + elif arg.nonlocally_immutable(): # plain local variables are ok pass else: @@ -3028,10 +3090,11 @@ class SimpleCallNode(CallNode): if i == 0 and self.self is not None: continue # self is ok arg = self.args[i] - if arg.is_name and arg.entry and ( - (arg.entry.is_local and not arg.entry.in_closure) - or arg.entry.type.is_cfunction): - # local variables and C functions are safe + if arg.nonlocally_immutable(): + # locals, C functions, unassignable types are safe. + pass + elif arg.type.is_cpp_class: + # Assignment has side effects, avoid. pass elif env.nogil and arg.type.is_pyobject: # can't copy a Python reference into a temp in nogil @@ -3039,7 +3102,11 @@ class SimpleCallNode(CallNode): # nogil anyway) pass else: - self.args[i] = arg.coerce_to_temp(env) + #self.args[i] = arg.coerce_to_temp(env) + # instead: issue a warning + if i > 0 or i == 1 and self.self is not None: # skip first arg + warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0) + break # Calc result type and code fragment if isinstance(self.function, NewExprNode): self.type = PyrexTypes.CPtrType(self.function.class_type) @@ -4046,6 +4113,10 @@ class TupleNode(SequenceNode): # either temp or constant => always simple return True + def nonlocally_immutable(self): + # either temp or constant => always safe + return True + def calculate_result_code(self): if len(self.args) > 0: return self.result_code @@ -5266,7 +5337,8 @@ class UnaryPlusNode(UnopNode): operator = '+' def analyse_c_operation(self, env): - self.type = self.operand.type + self.type = PyrexTypes.widest_numeric_type( + self.operand.type, PyrexTypes.c_int_type) def py_operation_function(self): return "PyNumber_Positive" @@ -5285,7 +5357,8 @@ class UnaryMinusNode(UnopNode): def analyse_c_operation(self, env): if self.operand.type.is_numeric: - self.type = self.operand.type + self.type = PyrexTypes.widest_numeric_type( + self.operand.type, PyrexTypes.c_int_type) else: self.type_error() if self.type.is_complex: @@ -5310,7 +5383,8 @@ class TildeNode(UnopNode): def analyse_c_operation(self, env): if self.operand.type.is_int: - self.type = self.operand.type + self.type = PyrexTypes.widest_numeric_type( + self.operand.type, PyrexTypes.c_int_type) else: self.type_error() @@ -5345,7 +5419,10 @@ class DecrementIncrementNode(CUnopNode): # unary ++/-- operator def analyse_c_operation(self, env): - if self.operand.type.is_ptr or self.operand.type.is_numeric: + if self.operand.type.is_numeric: + self.type = PyrexTypes.widest_numeric_type( + self.operand.type, PyrexTypes.c_int_type) + elif self.operand.type.is_ptr: self.type = self.operand.type else: self.type_error() @@ -5484,6 +5561,9 @@ class TypecastNode(ExprNode): # either temp or a C cast => no side effects return True + def nonlocally_immutable(self): + return self.operand.nonlocally_immutable() + def nogil_check(self, env): if self.type and self.type.is_pyobject and self.is_temp: self.gil_error() @@ -5881,6 +5961,9 @@ class NumBinopNode(BinopNode): if self.operator not in '|^&': # False + False == 0 # not False! widest_type = PyrexTypes.c_int_type + else: + widest_type = PyrexTypes.widest_numeric_type( + widest_type, PyrexTypes.c_int_type) return widest_type else: return None @@ -6022,7 +6105,7 @@ class DivNode(NumBinopNode): operand2 = self.operand2.compile_time_value(denv) try: func = self.find_compile_time_binary_operator( - self, operand1, operand2) + operand1, operand2) return func(operand1, operand2) except Exception, e: self.compile_time_value_error(e) @@ -6589,6 +6672,14 @@ class CmpNode(object): env.use_utility_code(pyunicode_equals_utility_code) self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals" return True + elif type1 is Builtin.bytes_type or type2 is Builtin.bytes_type: + env.use_utility_code(pybytes_equals_utility_code) + self.special_bool_cmp_function = "__Pyx_PyBytes_Equals" + return True + elif type1 is Builtin.str_type or type2 is Builtin.str_type: + env.use_utility_code(pystr_equals_utility_code) + self.special_bool_cmp_function = "__Pyx_PyString_Equals" + return True return False def generate_operation_code(self, code, result_code, @@ -6721,11 +6812,43 @@ static CYTHON_INLINE int __Pyx_UnicodeContains(PyObject* unicode, Py_UNICODE cha """, impl=""" static CYTHON_INLINE int __Pyx_UnicodeContains(PyObject* unicode, Py_UNICODE character) { + Py_UNICODE* pos; const Py_ssize_t length = PyUnicode_GET_SIZE(unicode); Py_UNICODE* char_start = PyUnicode_AS_UNICODE(unicode); + + for (pos=char_start; pos < char_start+length; pos++) { + if (unlikely(character == pos[0])) return 1; + } + return 0; +} +""") + +py_ucs4_in_unicode_utility_code = UtilityCode( +proto=""" +static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character); /*proto*/ +""", +# additionally handles surrogate pairs in 16bit Unicode builds +impl=""" +static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character) { Py_UNICODE* pos; + Py_UNICODE uchar; + const Py_ssize_t length = PyUnicode_GET_SIZE(unicode); + Py_UNICODE* char_start = PyUnicode_AS_UNICODE(unicode); + + #if Py_UNICODE_SIZE == 2 + if (unlikely(character > 65535)) { + Py_UNICODE high_val, low_val; + high_val = (Py_UNICODE) (0xD800 | (((character - 0x10000) >> 10) & ((1<<10)-1))); + low_val = (Py_UNICODE) (0xDC00 | ( (character - 0x10000) & ((1<<10)-1))); + for (pos=char_start; pos < char_start+length-1; pos++) { + if (unlikely(high_val == pos[0]) & unlikely(low_val == pos[1])) return 1; + } + return 0; + } + #endif + uchar = (Py_UNICODE) character; for (pos=char_start; pos < char_start+length; pos++) { - if (character == pos[0]) return 1; + if (unlikely(uchar == pos[0])) return 1; } return 0; } @@ -6753,8 +6876,6 @@ static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int return -1; return (equals == Py_EQ) ? (result == 0) : (result != 0); } - } else if ((s1 == Py_None) & (s2 == Py_None)) { - return (equals == Py_EQ); } else if ((s1 == Py_None) & PyUnicode_CheckExact(s2)) { return (equals == Py_NE); } else if ((s2 == Py_None) & PyUnicode_CheckExact(s1)) { @@ -6771,6 +6892,53 @@ static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int } """) +pybytes_equals_utility_code = UtilityCode( +proto=""" +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); /*proto*/ +""", +impl=""" +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { + if (s1 == s2) { /* as done by PyObject_RichCompareBool(); also catches the (interned) empty string */ + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + if (PyBytes_GET_SIZE(s1) != PyBytes_GET_SIZE(s2)) { + return (equals == Py_NE); + } else if (PyBytes_GET_SIZE(s1) == 1) { + if (equals == Py_EQ) + return (PyBytes_AS_STRING(s1)[0] == PyBytes_AS_STRING(s2)[0]); + else + return (PyBytes_AS_STRING(s1)[0] != PyBytes_AS_STRING(s2)[0]); + } else { + int result = memcmp(PyBytes_AS_STRING(s1), PyBytes_AS_STRING(s2), PyBytes_GET_SIZE(s1)); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +} +""", +requires=[Builtin.include_string_h_utility_code]) + +pystr_equals_utility_code = UtilityCode( +proto=""" +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals +#else +#define __Pyx_PyString_Equals __Pyx_PyBytes_Equals +#endif +""", +requires=[pybytes_equals_utility_code, pyunicode_equals_utility_code]) + class PrimaryCmpNode(ExprNode, CmpNode): # Non-cascaded comparison or first comparison of @@ -6823,7 +6991,12 @@ class PrimaryCmpNode(ExprNode, CmpNode): error(self.pos, "Cascading comparison not yet supported for 'int_val in string'.") return if self.operand2.type is unicode_type: - env.use_utility_code(pyunicode_in_unicode_utility_code) + self.uchar_test_type = PyrexTypes.widest_numeric_type( + self.operand1.type, PyrexTypes.c_py_unicode_type) + if self.uchar_test_type is PyrexTypes.c_py_unicode_type: + env.use_utility_code(pyunicode_in_unicode_utility_code) + else: + env.use_utility_code(py_ucs4_in_unicode_utility_code) else: if self.operand1.type is PyrexTypes.c_uchar_type: self.operand1 = self.operand1.coerce_to(PyrexTypes.c_char_type, env) @@ -6913,10 +7086,13 @@ class PrimaryCmpNode(ExprNode, CmpNode): self.operand1.result(), self.operand2.result()) elif self.is_c_string_contains(): - if self.operand2.type is bytes_type: - method = "__Pyx_BytesContains" + if self.operand2.type is unicode_type: + if self.uchar_test_type is PyrexTypes.c_py_unicode_type: + method = "__Pyx_UnicodeContains" + else: + method = "__Pyx_UnicodeContainsUCS4" else: - method = "__Pyx_UnicodeContains" + method = "__Pyx_BytesContains" if self.operator == "not_in": negation = "!" else: @@ -7568,20 +7744,27 @@ impl = """ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { PyObject *result; result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); + if (!result) { + if (dict != %(BUILTINS)s) { + PyErr_Clear(); + result = PyObject_GetAttr(%(BUILTINS)s, name); + } + if (!result) { + PyErr_SetObject(PyExc_NameError, name); + } + } return result; } -""") +""" % {'BUILTINS' : Naming.builtins_cname}) #------------------------------------------------------------------------------------ import_utility_code = UtilityCode( proto = """ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level); /*proto*/ """, impl = """ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level) { PyObject *py_import = 0; PyObject *empty_list = 0; PyObject *module = 0; @@ -7605,8 +7788,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { empty_dict = PyDict_New(); if (!empty_dict) goto bad; + #if PY_VERSION_HEX >= 0x02050000 + { + PyObject *py_level = PyInt_FromLong(level); + if (!py_level) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, global_dict, empty_dict, list, py_level, NULL); + Py_DECREF(py_level); + } + #else + if (level>0) { + PyErr_SetString(PyExc_RuntimeError, "Relative import is not supported for Python <=2.4."); + goto bad; + } module = PyObject_CallFunctionObjArgs(py_import, name, global_dict, empty_dict, list, NULL); + #endif bad: Py_XDECREF(empty_list); Py_XDECREF(py_import); @@ -7695,7 +7893,7 @@ static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases) { #if PY_MAJOR_VERSION < 3 if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { PyObject *base = PyTuple_GET_ITEM(bases, 0); - metaclass = PyObject_GetAttrString(base, "__class__"); + metaclass = PyObject_GetAttrString(base, (char *)"__class__"); if (!metaclass) { PyErr_Clear(); metaclass = (PyObject*) Py_TYPE(base); @@ -7773,7 +7971,7 @@ PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObje PyObject *ns; PyObject *str; - prep = PyObject_GetAttrString(metaclass, "__prepare__"); + prep = PyObject_GetAttrString(metaclass, (char *)"__prepare__"); if (!prep) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL; @@ -8328,8 +8526,8 @@ static int __Pyx_cdivision_warning(void) { # from intobject.c division_overflow_test_code = UtilityCode( proto=""" -#define UNARY_NEG_WOULD_OVERFLOW(x) \ - (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x))) +#define UNARY_NEG_WOULD_OVERFLOW(x) \ + (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x))) """) @@ -8352,29 +8550,29 @@ static int %(binding_cfunc)s_init(void); /* proto */ impl=""" static PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) { - %(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s); + %(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s); if (op == NULL) return NULL; - op->func.m_ml = ml; - Py_XINCREF(self); - op->func.m_self = self; - Py_XINCREF(module); - op->func.m_module = module; - PyObject_GC_Track(op); - return (PyObject *)op; + op->func.m_ml = ml; + Py_XINCREF(self); + op->func.m_self = self; + Py_XINCREF(module); + op->func.m_module = module; + PyObject_GC_Track(op); + return (PyObject *)op; } static void %(binding_cfunc)s_dealloc(%(binding_cfunc)s_object *m) { - PyObject_GC_UnTrack(m); - Py_XDECREF(m->func.m_self); - Py_XDECREF(m->func.m_module); + PyObject_GC_UnTrack(m); + Py_XDECREF(m->func.m_self); + Py_XDECREF(m->func.m_module); PyObject_GC_Del(m); } static PyObject *%(binding_cfunc)s_descr_get(PyObject *func, PyObject *obj, PyObject *type) { - if (obj == Py_None) - obj = NULL; - return PyMethod_New(func, obj, type); + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type); } static int %(binding_cfunc)s_init(void) { @@ -8401,6 +8599,17 @@ static PyObject *__Pyx_Generator_Throw(PyObject *gen, PyObject *args, CYTHON_UNU typedef PyObject *(*__pyx_generator_body_t)(PyObject *, PyObject *); """, impl=""" +static CYTHON_INLINE void __Pyx_Generator_ExceptionClear(struct __pyx_Generator_object *self) +{ + Py_XDECREF(self->exc_type); + Py_XDECREF(self->exc_value); + Py_XDECREF(self->exc_traceback); + + self->exc_type = NULL; + self->exc_value = NULL; + self->exc_traceback = NULL; +} + static CYTHON_INLINE PyObject *__Pyx_Generator_SendEx(struct __pyx_Generator_object *self, PyObject *value) { PyObject *retval; @@ -8425,10 +8634,21 @@ static CYTHON_INLINE PyObject *__Pyx_Generator_SendEx(struct __pyx_Generator_obj return NULL; } + + if (value) + __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, &self->exc_traceback); + else + __Pyx_Generator_ExceptionClear(self); + self->is_running = 1; retval = self->body((PyObject *) self, value); self->is_running = 0; + if (retval) + __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, &self->exc_traceback); + else + __Pyx_Generator_ExceptionClear(self); + return retval; } @@ -8479,12 +8699,12 @@ static PyObject *__Pyx_Generator_Throw(PyObject *self, PyObject *args, CYTHON_UN PyObject *tb = NULL; PyObject *val = NULL; - if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) + if (!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb)) return NULL; - __Pyx_Raise(typ, val, tb); + __Pyx_Raise(typ, val, tb, NULL); return __Pyx_Generator_SendEx(generator, NULL); } """, proto_block='utility_code_proto_before_types', -requires=[Nodes.raise_utility_code], +requires=[Nodes.raise_utility_code, Nodes.swap_exception_utility_code], )