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 self.can_coerce_to_char_literal():
error(self.pos, "Only single-character string literals can be coerced into ints.")
return self
- if dst_type is PyrexTypes.c_py_unicode_type:
- error(self.pos, "Bytes literals cannot coerce to Py_UNICODE, use a unicode literal instead.")
+ if dst_type.is_unicode_char:
+ error(self.pos, "Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.")
return self
return CharNode(self.pos, value=self.value)
def coerce_to(self, dst_type, env):
if dst_type is self.type:
pass
- elif dst_type is PyrexTypes.c_py_unicode_type:
+ elif dst_type.is_unicode_char:
if not self.can_coerce_to_char_literal():
- error(self.pos, "Only single-character Unicode string literals can be coerced into Py_UNICODE.")
+ error(self.pos, "Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.")
return self
int_value = ord(self.value)
- return IntNode(self.pos, value=int_value, constant_result=int_value)
+ return IntNode(self.pos, type=dst_type, value=str(int_value), constant_result=int_value)
elif not dst_type.is_pyobject:
if dst_type.is_string and self.bytes_value is not None:
# special case: '-3' enforced unicode literal used in a C char* context
return BytesNode(self.pos, value=self.bytes_value).coerce_to(dst_type, env)
- error(self.pos, "Unicode literals do not support coercion to C types other than Py_UNICODE.")
+ error(self.pos, "Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.")
elif dst_type is not py_object_type:
if not self.check_for_coercion_error(dst_type):
self.fail_assignment(dst_type)
def can_coerce_to_char_literal(self):
return len(self.value) == 1
+ ## or (len(self.value) == 2
+ ## and (0xD800 <= self.value[0] <= 0xDBFF)
+ ## and (0xDC00 <= self.value[1] <= 0xDFFF))
def contains_surrogates(self):
# Check if the unicode string contains surrogate code points
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
def is_ephemeral(self):
return self.base.is_ephemeral()
+ def is_simple(self):
+ if self.is_buffer_access:
+ return False
+ base = self.base
+ return (base.is_simple() and self.index.is_simple()
+ and base.type and (base.type.is_ptr or base.type.is_array))
+
def analyse_target_declaration(self, env):
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).
elif not skip_child_analysis:
self.index.analyse_types(env)
self.original_index_type = self.index.type
- if base_type is PyrexTypes.c_py_unicode_type:
- # we infer Py_UNICODE for unicode strings in some
+ if base_type.is_unicode_char:
+ # we infer Py_UNICODE/Py_UCS4 for unicode strings in some
# cases, but indexing must still work for them
if self.index.constant_result in (0, -1):
# FIXME: we know that this node is redundant -
self.index = self.index.coerce_to_pyobject(env)
self.is_temp = 1
if self.index.type.is_int and base_type is unicode_type:
- # Py_UNICODE will automatically coerce to a unicode string
+ # 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:
return "PyList_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result())
elif self.base.type is tuple_type:
return "PyTuple_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result())
- elif self.base.type is unicode_type and self.type is PyrexTypes.c_py_unicode_type:
+ elif self.base.type is unicode_type and self.type.is_unicode_char:
return "PyUnicode_AS_UNICODE(%s)[%s]" % (self.base.result(), self.index.result())
elif (self.type.is_ptr or self.type.is_array) and self.type == self.base.type:
error(self.pos, "Invalid use of pointer slice")
self.result(),
code.error_goto(self.pos)))
code.put_gotref(self.py_result())
- elif self.type is PyrexTypes.c_py_unicode_type and self.base.type is unicode_type:
+ elif self.type.is_unicode_char and self.base.type is unicode_type:
assert self.index.type.is_int
index_code = self.index.result()
function = "__Pyx_GetItemInt_Unicode"
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):
# stop ExprNode
# step ExprNode
+ subexprs = ['start', 'stop', 'step']
+
type = py_object_type
is_temp = 1
def calculate_constant_result(self):
- self.constant_result = self.base.constant_result[
- self.start.constant_result : \
- self.stop.constant_result : \
- self.step.constant_result]
+ self.constant_result = slice(
+ self.start.constant_result,
+ self.stop.constant_result,
+ self.step.constant_result)
def compile_time_value(self, denv):
start = self.start.compile_time_value(denv)
- if self.stop is None:
- stop = None
- else:
- stop = self.stop.compile_time_value(denv)
- if self.step is None:
- step = None
- else:
- step = self.step.compile_time_value(denv)
+ stop = self.stop.compile_time_value(denv)
+ step = self.step.compile_time_value(denv)
try:
return slice(start, stop, step)
except Exception, e:
self.compile_time_value_error(e)
- subexprs = ['start', 'stop', 'step']
-
def analyse_types(self, env):
self.start.analyse_types(env)
self.stop.analyse_types(env)
self.start = self.start.coerce_to_pyobject(env)
self.stop = self.stop.coerce_to_pyobject(env)
self.step = self.step.coerce_to_pyobject(env)
+ if self.start.is_literal and self.stop.is_literal and self.step.is_literal:
+ self.is_literal = True
+ self.is_temp = False
gil_message = "Constructing Python slice object"
+ def calculate_result_code(self):
+ return self.result_code
+
def generate_result_code(self, code):
+ if self.is_literal:
+ self.result_code = code.get_py_const(py_object_type, 'slice_', cleanup_level=2)
+ code = code.get_cached_constants_writer()
+ code.mark_pos(self.pos)
+
code.putln(
"%s = PySlice_New(%s, %s, %s); %s" % (
self.result(),
self.step.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
+ if self.is_literal:
+ code.put_giveref(self.py_result())
class CallNode(ExprNode):
func_type = func_type.base_type
return func_type
+ def is_simple(self):
+ # C function calls could be considered simple, but they may
+ # have side-effects that may hit when multiple operations must
+ # be effected in order, e.g. when constructing the argument
+ # sequence for a function call or comparing values.
+ return False
+
def analyse_c_function_call(self, env):
if self.function.type is error_type:
self.type = error_type
self.has_optional_args = 1
self.is_temp = 1
# Coerce arguments
- for i in range(min(max_nargs, actual_nargs)):
+ some_args_in_temps = False
+ for i in xrange(min(max_nargs, actual_nargs)):
formal_type = func_type.args[i].type
arg = self.args[i].coerce_to(formal_type, env)
- if arg.type.is_pyobject and not env.nogil and (arg.is_attribute or not arg.is_simple):
- # we do not own the argument's reference, but we must
- # make sure it cannot be collected before we return
- # from the function, so we create an owned temp
- # reference to it
- arg = arg.coerce_to_temp(env)
+ if arg.is_temp:
+ if i > 0:
+ # first argument in temp doesn't impact subsequent arguments
+ some_args_in_temps = True
+ elif arg.type.is_pyobject and not env.nogil:
+ if i == 0 and self.self is not None:
+ # a method's cloned "self" argument is ok
+ pass
+ elif arg.nonlocally_immutable():
+ # plain local variables are ok
+ pass
+ else:
+ # we do not safely own the argument's reference,
+ # but we must make sure it cannot be collected
+ # before we return from the function, so we create
+ # an owned temp reference to it
+ if i > 0: # first argument doesn't matter
+ some_args_in_temps = True
+ arg = arg.coerce_to_temp(env)
self.args[i] = arg
- for i in range(max_nargs, actual_nargs):
+ # handle additional varargs parameters
+ for i in xrange(max_nargs, actual_nargs):
arg = self.args[i]
if arg.type.is_pyobject:
arg_ctype = arg.type.default_coerced_ctype()
error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter")
else:
- self.args[i] = arg.coerce_to(arg_ctype, env)
+ self.args[i] = arg = arg.coerce_to(arg_ctype, env)
+ if arg.is_temp and i > 0:
+ some_args_in_temps = True
+ if some_args_in_temps:
+ # if some args are temps and others are not, they may get
+ # constructed in the wrong order (temps first) => make
+ # sure they are either all temps or all not temps (except
+ # for the last argument, which is evaluated last in any
+ # case)
+ for i in xrange(actual_nargs-1):
+ if i == 0 and self.self is not None:
+ continue # self is ok
+ arg = self.args[i]
+ 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
+ # env (this is safe: a construction would fail in
+ # nogil anyway)
+ pass
+ else:
+ #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)
self.is_temp = 0
self.is_literal = 1
+ def is_simple(self):
+ # 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()
elif self.type.is_complex and self.operand.type.is_complex:
self.operand = self.operand.coerce_to_simple(env)
+ def is_simple(self):
+ # 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
self.operand2.result())
def is_py_operation_types(self, type1, type2):
- return (type1 is PyrexTypes.c_py_unicode_type or
- type2 is PyrexTypes.c_py_unicode_type or
+ return (type1.is_unicode_char or
+ type2.is_unicode_char or
BinopNode.is_py_operation_types(self, type1, type2))
def py_operation_function(self):
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)
return self.operator in ('in', 'not_in') and \
((self.operand1.type.is_int
and (self.operand2.type.is_string or self.operand2.type is bytes_type)) or
- (self.operand1.type is PyrexTypes.c_py_unicode_type
+ (self.operand1.type.is_unicode_char
and self.operand2.type is unicode_type))
def is_ptr_contains(self):
""",
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;
}
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:
return False
return self.arg.may_be_none()
+ def is_simple(self):
+ return self.arg.is_simple()
+
def result_in_temp(self):
return self.arg.result_in_temp()
def may_be_none(self):
return False
+ def is_simple(self):
+ return self.arg.is_simple()
+
def result_in_temp(self):
return self.arg.result_in_temp()
# be specific about some known types
if arg.type.is_string:
self.type = bytes_type
- elif arg.type is PyrexTypes.c_py_unicode_type:
+ elif arg.type.is_unicode_char:
self.type = unicode_type
elif arg.type.is_complex:
self.type = Builtin.complex_type
if hasattr(self.arg, 'entry'):
self.entry = self.arg.entry
+ def is_simple(self):
+ return True # result is always in a temp (or a name)
+
def generate_evaluation_code(self, code):
pass
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;
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],
)