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):
def is_simple(self):
return 1
+ def nonlocally_immutable(self):
+ return 1
+
def may_be_none(self):
return False
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)
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):
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
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
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
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()
# 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
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"
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:
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:
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())
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
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:
def analyse_types(self, env):
return self.type
+ def analyse_target_declaration(self, env):
+ pass
+
def generate_result_code(self, code):
pass
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
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).
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:
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):
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:
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
# 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)
# 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
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"
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:
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()
# 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()
# 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()
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
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)
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,
""",
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;
}
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)) {
}
""")
+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
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)
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:
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;
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);
#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);
PyObject *ns;
PyObject *str;
- prep = PyObject_GetAttrString(metaclass, "__prepare__");
+ prep = PyObject_GetAttrString(metaclass, (char *)"__prepare__");
if (!prep) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
# 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)))
""")
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) {
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;
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;
}
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],
)