Commit ab17365a authored by Stefan Behnel's avatar Stefan Behnel

merged in latest cython-devel

parents 5c962c3b f30c3a6b
...@@ -289,7 +289,7 @@ class PyObjectConst(object): ...@@ -289,7 +289,7 @@ class PyObjectConst(object):
possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
nice_identifier = re.compile('^[a-zA-Z0-9_]+$').match nice_identifier = re.compile(r'\A[a-zA-Z0-9_]+\Z').match
find_alphanums = re.compile('([a-zA-Z0-9]+)').findall find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
class StringConst(object): class StringConst(object):
......
...@@ -851,12 +851,14 @@ class FloatNode(ConstNode): ...@@ -851,12 +851,14 @@ class FloatNode(ConstNode):
return float(self.value) return float(self.value)
def calculate_result_code(self): def calculate_result_code(self):
strval = repr(float(self.value)) strval = self.value
if strval == 'nan': assert isinstance(strval, (str, unicode))
cmpval = repr(float(strval))
if cmpval == 'nan':
return "(Py_HUGE_VAL * 0)" return "(Py_HUGE_VAL * 0)"
elif strval == 'inf': elif cmpval == 'inf':
return "Py_HUGE_VAL" return "Py_HUGE_VAL"
elif strval == '-inf': elif cmpval == '-inf':
return "(-Py_HUGE_VAL)" return "(-Py_HUGE_VAL)"
else: else:
return strval return strval
...@@ -1903,11 +1905,15 @@ class IndexNode(ExprNode): ...@@ -1903,11 +1905,15 @@ class IndexNode(ExprNode):
return self.base.type_dependencies(env) return self.base.type_dependencies(env)
def infer_type(self, env): def infer_type(self, env):
if isinstance(self.base, (StringNode, UnicodeNode)): # FIXME: BytesNode? if isinstance(self.base, StringNode): # FIXME: BytesNode?
return py_object_type return py_object_type
base_type = self.base.infer_type(env) base_type = self.base.infer_type(env)
if base_type.is_ptr or base_type.is_array: if base_type.is_ptr or base_type.is_array:
return base_type.base_type return base_type.base_type
elif base_type is Builtin.unicode_type:
# Py_UNICODE will automatically coerce to a unicode string
# if required, so this is safe
return PyrexTypes.c_py_unicode_type
else: else:
# TODO: Handle buffers (hopefully without too much redundancy). # TODO: Handle buffers (hopefully without too much redundancy).
return py_object_type return py_object_type
...@@ -1976,15 +1982,16 @@ class IndexNode(ExprNode): ...@@ -1976,15 +1982,16 @@ class IndexNode(ExprNode):
else: else:
self.base.entry.buffer_aux.writable_needed = True self.base.entry.buffer_aux.writable_needed = True
else: else:
base_type = self.base.type
if isinstance(self.index, TupleNode): if isinstance(self.index, TupleNode):
self.index.analyse_types(env, skip_children=skip_child_analysis) self.index.analyse_types(env, skip_children=skip_child_analysis)
elif not skip_child_analysis: elif not skip_child_analysis:
self.index.analyse_types(env) self.index.analyse_types(env)
self.original_index_type = self.index.type self.original_index_type = self.index.type
if self.base.type.is_pyobject: if base_type.is_pyobject:
if self.index.type.is_int: if self.index.type.is_int:
if (not setting if (not setting
and (self.base.type is list_type or self.base.type is tuple_type) and (base_type in (list_type, tuple_type, unicode_type))
and (not self.index.type.signed or isinstance(self.index, IntNode) and int(self.index.value) >= 0) and (not self.index.type.signed or isinstance(self.index, IntNode) and int(self.index.value) >= 0)
and not env.directives['boundscheck']): and not env.directives['boundscheck']):
self.is_temp = 0 self.is_temp = 0
...@@ -1994,10 +2001,15 @@ class IndexNode(ExprNode): ...@@ -1994,10 +2001,15 @@ class IndexNode(ExprNode):
else: else:
self.index = self.index.coerce_to_pyobject(env) self.index = self.index.coerce_to_pyobject(env)
self.is_temp = 1 self.is_temp = 1
self.type = py_object_type if base_type is unicode_type:
# Py_UNICODE will automatically coerce to a unicode string
# if required, so this is safe
self.type = PyrexTypes.c_py_unicode_type
else:
self.type = py_object_type
else: else:
if self.base.type.is_ptr or self.base.type.is_array: if base_type.is_ptr or base_type.is_array:
self.type = self.base.type.base_type self.type = base_type.base_type
if self.index.type.is_pyobject: if self.index.type.is_pyobject:
self.index = self.index.coerce_to( self.index = self.index.coerce_to(
PyrexTypes.c_py_ssize_t_type, env) PyrexTypes.c_py_ssize_t_type, env)
...@@ -2005,10 +2017,10 @@ class IndexNode(ExprNode): ...@@ -2005,10 +2017,10 @@ class IndexNode(ExprNode):
error(self.pos, error(self.pos,
"Invalid index type '%s'" % "Invalid index type '%s'" %
self.index.type) self.index.type)
elif self.base.type.is_cpp_class: elif base_type.is_cpp_class:
function = env.lookup_operator("[]", [self.base, self.index]) function = env.lookup_operator("[]", [self.base, self.index])
if function is None: if function is None:
error(self.pos, "Indexing '%s' not supported for index type '%s'" % (self.base.type, self.index.type)) error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type))
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
self.result_code = "<error>" self.result_code = "<error>"
return return
...@@ -2022,7 +2034,7 @@ class IndexNode(ExprNode): ...@@ -2022,7 +2034,7 @@ class IndexNode(ExprNode):
else: else:
error(self.pos, error(self.pos,
"Attempting to index non-array type '%s'" % "Attempting to index non-array type '%s'" %
self.base.type) base_type)
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
gil_message = "Indexing Python object" gil_message = "Indexing Python object"
...@@ -2051,6 +2063,8 @@ class IndexNode(ExprNode): ...@@ -2051,6 +2063,8 @@ class IndexNode(ExprNode):
return "PyList_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result()) return "PyList_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result())
elif self.base.type is tuple_type: elif self.base.type is tuple_type:
return "PyTuple_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result()) 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:
return "PyUnicode_AS_UNICODE(%s)[%s]" % (self.base.result(), self.index.result())
else: else:
return "(%s[%s])" % ( return "(%s[%s])" % (
self.base.result(), self.index.result()) self.base.result(), self.index.result())
...@@ -2098,34 +2112,51 @@ class IndexNode(ExprNode): ...@@ -2098,34 +2112,51 @@ class IndexNode(ExprNode):
# is_temp is True, so must pull out value and incref it. # is_temp is True, so must pull out value and incref it.
code.putln("%s = *%s;" % (self.result(), self.buffer_ptr_code)) code.putln("%s = *%s;" % (self.result(), self.buffer_ptr_code))
code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result()) code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
elif self.type.is_pyobject and self.is_temp: elif self.is_temp:
if self.index.type.is_int: if self.type.is_pyobject:
index_code = self.index.result() if self.index.type.is_int:
if self.base.type is list_type: index_code = self.index.result()
function = "__Pyx_GetItemInt_List" if self.base.type is list_type:
elif self.base.type is tuple_type: function = "__Pyx_GetItemInt_List"
function = "__Pyx_GetItemInt_Tuple" elif self.base.type is tuple_type:
function = "__Pyx_GetItemInt_Tuple"
else:
function = "__Pyx_GetItemInt"
code.globalstate.use_utility_code(getitem_int_utility_code)
else: else:
function = "__Pyx_GetItemInt" index_code = self.index.py_result()
code.globalstate.use_utility_code(getitem_int_utility_code) if self.base.type is dict_type:
else: function = "__Pyx_PyDict_GetItem"
if self.base.type is dict_type: code.globalstate.use_utility_code(getitem_dict_utility_code)
function = "__Pyx_PyDict_GetItem" else:
code.globalstate.use_utility_code(getitem_dict_utility_code) function = "PyObject_GetItem"
code.putln(
"%s = %s(%s, %s%s); if (!%s) %s" % (
self.result(),
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
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:
code.globalstate.use_utility_code(getitem_int_pyunicode_utility_code)
if self.index.type.is_int:
index_code = self.index.result()
function = "__Pyx_GetItemInt_Unicode"
else: else:
function = "PyObject_GetItem" index_code = self.index.py_result()
index_code = self.index.py_result() function = "__Pyx_GetItemInt_Unicode_Generic"
sign_code = "" code.putln(
code.putln( "%s = %s(%s, %s%s); if (unlikely(%s == (Py_UNICODE)-1)) %s;" % (
"%s = %s(%s, %s%s); if (!%s) %s" % ( self.result(),
self.result(), function,
function, self.base.py_result(),
self.base.py_result(), index_code,
index_code, self.extra_index_params(),
self.extra_index_params(), self.result(),
self.result(), code.error_goto(self.pos)))
code.error_goto(self.pos)))
code.put_gotref(self.py_result())
def generate_setitem_code(self, value_code, code): def generate_setitem_code(self, value_code, code):
if self.index.type.is_int: if self.index.type.is_int:
...@@ -5123,6 +5154,11 @@ class NumBinopNode(BinopNode): ...@@ -5123,6 +5154,11 @@ class NumBinopNode(BinopNode):
self.operand1.result(), self.operand1.result(),
self.operand2.result()) 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
BinopNode.is_py_operation_types(self, type1, type2))
def py_operation_function(self): def py_operation_function(self):
return self.py_functions[self.operator] return self.py_functions[self.operator]
...@@ -6868,6 +6904,38 @@ requires = [raise_noneindex_error_utility_code]) ...@@ -6868,6 +6904,38 @@ requires = [raise_noneindex_error_utility_code])
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
getitem_int_pyunicode_utility_code = UtilityCode(
proto = '''
#define __Pyx_GetItemInt_Unicode(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_GetItemInt_Unicode_Fast(o, i) : \\
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE Py_UNICODE __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i) {
if (likely((0 <= i) & (i < PyUnicode_GET_SIZE(ustring)))) {
return PyUnicode_AS_UNICODE(ustring)[i];
} else if ((-PyUnicode_GET_SIZE(ustring) <= i) & (i < 0)) {
i += PyUnicode_GET_SIZE(ustring);
return PyUnicode_AS_UNICODE(ustring)[i];
} else {
PyErr_SetString(PyExc_IndexError, "string index out of range");
return (Py_UNICODE)-1;
}
}
static CYTHON_INLINE Py_UNICODE __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j) {
PyObject *r;
Py_UNICODE uchar;
if (!j) return (Py_UNICODE)-1;
r = PyObject_GetItem(ustring, j);
Py_DECREF(j);
if (!r) return (Py_UNICODE)-1;
uchar = PyUnicode_AS_UNICODE(r)[0];
Py_DECREF(r);
return uchar;
}
''',
)
getitem_int_utility_code = UtilityCode( getitem_int_utility_code = UtilityCode(
proto = """ proto = """
......
...@@ -2443,6 +2443,9 @@ def spanning_type(type1, type2): ...@@ -2443,6 +2443,9 @@ def spanning_type(type1, type2):
return type1 return type1
elif type1 is py_object_type or type2 is py_object_type: elif type1 is py_object_type or type2 is py_object_type:
return py_object_type return py_object_type
elif type1 is c_py_unicode_type or type2 is c_py_unicode_type:
# Py_UNICODE behaves more like a string than an int
return py_object_type
span_type = _spanning_type(type1, type2) span_type = _spanning_type(type1, type2)
if span_type is None: if span_type is None:
return py_object_type return py_object_type
......
DEF FLOAT = 12.5 DEF FLOAT = 12.5
DEF EFLOAT = 5e-1
DEF FLOAT_NAN = float('nan') DEF FLOAT_NAN = float('nan')
DEF FLOAT_INFP = float('+inf') DEF FLOAT_INFP = float('+inf')
DEF FLOAT_INFN = float('-inf') DEF FLOAT_INFN = float('-inf')
...@@ -20,6 +21,14 @@ def f(): ...@@ -20,6 +21,14 @@ def f():
f = FLOAT f = FLOAT
return f return f
def efloat():
"""
>>> efloat()
0.5
"""
cdef float f = EFLOAT
return f
def nan1(): def nan1():
""" """
>>> nan1() >>> nan1()
......
...@@ -103,6 +103,9 @@ __doc__ = ur""" ...@@ -103,6 +103,9 @@ __doc__ = ur"""
True True
>>> len(u6) >>> len(u6)
7 7
>>> newlines == "Aaa\n"
True
""" """
import sys import sys
...@@ -127,3 +130,5 @@ u3 = ur"abc\x11" ...@@ -127,3 +130,5 @@ u3 = ur"abc\x11"
u4 = Ur"abc\x11" u4 = Ur"abc\x11"
u5 = uR"abc\x11" u5 = uR"abc\x11"
u6 = UR"abc\x11" u6 = UR"abc\x11"
newlines = "Aaa\n"
cimport cython
cdef unicode _ustring = u'azerty123456'
ustring = _ustring
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
def index(unicode ustring, Py_ssize_t i):
"""
>>> index(ustring, 0)
u'a'
>>> index(ustring, 2)
u'e'
>>> index(ustring, -1)
u'6'
>>> index(ustring, -len(ustring))
u'a'
>>> index(ustring, len(ustring))
Traceback (most recent call last):
IndexError: string index out of range
"""
return ustring[i]
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
def index_literal(Py_ssize_t i):
"""
>>> index_literal(0)
u'a'
>>> index_literal(2)
u'e'
>>> index_literal(-1)
u'6'
>>> index_literal(-len('azerty123456'))
u'a'
>>> index_literal(len(ustring))
Traceback (most recent call last):
IndexError: string index out of range
"""
return u'azerty123456'[i]
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
@cython.boundscheck(False)
def index_no_boundscheck(unicode ustring, Py_ssize_t i):
"""
>>> index_no_boundscheck(ustring, 0)
u'a'
>>> index_no_boundscheck(ustring, 2)
u'e'
>>> index_no_boundscheck(ustring, -1)
u'6'
>>> index_no_boundscheck(ustring, len(ustring)-1)
u'6'
>>> index_no_boundscheck(ustring, -len(ustring))
u'a'
"""
return ustring[i]
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
@cython.boundscheck(False)
def unsigned_index_no_boundscheck(unicode ustring, unsigned int i):
"""
>>> unsigned_index_no_boundscheck(ustring, 0)
u'a'
>>> unsigned_index_no_boundscheck(ustring, 2)
u'e'
>>> unsigned_index_no_boundscheck(ustring, len(ustring)-1)
u'6'
"""
return ustring[i]
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode",
"//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
def index_compare(unicode ustring, Py_ssize_t i):
"""
>>> index_compare(ustring, 0)
True
>>> index_compare(ustring, 1)
False
>>> index_compare(ustring, -1)
False
>>> index_compare(ustring, -len(ustring))
True
>>> index_compare(ustring, len(ustring))
Traceback (most recent call last):
IndexError: string index out of range
"""
return ustring[i] == u'a'
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode",
"//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
def index_compare_string(unicode ustring, Py_ssize_t i, unicode other):
"""
>>> index_compare_string(ustring, 0, ustring[0])
True
>>> index_compare_string(ustring, 0, ustring[:4])
False
>>> index_compare_string(ustring, 1, ustring[0])
False
>>> index_compare_string(ustring, 1, ustring[1])
True
>>> index_compare_string(ustring, -1, ustring[0])
False
>>> index_compare_string(ustring, -1, ustring[-1])
True
>>> index_compare_string(ustring, -len(ustring), ustring[-len(ustring)])
True
>>> index_compare_string(ustring, len(ustring), ustring)
Traceback (most recent call last):
IndexError: string index out of range
"""
return ustring[i] == other
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode",
"//MulNode",
"//MulNode/CoerceToPyTypeNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
def index_multiply(unicode ustring, Py_ssize_t i, int mul):
"""
>>> ustring[0] * 5
u'aaaaa'
>>> index_multiply(ustring, 0, 5)
u'aaaaa'
"""
return ustring[i] * mul
@cython.test_assert_path_exists("//CoerceToPyTypeNode",
"//IndexNode",
"//AddNode",
"//AddNode/CoerceToPyTypeNode")
@cython.test_fail_if_path_exists("//IndexNode//CoerceToPyTypeNode")
def index_add(unicode ustring, Py_ssize_t i, Py_ssize_t j):
"""
>>> ustring[0] + ustring[-1]
u'a6'
>>> index_add(ustring, 0, -1)
u'a6'
"""
return ustring[i] + ustring[j]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment