Commit 4964e6d8 authored by Craig Citro's avatar Craig Citro

merge

parents 13d0f030 6d56f108
...@@ -723,8 +723,8 @@ typedef struct { ...@@ -723,8 +723,8 @@ typedef struct {
} __Pyx_BufFmt_StackElem; } __Pyx_BufFmt_StackElem;
static CYTHON_INLINE int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack);
static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info); static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info);
static int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack);
""", impl=""" """, impl="""
static CYTHON_INLINE int __Pyx_IsLittleEndian(void) { static CYTHON_INLINE int __Pyx_IsLittleEndian(void) {
unsigned int n = 1; unsigned int n = 1;
...@@ -1131,7 +1131,7 @@ static CYTHON_INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) { ...@@ -1131,7 +1131,7 @@ static CYTHON_INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) {
buf->suboffsets = __Pyx_minusones; buf->suboffsets = __Pyx_minusones;
} }
static int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack) { static CYTHON_INLINE int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack) {
if (obj == Py_None) { if (obj == Py_None) {
__Pyx_ZeroBuffer(buf); __Pyx_ZeroBuffer(buf);
return 0; return 0;
......
...@@ -3440,8 +3440,6 @@ class SequenceNode(ExprNode): ...@@ -3440,8 +3440,6 @@ class SequenceNode(ExprNode):
# allocates the temps in a rather hacky way -- the assignment # allocates the temps in a rather hacky way -- the assignment
# is evaluated twice, within each if-block. # is evaluated twice, within each if-block.
code.globalstate.use_utility_code(unpacking_utility_code)
if rhs.type is tuple_type: if rhs.type is tuple_type:
tuple_check = "likely(%s != Py_None)" tuple_check = "likely(%s != Py_None)"
else: else:
...@@ -3477,6 +3475,8 @@ class SequenceNode(ExprNode): ...@@ -3477,6 +3475,8 @@ class SequenceNode(ExprNode):
rhs.py_result(), len(self.args))) rhs.py_result(), len(self.args)))
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
else: else:
code.globalstate.use_utility_code(unpacking_utility_code)
self.iterator.allocate(code) self.iterator.allocate(code)
code.putln( code.putln(
"%s = PyObject_GetIter(%s); %s" % ( "%s = PyObject_GetIter(%s); %s" % (
......
...@@ -2025,7 +2025,7 @@ class DefNode(FuncDefNode): ...@@ -2025,7 +2025,7 @@ class DefNode(FuncDefNode):
def declare_python_arg(self, env, arg): def declare_python_arg(self, env, arg):
if arg: if arg:
if env.directives['infer_types'] != 'none': if env.directives['infer_types'] != False:
type = PyrexTypes.unspecified_type type = PyrexTypes.unspecified_type
else: else:
type = py_object_type type = py_object_type
...@@ -2441,7 +2441,7 @@ class DefNode(FuncDefNode): ...@@ -2441,7 +2441,7 @@ class DefNode(FuncDefNode):
# it looks funny to separate the init-to-0 from setting the # it looks funny to separate the init-to-0 from setting the
# default value, but C89 needs this # default value, but C89 needs this
code.putln("PyObject* values[%d] = {%s};" % ( code.putln("PyObject* values[%d] = {%s};" % (
max_args, ','.join(['0']*max_args))) max_args, ','.join('0'*max_args)))
for i, default_value in default_args: for i, default_value in default_args:
code.putln('values[%d] = %s;' % (i, default_value)) code.putln('values[%d] = %s;' % (i, default_value))
...@@ -3447,11 +3447,15 @@ class PrintStatNode(StatNode): ...@@ -3447,11 +3447,15 @@ class PrintStatNode(StatNode):
# print statement # print statement
# #
# arg_tuple TupleNode # arg_tuple TupleNode
# stream ExprNode or None (stdout)
# append_newline boolean # append_newline boolean
child_attrs = ["arg_tuple"] child_attrs = ["arg_tuple", "stream"]
def analyse_expressions(self, env): def analyse_expressions(self, env):
if self.stream:
self.stream.analyse_expressions(env)
self.stream = self.stream.coerce_to_pyobject(env)
self.arg_tuple.analyse_expressions(env) self.arg_tuple.analyse_expressions(env)
self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env) self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
env.use_utility_code(printing_utility_code) env.use_utility_code(printing_utility_code)
...@@ -3462,12 +3466,18 @@ class PrintStatNode(StatNode): ...@@ -3462,12 +3466,18 @@ class PrintStatNode(StatNode):
gil_message = "Python print statement" gil_message = "Python print statement"
def generate_execution_code(self, code): def generate_execution_code(self, code):
if self.stream:
self.stream.generate_evaluation_code(code)
stream_result = self.stream.py_result()
else:
stream_result = '0'
if len(self.arg_tuple.args) == 1 and self.append_newline: if len(self.arg_tuple.args) == 1 and self.append_newline:
arg = self.arg_tuple.args[0] arg = self.arg_tuple.args[0]
arg.generate_evaluation_code(code) arg.generate_evaluation_code(code)
code.putln( code.putln(
"if (__Pyx_PrintOne(%s) < 0) %s" % ( "if (__Pyx_PrintOne(%s, %s) < 0) %s" % (
stream_result,
arg.py_result(), arg.py_result(),
code.error_goto(self.pos))) code.error_goto(self.pos)))
arg.generate_disposal_code(code) arg.generate_disposal_code(code)
...@@ -3475,14 +3485,21 @@ class PrintStatNode(StatNode): ...@@ -3475,14 +3485,21 @@ class PrintStatNode(StatNode):
else: else:
self.arg_tuple.generate_evaluation_code(code) self.arg_tuple.generate_evaluation_code(code)
code.putln( code.putln(
"if (__Pyx_Print(%s, %d) < 0) %s" % ( "if (__Pyx_Print(%s, %s, %d) < 0) %s" % (
stream_result,
self.arg_tuple.py_result(), self.arg_tuple.py_result(),
self.append_newline, self.append_newline,
code.error_goto(self.pos))) code.error_goto(self.pos)))
self.arg_tuple.generate_disposal_code(code) self.arg_tuple.generate_disposal_code(code)
self.arg_tuple.free_temps(code) self.arg_tuple.free_temps(code)
if self.stream:
self.stream.generate_disposal_code(code)
self.stream.free_temps(code)
def annotate(self, code): def annotate(self, code):
if self.stream:
self.stream.annotate(code)
self.arg_tuple.annotate(code) self.arg_tuple.annotate(code)
...@@ -5028,12 +5045,18 @@ else: ...@@ -5028,12 +5045,18 @@ else:
printing_utility_code = UtilityCode( printing_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_Print(PyObject *, int); /*proto*/ static int __Pyx_Print(PyObject*, PyObject *, int); /*proto*/
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
static PyObject* %s = 0; static PyObject* %s = 0;
static PyObject* %s = 0; static PyObject* %s = 0;
#endif #endif
""" % (Naming.print_function, Naming.print_function_kwargs), """ % (Naming.print_function, Naming.print_function_kwargs),
cleanup = """
#if PY_MAJOR_VERSION >= 3
Py_CLEAR(%s);
Py_CLEAR(%s);
#endif
""" % (Naming.print_function, Naming.print_function_kwargs),
impl = r""" impl = r"""
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
static PyObject *__Pyx_GetStdout(void) { static PyObject *__Pyx_GetStdout(void) {
...@@ -5044,13 +5067,14 @@ static PyObject *__Pyx_GetStdout(void) { ...@@ -5044,13 +5067,14 @@ static PyObject *__Pyx_GetStdout(void) {
return f; return f;
} }
static int __Pyx_Print(PyObject *arg_tuple, int newline) { static int __Pyx_Print(PyObject* f, PyObject *arg_tuple, int newline) {
PyObject *f;
PyObject* v; PyObject* v;
int i; int i;
if (!f) {
if (!(f = __Pyx_GetStdout())) if (!(f = __Pyx_GetStdout()))
return -1; return -1;
}
for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) { for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) {
if (PyFile_SoftSpace(f, 1)) { if (PyFile_SoftSpace(f, 1)) {
if (PyFile_WriteString(" ", f) < 0) if (PyFile_WriteString(" ", f) < 0)
...@@ -5078,7 +5102,7 @@ static int __Pyx_Print(PyObject *arg_tuple, int newline) { ...@@ -5078,7 +5102,7 @@ static int __Pyx_Print(PyObject *arg_tuple, int newline) {
#else /* Python 3 has a print function */ #else /* Python 3 has a print function */
static int __Pyx_Print(PyObject *arg_tuple, int newline) { static int __Pyx_Print(PyObject* stream, PyObject *arg_tuple, int newline) {
PyObject* kwargs = 0; PyObject* kwargs = 0;
PyObject* result = 0; PyObject* result = 0;
PyObject* end_string; PyObject* end_string;
...@@ -5087,27 +5111,43 @@ static int __Pyx_Print(PyObject *arg_tuple, int newline) { ...@@ -5087,27 +5111,43 @@ static int __Pyx_Print(PyObject *arg_tuple, int newline) {
if (!%(PRINT_FUNCTION)s) if (!%(PRINT_FUNCTION)s)
return -1; return -1;
} }
if (stream) {
kwargs = PyDict_New();
if (unlikely(!kwargs))
return -1;
if (unlikely(PyDict_SetItemString(kwargs, "file", stream) < 0))
goto bad;
}
}
if (!newline) { if (!newline) {
if (!%(PRINT_KWARGS)s) { if (!kwargs)
kwargs = %(PRINT_KWARGS)s;
if (!kwargs) {
%(PRINT_KWARGS)s = PyDict_New(); %(PRINT_KWARGS)s = PyDict_New();
if (!%(PRINT_KWARGS)s) if unlikely((!%(PRINT_KWARGS)s))
return -1; return -1;
kwargs = %(PRINT_KWARGS)s;
}
end_string = PyUnicode_FromStringAndSize(" ", 1); end_string = PyUnicode_FromStringAndSize(" ", 1);
if (!end_string) if (unlikely(!end_string))
return -1; goto bad;
if (PyDict_SetItemString(%(PRINT_KWARGS)s, "end", end_string) < 0) { if (PyDict_SetItemString(%(PRINT_KWARGS)s, "end", end_string) < 0) {
Py_DECREF(end_string); Py_DECREF(end_string);
return -1; goto bad;
} }
Py_DECREF(end_string); Py_DECREF(end_string);
} }
kwargs = %(PRINT_KWARGS)s;
}
result = PyObject_Call(%(PRINT_FUNCTION)s, arg_tuple, kwargs); result = PyObject_Call(%(PRINT_FUNCTION)s, arg_tuple, kwargs);
if (unlikely(kwargs) && (kwargs != %(PRINT_FUNCTION)s))
Py_DECREF(kwargs);
if (!result) if (!result)
return -1; return -1;
Py_DECREF(result); Py_DECREF(result);
return 0; return 0;
bad:
if (kwargs != %(PRINT_FUNCTION)s)
Py_XDECREF(kwargs);
return -1;
} }
#endif #endif
...@@ -5119,15 +5159,16 @@ static int __Pyx_Print(PyObject *arg_tuple, int newline) { ...@@ -5119,15 +5159,16 @@ static int __Pyx_Print(PyObject *arg_tuple, int newline) {
printing_one_utility_code = UtilityCode( printing_one_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_PrintOne(PyObject *o); /*proto*/ static int __Pyx_PrintOne(PyObject* stream, PyObject *o); /*proto*/
""", """,
impl = r""" impl = r"""
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
static int __Pyx_PrintOne(PyObject *o) { static int __Pyx_PrintOne(PyObject* f, PyObject *o) {
PyObject *f; if (!f) {
if (!(f = __Pyx_GetStdout())) if (!(f = __Pyx_GetStdout()))
return -1; return -1;
}
if (PyFile_SoftSpace(f, 0)) { if (PyFile_SoftSpace(f, 0)) {
if (PyFile_WriteString(" ", f) < 0) if (PyFile_WriteString(" ", f) < 0)
return -1; return -1;
...@@ -5139,19 +5180,19 @@ static int __Pyx_PrintOne(PyObject *o) { ...@@ -5139,19 +5180,19 @@ static int __Pyx_PrintOne(PyObject *o) {
return 0; return 0;
/* the line below is just to avoid compiler /* the line below is just to avoid compiler
* compiler warnings about unused functions */ * compiler warnings about unused functions */
return __Pyx_Print(NULL, 0); return __Pyx_Print(f, NULL, 0);
} }
#else /* Python 3 has a print function */ #else /* Python 3 has a print function */
static int __Pyx_PrintOne(PyObject *o) { static int __Pyx_PrintOne(PyObject* stream, PyObject *o) {
int res; int res;
PyObject* arg_tuple = PyTuple_New(1); PyObject* arg_tuple = PyTuple_New(1);
if (unlikely(!arg_tuple)) if (unlikely(!arg_tuple))
return -1; return -1;
Py_INCREF(o); Py_INCREF(o);
PyTuple_SET_ITEM(arg_tuple, 0, o); PyTuple_SET_ITEM(arg_tuple, 0, o);
res = __Pyx_Print(arg_tuple, 1); res = __Pyx_Print(stream, arg_tuple, 1);
Py_DECREF(arg_tuple); Py_DECREF(arg_tuple);
return res; return res;
} }
......
...@@ -1121,6 +1121,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1121,6 +1121,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
exception_check = True) exception_check = True)
def _handle_simple_function_float(self, node, pos_args): def _handle_simple_function_float(self, node, pos_args):
"""Transform float() into either a C type cast or a faster C
function call.
"""
# Note: this requires the float() function to be typed as # Note: this requires the float() function to be typed as
# returning a C 'double' # returning a C 'double'
if len(pos_args) != 1: if len(pos_args) != 1:
...@@ -1158,6 +1161,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1158,6 +1161,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
]) ])
def _handle_simple_function_getattr(self, node, pos_args): def _handle_simple_function_getattr(self, node, pos_args):
"""Replace 2/3 argument forms of getattr() by C-API calls.
"""
if len(pos_args) == 2: if len(pos_args) == 2:
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, "PyObject_GetAttr", self.PyObject_GetAttr2_func_type, node.pos, "PyObject_GetAttr", self.PyObject_GetAttr2_func_type,
...@@ -1185,6 +1190,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1185,6 +1190,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
]) ])
def _handle_simple_function_iter(self, node, pos_args): def _handle_simple_function_iter(self, node, pos_args):
"""Replace 1/2 argument forms of iter() by C-API calls.
"""
if len(pos_args) == 1: if len(pos_args) == 1:
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, "PyObject_GetIter", self.PyObject_GetIter_func_type, node.pos, "PyObject_GetIter", self.PyObject_GetIter_func_type,
...@@ -1205,6 +1212,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1205,6 +1212,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
]) ])
def _handle_simple_function_len(self, node, pos_args): def _handle_simple_function_len(self, node, pos_args):
"""Replace len(char*) by the equivalent call to strlen().
"""
if len(pos_args) != 1: if len(pos_args) != 1:
self._error_wrong_arg_count('len', node, pos_args, 1) self._error_wrong_arg_count('len', node, pos_args, 1)
return node return node
...@@ -1234,6 +1243,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1234,6 +1243,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
]) ])
def _handle_simple_function_type(self, node, pos_args): def _handle_simple_function_type(self, node, pos_args):
"""Replace type(o) by a macro call to Py_TYPE(o).
"""
if len(pos_args) != 1: if len(pos_args) != 1:
return node return node
node = ExprNodes.PythonCapiCallNode( node = ExprNodes.PythonCapiCallNode(
...@@ -1298,7 +1309,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1298,7 +1309,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
]) ])
def _handle_simple_method_object_append(self, node, args, is_unbound_method): def _handle_simple_method_object_append(self, node, args, is_unbound_method):
# X.append() is almost always referring to a list """Optimistic optimisation as X.append() is almost always
referring to a list.
"""
if len(args) != 2: if len(args) != 2:
return node return node
...@@ -1321,7 +1334,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1321,7 +1334,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
]) ])
def _handle_simple_method_object_pop(self, node, args, is_unbound_method): def _handle_simple_method_object_pop(self, node, args, is_unbound_method):
# X.pop([n]) is almost always referring to a list """Optimistic optimisation as X.pop([n]) is almost always
referring to a list.
"""
if len(args) == 1: if len(args) == 1:
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_PyObject_Pop", self.PyObject_Pop_func_type, node.pos, "__Pyx_PyObject_Pop", self.PyObject_Pop_func_type,
...@@ -1351,6 +1366,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1351,6 +1366,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
exception_value = "-1") exception_value = "-1")
def _handle_simple_method_list_append(self, node, args, is_unbound_method): def _handle_simple_method_list_append(self, node, args, is_unbound_method):
"""Call PyList_Append() instead of l.append().
"""
if len(args) != 2: if len(args) != 2:
self._error_wrong_arg_count('list.append', node, args, 2) self._error_wrong_arg_count('list.append', node, args, 2)
return node return node
...@@ -1365,6 +1382,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1365,6 +1382,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
exception_value = "-1") exception_value = "-1")
def _handle_simple_method_list_sort(self, node, args, is_unbound_method): def _handle_simple_method_list_sort(self, node, args, is_unbound_method):
"""Call PyList_Sort() instead of the 0-argument l.sort().
"""
if len(args) != 1: if len(args) != 1:
return node return node
return self._substitute_method_call( return self._substitute_method_call(
...@@ -1372,6 +1391,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1372,6 +1391,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
'sort', is_unbound_method, args) 'sort', is_unbound_method, args)
def _handle_simple_method_list_reverse(self, node, args, is_unbound_method): def _handle_simple_method_list_reverse(self, node, args, is_unbound_method):
"""Call PyList_Reverse() instead of l.reverse().
"""
if len(args) != 1: if len(args) != 1:
self._error_wrong_arg_count('list.reverse', node, args, 1) self._error_wrong_arg_count('list.reverse', node, args, 1)
return node return node
...@@ -1388,6 +1409,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1388,6 +1409,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
exception_value = "NULL") exception_value = "NULL")
def _handle_simple_method_dict_get(self, node, args, is_unbound_method): def _handle_simple_method_dict_get(self, node, args, is_unbound_method):
"""Replace dict.get() by a call to PyDict_GetItem().
"""
if len(args) == 2: if len(args) == 2:
args.append(ExprNodes.NoneNode(node.pos)) args.append(ExprNodes.NoneNode(node.pos))
elif len(args) != 3: elif len(args) != 3:
...@@ -1420,6 +1443,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1420,6 +1443,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
for name in _special_encodings ] for name in _special_encodings ]
def _handle_simple_method_unicode_encode(self, node, args, is_unbound_method): def _handle_simple_method_unicode_encode(self, node, args, is_unbound_method):
"""Replace unicode.encode(...) by a direct C-API call to the
corresponding codec.
"""
if len(args) < 1 or len(args) > 3: if len(args) < 1 or len(args) > 3:
self._error_wrong_arg_count('unicode.encode', node, args, '1-3') self._error_wrong_arg_count('unicode.encode', node, args, '1-3')
return node return node
...@@ -1485,6 +1511,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1485,6 +1511,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
exception_value = "NULL") exception_value = "NULL")
def _handle_simple_method_bytes_decode(self, node, args, is_unbound_method): def _handle_simple_method_bytes_decode(self, node, args, is_unbound_method):
"""Replace char*.decode() by a direct C-API call to the
corresponding codec, possibly resoving a slice on the char*.
"""
if len(args) < 1 or len(args) > 3: if len(args) < 1 or len(args) > 3:
self._error_wrong_arg_count('bytes.decode', node, args, '1-3') self._error_wrong_arg_count('bytes.decode', node, args, '1-3')
return node return node
......
...@@ -242,6 +242,231 @@ class PostParse(CythonTransform): ...@@ -242,6 +242,231 @@ class PostParse(CythonTransform):
self.context.nonfatal_error(e) self.context.nonfatal_error(e)
return None return None
# Split parallel assignments (a,b = b,a) into separate partial
# assignments that are executed rhs-first using temps. This
# optimisation is best applied before type analysis so that known
# types on rhs and lhs can be matched directly.
def visit_SingleAssignmentNode(self, node):
self.visitchildren(node)
return self._visit_assignment_node(node, [node.lhs, node.rhs])
def visit_CascadedAssignmentNode(self, node):
self.visitchildren(node)
return self._visit_assignment_node(node, node.lhs_list + [node.rhs])
def _visit_assignment_node(self, node, expr_list):
"""Flatten parallel assignments into separate single
assignments or cascaded assignments.
"""
if sum([ 1 for expr in expr_list if expr.is_sequence_constructor ]) < 2:
# no parallel assignments => nothing to do
return node
expr_list_list = []
flatten_parallel_assignments(expr_list, expr_list_list)
temp_refs = []
eliminate_rhs_duplicates(expr_list_list, temp_refs)
nodes = []
for expr_list in expr_list_list:
lhs_list = expr_list[:-1]
rhs = expr_list[-1]
if len(lhs_list) == 1:
node = Nodes.SingleAssignmentNode(rhs.pos,
lhs = lhs_list[0], rhs = rhs)
else:
node = Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = lhs_list, rhs = rhs)
nodes.append(node)
if len(nodes) == 1:
assign_node = nodes[0]
else:
assign_node = Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
if temp_refs:
duplicates_and_temps = [ (temp.expression, temp)
for temp in temp_refs ]
sort_common_subsequences(duplicates_and_temps)
for _, temp_ref in duplicates_and_temps[::-1]:
assign_node = LetNode(temp_ref, assign_node)
return assign_node
def eliminate_rhs_duplicates(expr_list_list, ref_node_sequence):
"""Replace rhs items by LetRefNodes if they appear more than once.
Creates a sequence of LetRefNodes that set up the required temps
and appends them to ref_node_sequence. The input list is modified
in-place.
"""
seen_nodes = set()
ref_nodes = {}
def find_duplicates(node):
if node.is_literal or node.is_name:
# no need to replace those; can't include attributes here
# as their access is not necessarily side-effect free
return
if node in seen_nodes:
if node not in ref_nodes:
ref_node = LetRefNode(node)
ref_nodes[node] = ref_node
ref_node_sequence.append(ref_node)
else:
seen_nodes.add(node)
if node.is_sequence_constructor:
for item in node.args:
find_duplicates(item)
for expr_list in expr_list_list:
rhs = expr_list[-1]
find_duplicates(rhs)
if not ref_nodes:
return
def substitute_nodes(node):
if node in ref_nodes:
return ref_nodes[node]
elif node.is_sequence_constructor:
node.args = map(substitute_nodes, node.args)
return node
# replace nodes inside of the common subexpressions
for node in ref_nodes:
if node.is_sequence_constructor:
node.args = map(substitute_nodes, node.args)
# replace common subexpressions on all rhs items
for expr_list in expr_list_list:
expr_list[-1] = substitute_nodes(expr_list[-1])
def sort_common_subsequences(items):
"""Sort items/subsequences so that all items and subsequences that
an item contains appear before the item itself. This implies a
partial order, and the sort must be stable to preserve the
original order as much as possible, so we use a simple insertion
sort.
"""
def contains(seq, x):
for item in seq:
if item is x:
return True
elif item.is_sequence_constructor and contains(item.args, x):
return True
return False
def lower_than(a,b):
return b.is_sequence_constructor and contains(b.args, a)
for pos, item in enumerate(items):
new_pos = pos
key = item[0]
for i in xrange(pos-1, -1, -1):
if lower_than(key, items[i][0]):
new_pos = i
if new_pos != pos:
for i in xrange(pos, new_pos, -1):
items[i] = items[i-1]
items[new_pos] = item
def flatten_parallel_assignments(input, output):
# The input is a list of expression nodes, representing the LHSs
# and RHS of one (possibly cascaded) assignment statement. For
# sequence constructors, rearranges the matching parts of both
# sides into a list of equivalent assignments between the
# individual elements. This transformation is applied
# recursively, so that nested structures get matched as well.
rhs = input[-1]
if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
output.append(input)
return
complete_assignments = []
rhs_size = len(rhs.args)
lhs_targets = [ [] for _ in xrange(rhs_size) ]
starred_assignments = []
for lhs in input[:-1]:
if not lhs.is_sequence_constructor:
if lhs.is_starred:
error(lhs.pos, "starred assignment target must be in a list or tuple")
complete_assignments.append(lhs)
continue
lhs_size = len(lhs.args)
starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
if starred_targets > 1:
error(lhs.pos, "more than 1 starred expression in assignment")
output.append([lhs,rhs])
continue
elif lhs_size - starred_targets > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
elif starred_targets:
map_starred_assignment(lhs_targets, starred_assignments,
lhs.args, rhs.args)
elif lhs_size < rhs_size:
error(lhs.pos, "too many values to unpack (expected %d, got %d)"
% (lhs_size, rhs_size))
output.append([lhs,rhs])
continue
else:
for targets, expr in zip(lhs_targets, lhs.args):
targets.append(expr)
if complete_assignments:
complete_assignments.append(rhs)
output.append(complete_assignments)
# recursively flatten partial assignments
for cascade, rhs in zip(lhs_targets, rhs.args):
if cascade:
cascade.append(rhs)
flatten_parallel_assignments(cascade, output)
# recursively flatten starred assignments
for cascade in starred_assignments:
if cascade[0].is_sequence_constructor:
flatten_parallel_assignments(cascade, output)
else:
output.append(cascade)
def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
# Appends the fixed-position LHS targets to the target list that
# appear left and right of the starred argument.
#
# The starred_assignments list receives a new tuple
# (lhs_target, rhs_values_list) that maps the remaining arguments
# (those that match the starred target) to a list.
# left side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
if expr.is_starred:
starred = i
lhs_remaining = len(lhs_args) - i - 1
break
targets.append(expr)
else:
raise InternalError("no starred arg found when splitting starred assignment")
# right side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
lhs_args[-lhs_remaining:])):
targets.append(expr)
# the starred target itself, must be assigned a (potentially empty) list
target = lhs_args[starred].target # unpack starred node
starred_rhs = rhs_args[starred:]
if lhs_remaining:
starred_rhs = starred_rhs[:-lhs_remaining]
if starred_rhs:
pos = starred_rhs[0].pos
else:
pos = target.pos
starred_assignments.append([
target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
class PxdPostParse(CythonTransform, SkipDeclarations): class PxdPostParse(CythonTransform, SkipDeclarations):
""" """
Basic interpretation/validity checking that should only be Basic interpretation/validity checking that should only be
......
...@@ -59,8 +59,6 @@ cpdef p_testlist(PyrexScanner s) ...@@ -59,8 +59,6 @@ cpdef p_testlist(PyrexScanner s)
# #
#------------------------------------------------------- #-------------------------------------------------------
cpdef flatten_parallel_assignments(input, output)
cpdef p_global_statement(PyrexScanner s) cpdef p_global_statement(PyrexScanner s)
cpdef p_expression_or_assignment(PyrexScanner s) cpdef p_expression_or_assignment(PyrexScanner s)
cpdef p_print_statement(PyrexScanner s) cpdef p_print_statement(PyrexScanner s)
......
...@@ -917,138 +917,29 @@ def p_expression_or_assignment(s): ...@@ -917,138 +917,29 @@ def p_expression_or_assignment(s):
return Nodes.PassStatNode(expr.pos) return Nodes.PassStatNode(expr.pos)
else: else:
return Nodes.ExprStatNode(expr.pos, expr = expr) return Nodes.ExprStatNode(expr.pos, expr = expr)
else:
expr_list_list = []
flatten_parallel_assignments(expr_list, expr_list_list)
nodes = []
for expr_list in expr_list_list:
lhs_list = expr_list[:-1]
rhs = expr_list[-1]
if len(lhs_list) == 1:
node = Nodes.SingleAssignmentNode(rhs.pos,
lhs = lhs_list[0], rhs = rhs)
else:
node = Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = lhs_list, rhs = rhs)
nodes.append(node)
if len(nodes) == 1:
return nodes[0]
else:
return Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
def flatten_parallel_assignments(input, output):
# The input is a list of expression nodes, representing the LHSs
# and RHS of one (possibly cascaded) assignment statement. For
# sequence constructors, rearranges the matching parts of both
# sides into a list of equivalent assignments between the
# individual elements. This transformation is applied
# recursively, so that nested structures get matched as well.
rhs = input[-1]
if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
output.append(input)
return
complete_assignments = []
rhs_size = len(rhs.args)
lhs_targets = [ [] for _ in range(rhs_size) ]
starred_assignments = []
for lhs in input[:-1]:
if not lhs.is_sequence_constructor:
if lhs.is_starred:
error(lhs.pos, "starred assignment target must be in a list or tuple")
complete_assignments.append(lhs)
continue
lhs_size = len(lhs.args)
starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
if starred_targets:
if starred_targets > 1:
error(lhs.pos, "more than 1 starred expression in assignment")
output.append([lhs,rhs])
continue
elif lhs_size - starred_targets > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
map_starred_assignment(lhs_targets, starred_assignments,
lhs.args, rhs.args)
else:
if lhs_size > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
elif lhs_size < rhs_size:
error(lhs.pos, "too many values to unpack (expected %d, got %d)"
% (lhs_size, rhs_size))
output.append([lhs,rhs])
continue
else:
for targets, expr in zip(lhs_targets, lhs.args):
targets.append(expr)
if complete_assignments:
complete_assignments.append(rhs)
output.append(complete_assignments)
# recursively flatten partial assignments
for cascade, rhs in zip(lhs_targets, rhs.args):
if cascade:
cascade.append(rhs)
flatten_parallel_assignments(cascade, output)
# recursively flatten starred assignments
for cascade in starred_assignments:
if cascade[0].is_sequence_constructor:
flatten_parallel_assignments(cascade, output)
else:
output.append(cascade)
def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
# Appends the fixed-position LHS targets to the target list that
# appear left and right of the starred argument.
#
# The starred_assignments list receives a new tuple
# (lhs_target, rhs_values_list) that maps the remaining arguments
# (those that match the starred target) to a list.
# left side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
if expr.is_starred:
starred = i
lhs_remaining = len(lhs_args) - i - 1
break
targets.append(expr)
else:
raise InternalError("no starred arg found when splitting starred assignment")
# right side of the starred target rhs = expr_list[-1]
for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:], if len(expr_list) == 2:
lhs_args[-lhs_remaining:])): return Nodes.SingleAssignmentNode(rhs.pos,
targets.append(expr) lhs = expr_list[0], rhs = rhs)
# the starred target itself, must be assigned a (potentially empty) list
target = lhs_args[starred].target # unpack starred node
starred_rhs = rhs_args[starred:]
if lhs_remaining:
starred_rhs = starred_rhs[:-lhs_remaining]
if starred_rhs:
pos = starred_rhs[0].pos
else: else:
pos = target.pos return Nodes.CascadedAssignmentNode(rhs.pos,
starred_assignments.append([ lhs_list = expr_list[:-1], rhs = rhs)
target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
def p_print_statement(s): def p_print_statement(s):
# s.sy == 'print' # s.sy == 'print'
pos = s.position() pos = s.position()
ends_with_comma = 0
s.next() s.next()
if s.sy == '>>': if s.sy == '>>':
s.error("'print >>' not yet implemented") s.next()
stream = p_simple_expr(s)
if s.sy == ',':
s.next()
ends_with_comma = s.sy in ('NEWLINE', 'EOF')
else:
stream = None
args = [] args = []
ends_with_comma = 0
if s.sy not in ('NEWLINE', 'EOF'): if s.sy not in ('NEWLINE', 'EOF'):
args.append(p_simple_expr(s)) args.append(p_simple_expr(s))
while s.sy == ',': while s.sy == ',':
...@@ -1059,7 +950,8 @@ def p_print_statement(s): ...@@ -1059,7 +950,8 @@ def p_print_statement(s):
args.append(p_simple_expr(s)) args.append(p_simple_expr(s))
arg_tuple = ExprNodes.TupleNode(pos, args = args) arg_tuple = ExprNodes.TupleNode(pos, args = args)
return Nodes.PrintStatNode(pos, return Nodes.PrintStatNode(pos,
arg_tuple = arg_tuple, append_newline = not ends_with_comma) arg_tuple = arg_tuple, stream = stream,
append_newline = not ends_with_comma)
def p_exec_statement(s): def p_exec_statement(s):
# s.sy == 'exec' # s.sy == 'exec'
......
...@@ -164,13 +164,13 @@ class PyrexType(BaseType): ...@@ -164,13 +164,13 @@ class PyrexType(BaseType):
return 1 return 1
def create_typedef_type(cname, base_type, is_external=0): def create_typedef_type(name, base_type, cname, is_external=0):
if base_type.is_complex: if base_type.is_complex:
if is_external: if is_external:
raise ValueError("Complex external typedefs not supported") raise ValueError("Complex external typedefs not supported")
return base_type return base_type
else: else:
return CTypedefType(cname, base_type, is_external) return CTypedefType(name, base_type, cname, is_external)
class CTypedefType(BaseType): class CTypedefType(BaseType):
# #
...@@ -180,6 +180,7 @@ class CTypedefType(BaseType): ...@@ -180,6 +180,7 @@ class CTypedefType(BaseType):
# HERE IS DELEGATED! # HERE IS DELEGATED!
# #
# qualified_name string # qualified_name string
# typedef_name string
# typedef_cname string # typedef_cname string
# typedef_base_type PyrexType # typedef_base_type PyrexType
# typedef_is_external bool # typedef_is_external bool
...@@ -191,8 +192,9 @@ class CTypedefType(BaseType): ...@@ -191,8 +192,9 @@ class CTypedefType(BaseType):
from_py_utility_code = None from_py_utility_code = None
def __init__(self, cname, base_type, is_external=0): def __init__(self, name, base_type, cname, is_external=0):
assert not base_type.is_complex assert not base_type.is_complex
self.typedef_name = name
self.typedef_cname = cname self.typedef_cname = cname
self.typedef_base_type = base_type self.typedef_base_type = base_type
self.typedef_is_external = is_external self.typedef_is_external = is_external
...@@ -214,19 +216,12 @@ class CTypedefType(BaseType): ...@@ -214,19 +216,12 @@ class CTypedefType(BaseType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
name = self.declaration_name(for_display, pyrex)
if pyrex or for_display: if pyrex or for_display:
base_code = name base_code = self.typedef_name
else: else:
base_code = public_decl(name, dll_linkage) base_code = public_decl(self.typedef_cname, dll_linkage)
return self.base_declaration_code(base_code, entity_code) return self.base_declaration_code(base_code, entity_code)
def declaration_name(self, for_display = 0, pyrex = 0):
if pyrex or for_display:
return self.qualified_name
else:
return self.typedef_cname
def as_argument_type(self): def as_argument_type(self):
return self return self
...@@ -242,7 +237,7 @@ class CTypedefType(BaseType): ...@@ -242,7 +237,7 @@ class CTypedefType(BaseType):
return "<CTypedefType %s>" % self.typedef_cname return "<CTypedefType %s>" % self.typedef_cname
def __str__(self): def __str__(self):
return self.declaration_name(for_display = 1) return self.typedef_name
def _create_utility_code(self, template_utility_code, def _create_utility_code(self, template_utility_code,
template_function_name): template_function_name):
......
...@@ -359,7 +359,8 @@ class Scope(object): ...@@ -359,7 +359,8 @@ class Scope(object):
else: else:
cname = self.mangle(Naming.type_prefix, name) cname = self.mangle(Naming.type_prefix, name)
try: try:
type = PyrexTypes.create_typedef_type(cname, base_type, (visibility == 'extern')) type = PyrexTypes.create_typedef_type(name, base_type, cname,
(visibility == 'extern'))
except ValueError, e: except ValueError, e:
error(pos, e.message) error(pos, e.message)
type = PyrexTypes.error_type type = PyrexTypes.error_type
......
...@@ -50,13 +50,13 @@ class TestNormalizeTree(TransformTest): ...@@ -50,13 +50,13 @@ class TestNormalizeTree(TransformTest):
""") """)
self.assertLines(u""" self.assertLines(u"""
(root): StatListNode (root): StatListNode
stats[0]: ParallelAssignmentNode
stats[0]: SingleAssignmentNode stats[0]: SingleAssignmentNode
lhs: NameNode lhs: TupleNode
rhs: NameNode args[0]: NameNode
stats[1]: SingleAssignmentNode args[1]: NameNode
lhs: NameNode rhs: TupleNode
rhs: NameNode args[0]: NameNode
args[1]: NameNode
""", self.treetypes(t)) """, self.treetypes(t))
def test_wrap_offagain(self): def test_wrap_offagain(self):
......
...@@ -262,11 +262,12 @@ class SimpleAssignmentTypeInferer: ...@@ -262,11 +262,12 @@ class SimpleAssignmentTypeInferer:
def find_spanning_type(type1, type2): def find_spanning_type(type1, type2):
if type1 is type2: if type1 is type2:
return type1 result_type = type1
elif type1 is PyrexTypes.c_bint_type or type2 is PyrexTypes.c_bint_type: elif type1 is PyrexTypes.c_bint_type or type2 is PyrexTypes.c_bint_type:
# type inference can break the coercion back to a Python bool # type inference can break the coercion back to a Python bool
# if it returns an arbitrary int type here # if it returns an arbitrary int type here
return py_object_type return py_object_type
else:
result_type = PyrexTypes.spanning_type(type1, type2) result_type = PyrexTypes.spanning_type(type1, type2)
if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type, Builtin.float_type): if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type, Builtin.float_type):
# Python's float type is just a C double, so it's safe to # Python's float type is just a C double, so it's safe to
......
...@@ -130,6 +130,9 @@ class ResultRefNode(AtomicExprNode): ...@@ -130,6 +130,9 @@ class ResultRefNode(AtomicExprNode):
def infer_type(self, env): def infer_type(self, env):
return self.expression.infer_type(env) return self.expression.infer_type(env)
def is_simple(self):
return True
def result(self): def result(self):
return self.result_code return self.result_code
...@@ -222,7 +225,8 @@ class LetNode(Nodes.StatNode, LetNodeMixin): ...@@ -222,7 +225,8 @@ class LetNode(Nodes.StatNode, LetNodeMixin):
# BLOCK (can modify temp) # BLOCK (can modify temp)
# if temp is an object, decref # if temp is an object, decref
# #
# To be used after analysis phase, does no analysis. # Usually used after analysis phase, but forwards analysis methods
# to its children
child_attrs = ['temp_expression', 'body'] child_attrs = ['temp_expression', 'body']
...@@ -231,6 +235,17 @@ class LetNode(Nodes.StatNode, LetNodeMixin): ...@@ -231,6 +235,17 @@ class LetNode(Nodes.StatNode, LetNodeMixin):
self.pos = body.pos self.pos = body.pos
self.body = body self.body = body
def analyse_control_flow(self, env):
self.body.analyse_control_flow(env)
def analyse_declarations(self, env):
self.temp_expression.analyse_declarations(env)
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.temp_expression.analyse_expressions(env)
self.body.analyse_expressions(env)
def generate_execution_code(self, code): def generate_execution_code(self, code):
self.setup_temp_expr(code) self.setup_temp_expr(code)
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
......
This diff is collapsed.
Welcome to Cython! Welcome to Cython!
================= =================
Cython (http://www.cython.org) is based on Pyrex, but supports more Cython (http://cython.org) is a language that makes writing C extensions for
cutting edge functionality and optimizations. the Python language as easy as Python itself. Cython is based on the
well-known Pyrex, but supports more cutting edge functionality and
optimizations.
The Cython language is very close to the Python language, but Cython
additionally supports calling C functions and declaring C types on variables
and class attributes. This allows the compiler to generate very efficient C
code from Cython code.
This makes Cython the ideal language for wrapping external C libraries, and
for fast C modules that speed up the execution of Python code.
LICENSE: LICENSE:
The original Pyrex program was licensed "free of restrictions" (see The original Pyrex program was licensed "free of restrictions" (see
below). Cython itself is licensed under the below). Cython itself is licensed under the permissive
PYTHON SOFTWARE FOUNDATION LICENSE Apache License
http://www.python.org/psf/license/
See LICENSE.txt.
-------------------------- --------------------------
There are TWO mercurial (hg) repositories included with Cython: Note that Cython used to ship the Mercurial (hg) repository in its source
distribution, but no longer does so due to space constraints. To get the
* Various project files, documentation, etc. (in the top level directory) full source history, make sure you have hg installed, then step into the
* The main codebase itself (in Cython/) base directory of the Cython source distribution and type
We keep these separate for easier merging with the Pyrex project.
To see the change history for Cython code itself, go to the Cython
directory and type
$ hg log
This requires that you have installed Mercurial. make repo
Alternatively, check out the latest developer repository from
-- William Stein (wstein@gmail.com) http://hg.cython.org/cython-devel
xxxx
The following is from Pyrex: The following is from Pyrex:
......
...@@ -731,7 +731,12 @@ if __name__ == '__main__': ...@@ -731,7 +731,12 @@ if __name__ == '__main__':
help="display test progress, pass twice to print test names") help="display test progress, pass twice to print test names")
parser.add_option("-T", "--ticket", dest="tickets", parser.add_option("-T", "--ticket", dest="tickets",
action="append", action="append",
help="a bug ticket number to run the respective test in 'tests/bugs'") help="a bug ticket number to run the respective test in 'tests/*'")
parser.add_option("--xml-output", dest="xml_output_dir", metavar="DIR",
help="write test results in XML to directory DIR")
parser.add_option("--exit-ok", dest="exit_ok", default=False,
action="store_true",
help="exit without error code even on test failures")
options, cmd_args = parser.parse_args() options, cmd_args = parser.parse_args()
...@@ -885,7 +890,14 @@ if __name__ == '__main__': ...@@ -885,7 +890,14 @@ if __name__ == '__main__':
os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'), os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'),
'pyregr')) 'pyregr'))
result = unittest.TextTestRunner(verbosity=options.verbosity).run(test_suite) if options.xml_output_dir:
from Cython.Tests.xmlrunner import XMLTestRunner
test_runner = XMLTestRunner(output=options.xml_output_dir,
verbose=options.verbosity > 0)
else:
test_runner = unittest.TextTestRunner(verbosity=options.verbosity)
result = test_runner.run(test_suite)
if options.coverage: if options.coverage:
coverage.stop() coverage.stop()
...@@ -905,4 +917,7 @@ if __name__ == '__main__': ...@@ -905,4 +917,7 @@ if __name__ == '__main__':
import refnanny import refnanny
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog])) sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
if options.exit_ok:
sys.exit(0)
else:
sys.exit(not result.wasSuccessful()) sys.exit(not result.wasSuccessful())
...@@ -3,13 +3,13 @@ from distutils.sysconfig import get_python_lib ...@@ -3,13 +3,13 @@ from distutils.sysconfig import get_python_lib
import os, os.path import os, os.path
import sys import sys
if 'sdist' in sys.argv: if 'sdist' in sys.argv and sys.platform != "win32":
# Record the current revision in .hgrev # Record the current revision in .hgrev
import subprocess # os.popen is cleaner but depricated import subprocess # os.popen is cleaner but depricated
changset = subprocess.Popen("hg log --rev tip | grep changeset", changset = subprocess.Popen("hg log --rev tip | grep changeset",
shell=True, shell=True,
stdout=subprocess.PIPE).stdout.read() stdout=subprocess.PIPE).stdout.read()
rev = changset.split(':')[-1].strip() rev = changset.decode('ISO-8859-1').split(':')[-1].strip()
hgrev = open('.hgrev', 'w') hgrev = open('.hgrev', 'w')
hgrev.write(rev) hgrev.write(rev)
hgrev.close() hgrev.close()
......
...@@ -9,3 +9,7 @@ missing_baseclass_in_predecl_T262 ...@@ -9,3 +9,7 @@ missing_baseclass_in_predecl_T262
cfunc_call_tuple_args_T408 cfunc_call_tuple_args_T408
cascaded_list_unpacking_T467 cascaded_list_unpacking_T467
compile.cpp_operators compile.cpp_operators
# Pyrex regression tests that don't current work:
pyregr.test_threadsignals
pyregr.test_module
cdef int raiseit(): cdef int raiseit():
raise IndexError raise IndexError
if False: raiseit()
_ERRORS = u""" _ERRORS = u"""
FIXME: provide a good error message here. FIXME: provide a good error message here.
......
...@@ -7,6 +7,6 @@ cdef spamfunc spam ...@@ -7,6 +7,6 @@ cdef spamfunc spam
grail = spam # type mismatch grail = spam # type mismatch
spam = grail # type mismatch spam = grail # type mismatch
_ERRORS = u""" _ERRORS = u"""
7:28: Cannot assign type 'e_excvalfunctype.spamfunc' to 'e_excvalfunctype.grailfunc' 7:28: Cannot assign type 'spamfunc' to 'grailfunc'
8:28: Cannot assign type 'e_excvalfunctype.grailfunc' to 'e_excvalfunctype.spamfunc' 8:28: Cannot assign type 'grailfunc' to 'spamfunc'
""" """
# invalid syntax (as handled by the parser)
def syntax():
*a, *b = 1,2,3,4,5
# wrong size RHS (as handled by the parser) # wrong size RHS (as handled by the parser)
def length1(): def length1():
...@@ -27,12 +22,11 @@ def length_recursive(): ...@@ -27,12 +22,11 @@ def length_recursive():
_ERRORS = u""" _ERRORS = u"""
5:4: more than 1 starred expression in assignment 5:4: too many values to unpack (expected 2, got 3)
10:4: too many values to unpack (expected 2, got 3) 8:4: need more than 1 value to unpack
13:4: need more than 1 value to unpack 11:4: need more than 0 values to unpack
16:4: need more than 0 values to unpack 14:4: need more than 0 values to unpack
19:4: need more than 0 values to unpack 17:4: need more than 0 values to unpack
22:4: need more than 0 values to unpack 18:4: need more than 1 value to unpack
23:4: need more than 1 value to unpack 21:6: need more than 1 value to unpack
26:6: need more than 1 value to unpack
""" """
# invalid syntax (as handled by the parser)
def syntax():
*a, *b = 1,2,3,4,5
_ERRORS = u"""
5:4: more than 1 starred expression in assignment
5:8: more than 1 starred expression in assignment
"""
...@@ -109,3 +109,5 @@ cdef class MyCdefClass: ...@@ -109,3 +109,5 @@ cdef class MyCdefClass:
>>> True >>> True
False False
""" """
cdeffunc()
...@@ -53,6 +53,8 @@ def printbuf(): ...@@ -53,6 +53,8 @@ def printbuf():
""" """
cdef object[int, ndim=2] buf cdef object[int, ndim=2] buf
print buf print buf
return
buf[0,0] = 0
@testcase @testcase
def acquire_release(o1, o2): def acquire_release(o1, o2):
...@@ -798,7 +800,7 @@ def printbuf_td_cy_int(object[td_cy_int] buf, shape): ...@@ -798,7 +800,7 @@ def printbuf_td_cy_int(object[td_cy_int] buf, shape):
>>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,)) >>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch, expected 'bufaccess.td_cy_int' but got 'short' ValueError: Buffer dtype mismatch, expected 'td_cy_int' but got 'short'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -813,7 +815,7 @@ def printbuf_td_h_short(object[td_h_short] buf, shape): ...@@ -813,7 +815,7 @@ def printbuf_td_h_short(object[td_h_short] buf, shape):
>>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,)) >>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_short' but got 'int' ValueError: Buffer dtype mismatch, expected 'td_h_short' but got 'int'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -828,7 +830,7 @@ def printbuf_td_h_cy_short(object[td_h_cy_short] buf, shape): ...@@ -828,7 +830,7 @@ def printbuf_td_h_cy_short(object[td_h_cy_short] buf, shape):
>>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,)) >>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_cy_short' but got 'int' ValueError: Buffer dtype mismatch, expected 'td_h_cy_short' but got 'int'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -843,7 +845,7 @@ def printbuf_td_h_ushort(object[td_h_ushort] buf, shape): ...@@ -843,7 +845,7 @@ def printbuf_td_h_ushort(object[td_h_ushort] buf, shape):
>>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,)) >>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_ushort' but got 'short' ValueError: Buffer dtype mismatch, expected 'td_h_ushort' but got 'short'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -858,7 +860,7 @@ def printbuf_td_h_double(object[td_h_double] buf, shape): ...@@ -858,7 +860,7 @@ def printbuf_td_h_double(object[td_h_double] buf, shape):
>>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,)) >>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_double' but got 'float' ValueError: Buffer dtype mismatch, expected 'td_h_double' but got 'float'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
......
...@@ -77,9 +77,16 @@ def test_attr_int(TestExtInt e): ...@@ -77,9 +77,16 @@ def test_attr_int(TestExtInt e):
else: else:
return False return False
ctypedef union _aux:
int i
void *p
cdef class TestExtPtr: cdef class TestExtPtr:
cdef void* p cdef void* p
def __init__(self, int i): self.p = <void*>i def __init__(self, int i):
cdef _aux aux
aux.i = i
self.p = aux.p
def test_attr_ptr(TestExtPtr e): def test_attr_ptr(TestExtPtr e):
""" """
......
...@@ -135,6 +135,12 @@ __doc__ = ur""" ...@@ -135,6 +135,12 @@ __doc__ = ur"""
>>> print (f_D.__doc__) >>> print (f_D.__doc__)
f_D(long double D) -> long double f_D(long double D) -> long double
>>> print (f_my_i.__doc__)
f_my_i(MyInt i) -> MyInt
>>> print (f_my_f.__doc__)
f_my_f(MyFloat f) -> MyFloat
""" """
cdef class Ext: cdef class Ext:
...@@ -279,3 +285,11 @@ cpdef double f_d(double d): ...@@ -279,3 +285,11 @@ cpdef double f_d(double d):
cpdef long double f_D(long double D): cpdef long double f_D(long double D):
return D return D
ctypedef int MyInt
cpdef MyInt f_my_i(MyInt i):
return i
ctypedef float MyFloat
cpdef MyFloat f_my_f(MyFloat f):
return f
...@@ -19,7 +19,7 @@ def range_loop_indices(): ...@@ -19,7 +19,7 @@ def range_loop_indices():
Optimized integer for loops using range() should follow Python behavior, Optimized integer for loops using range() should follow Python behavior,
and leave the index variable with the last value of the range. and leave the index variable with the last value of the range.
""" """
cdef int i, j, k=0, l, m cdef int i, j, k=0, l=10, m=10
for i in range(10): pass for i in range(10): pass
for j in range(2,10): pass for j in range(2,10): pass
for k in range(0,10,get_step()): pass for k in range(0,10,get_step()): pass
......
...@@ -13,3 +13,5 @@ def myfunc(): ...@@ -13,3 +13,5 @@ def myfunc():
for i from 0 <= i < A.shape[0]: for i from 0 <= i < A.shape[0]:
A[i, :] /= 2 A[i, :] /= 2
return A[0,0] return A[0,0]
include "numpy_common.pxi"
cdef extern from *:
void import_array()
void import_umath()
if 0:
import_array()
import_umath()
...@@ -428,3 +428,5 @@ def test_point_record(): ...@@ -428,3 +428,5 @@ def test_point_record():
test[i].x = i test[i].x = i
test[i].y = -i test[i].y = -i
print repr(test).replace('<', '!').replace('>', '!') print repr(test).replace('<', '!').replace('>', '!')
include "numpy_common.pxi"
...@@ -107,6 +107,60 @@ def swap_attr_values(A a, A b): ...@@ -107,6 +107,60 @@ def swap_attr_values(A a, A b):
a.x, a.y, b.x, b.y = b.y, b.x, a.y, a.x # reverse a.x, a.y, b.x, b.y = b.y, b.x, a.y, a.x # reverse
cdef class B:
cdef readonly A a1
cdef readonly A a2
def __init__(self, x1, y1, x2, y2):
self.a1, self.a2 = A(x1, y1), A(x2, y2)
@cython.test_assert_path_exists(
"//ParallelAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode/CoerceToTempNode",
"//ParallelAssignmentNode/SingleAssignmentNode/CoerceToTempNode[@use_managed_ref=False]",
"//ParallelAssignmentNode/SingleAssignmentNode//AttributeNode/NameNode",
"//ParallelAssignmentNode/SingleAssignmentNode//AttributeNode[@use_managed_ref=False]/NameNode",
)
@cython.test_fail_if_path_exists(
"//ParallelAssignmentNode/SingleAssignmentNode/CoerceToTempNode[@use_managed_ref=True]",
"//ParallelAssignmentNode/SingleAssignmentNode/AttributeNode[@use_managed_ref=True]",
)
def swap_recursive_attr_values(B a, B b):
"""
>>> a, b = B(1,2,3,4), B(5,6,7,8)
>>> a.a1.x, a.a1.y, a.a2.x, a.a2.y
(1, 2, 3, 4)
>>> b.a1.x, b.a1.y, b.a2.x, b.a2.y
(5, 6, 7, 8)
>>> swap_recursive_attr_values(a,b)
>>> a.a1.x, a.a1.y, a.a2.x, a.a2.y
(2, 1, 4, 4)
>>> b.a1.x, b.a1.y, b.a2.x, b.a2.y
(6, 5, 8, 8)
# compatibility test
>>> class A:
... def __init__(self, x, y):
... self.x, self.y = x, y
>>> class B:
... def __init__(self, x1, y1, x2, y2):
... self.a1, self.a2 = A(x1, y1), A(x2, y2)
>>> a, b = B(1,2,3,4), B(5,6,7,8)
>>> a.a1, a.a2 = a.a2, a.a1
>>> b.a1, b.a2 = b.a2, b.a1
>>> a.a1, a.a1.x, a.a2.y, a.a2, a.a1.y, a.a2.x = a.a2, a.a2.y, a.a1.x, a.a1, a.a2.x, a.a1.y
>>> b.a1, b.a1.x, b.a2.y, b.a2, b.a1.y, b.a2.x = b.a2, b.a2.y, b.a1.x, b.a1, b.a2.x, b.a1.y
>>> a.a1.x, a.a1.y, a.a2.x, a.a2.y
(2, 1, 4, 4)
>>> b.a1.x, b.a1.y, b.a2.x, b.a2.y
(6, 5, 8, 8)
"""
a.a1, a.a2 = a.a2, a.a1
b.a1, b.a2 = b.a2, b.a1
a.a1, a.a1.x, a.a2.y, a.a2, a.a1.y, a.a2.x = a.a2, a.a2.y, a.a1.x, a.a1, a.a2.x, a.a1.y
b.a1, b.a1.x, b.a2.y, b.a2, b.a1.y, b.a2.x = b.a2, b.a2.y, b.a1.x, b.a1, b.a2.x, b.a1.y
@cython.test_assert_path_exists( @cython.test_assert_path_exists(
# "//ParallelAssignmentNode", # "//ParallelAssignmentNode",
# "//ParallelAssignmentNode/SingleAssignmentNode", # "//ParallelAssignmentNode/SingleAssignmentNode",
......
def f(a, b): def print_to_stdout(a, b):
""" """
>>> f(1, 'test') >>> print_to_stdout(1, 'test')
<BLANKLINE> <BLANKLINE>
1 1
1 test 1 test
...@@ -14,3 +14,29 @@ def f(a, b): ...@@ -14,3 +14,29 @@ def f(a, b):
print a, b print a, b
print a, b, print a, b,
print 42, u"spam" print 42, u"spam"
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
def print_to_stringio(stream, a, b):
"""
>>> stream = StringIO()
>>> print_to_stringio(stream, 1, 'test')
>>> print(stream.getvalue())
<BLANKLINE>
1
1 test
1 test
1 test 42 spam
<BLANKLINE>
"""
print >> stream
print >> stream, a
print >> stream, a,
print >> stream, b
print >> stream, a, b
print >> stream, a, b,
print >> stream, 42, u"spam"
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