Commit f8e85bee authored by Stefan Behnel's avatar Stefan Behnel

implement C array iteration with explicit step size (#574), always coerce...

implement C array iteration with explicit step size (#574), always coerce start/stop offsets in C array iteration to Py_ssize_t
parent e710b94a
...@@ -90,9 +90,15 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -90,9 +90,15 @@ class IterationTransform(Visitor.VisitorTransform):
node, dict_obj=iterator, keys=True, values=False) node, dict_obj=iterator, keys=True, values=False)
# C array (slice) iteration? # C array (slice) iteration?
if isinstance(iterator, ExprNodes.CoerceToPyTypeNode):
iterator = iterator.arg
if isinstance(iterator, ExprNodes.SliceIndexNode) and \ if isinstance(iterator, ExprNodes.SliceIndexNode) and \
(iterator.base.type.is_array or iterator.base.type.is_ptr): (iterator.base.type.is_array or iterator.base.type.is_ptr):
return self._transform_carray_iteration(node, iterator) return self._transform_carray_iteration(node, iterator)
elif isinstance(iterator, ExprNodes.IndexNode) and \
isinstance(iterator.index, (ExprNodes.SliceNode, ExprNodes.CoerceFromPyTypeNode)) and \
(iterator.base.type.is_array or iterator.base.type.is_ptr):
return self._transform_carray_iteration(node, iterator)
elif iterator.type.is_array: elif iterator.type.is_array:
return self._transform_carray_iteration(node, iterator) return self._transform_carray_iteration(node, iterator)
elif iterator.type in (Builtin.bytes_type, Builtin.unicode_type): elif iterator.type in (Builtin.bytes_type, Builtin.unicode_type):
...@@ -201,6 +207,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -201,6 +207,7 @@ class IterationTransform(Visitor.VisitorTransform):
))) )))
def _transform_carray_iteration(self, node, slice_node): def _transform_carray_iteration(self, node, slice_node):
neg_step = False
if isinstance(slice_node, ExprNodes.SliceIndexNode): if isinstance(slice_node, ExprNodes.SliceIndexNode):
slice_base = slice_node.base slice_base = slice_node.base
start = slice_node.start start = slice_node.start
...@@ -208,15 +215,51 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -208,15 +215,51 @@ class IterationTransform(Visitor.VisitorTransform):
step = None step = None
if not stop: if not stop:
return node return node
elif isinstance(slice_node, ExprNodes.IndexNode):
# slice_node.index must be a SliceNode
slice_base = slice_node.base
index = slice_node.index
if isinstance(index, ExprNodes.CoerceFromPyTypeNode):
index = index.arg
start = index.start
stop = index.stop
step = index.step
if step:
if step.constant_result is None:
step = None
elif not isinstance(step.constant_result, (int,long)) \
or step.constant_result == 0 \
or step.constant_result > 0 and not stop \
or step.constant_result < 0 and not start:
error(step.pos, "C array iteration requires known step size and end index")
return node
else:
# step sign is handled internally by ForFromStatNode
neg_step = step.constant_result < 0
step = ExprNodes.IntNode(step.pos, type=PyrexTypes.c_py_ssize_t_type,
value=abs(step.constant_result),
constant_result=abs(step.constant_result))
elif slice_node.type.is_array and slice_node.type.size is not None: elif slice_node.type.is_array and slice_node.type.size is not None:
slice_base = slice_node slice_base = slice_node
start = None start = None
stop = ExprNodes.IntNode( stop = ExprNodes.IntNode(
slice_node.pos, value=str(slice_node.type.size)) slice_node.pos, value=str(slice_node.type.size),
type=PyrexTypes.c_py_ssize_t_type, constant_result=slice_node.type.size)
step = None step = None
else: else:
return node return node
if start:
if start.constant_result is None:
start = None
else:
start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope)
if stop:
if stop.constant_result is None:
stop = None
else:
stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope)
ptr_type = slice_base.type ptr_type = slice_base.type
if ptr_type.is_array: if ptr_type.is_array:
ptr_type = ptr_type.element_ptr_type() ptr_type = ptr_type.element_ptr_type()
...@@ -281,9 +324,9 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -281,9 +324,9 @@ class IterationTransform(Visitor.VisitorTransform):
for_node = Nodes.ForFromStatNode( for_node = Nodes.ForFromStatNode(
node.pos, node.pos,
bound1=start_ptr_node, relation1='<=', bound1=start_ptr_node, relation1=neg_step and '>=' or '<=',
target=counter_temp, target=counter_temp,
relation2='<', bound2=stop_ptr_node, relation2=neg_step and '>' or '<', bound2=stop_ptr_node,
step=step, body=body, step=step, body=body,
else_clause=node.else_clause, else_clause=node.else_clause,
from_range=True) from_range=True)
......
...@@ -42,20 +42,30 @@ def slice_charptr_for_loop_c(): ...@@ -42,20 +42,30 @@ def slice_charptr_for_loop_c():
print [ chr(c) for c in cstring[1:5] ] print [ chr(c) for c in cstring[1:5] ]
print [ chr(c) for c in cstring[4:9] ] print [ chr(c) for c in cstring[4:9] ]
## @cython.test_assert_path_exists("//ForFromStatNode", @cython.test_assert_path_exists("//ForFromStatNode",
## "//ForFromStatNode//IndexNode") "//ForFromStatNode//IndexNode")
## @cython.test_fail_if_path_exists("//ForInStatNode") @cython.test_fail_if_path_exists("//ForInStatNode")
## def slice_charptr_for_loop_c_step(): def slice_charptr_for_loop_c_step():
## """ """
## >>> slice_charptr_for_loop_c() >>> slice_charptr_for_loop_c_step()
## ['c', 'b', 'a'] []
## ['b', 'c', 'A', 'B'] []
## ['p', 't', 'q', 'C', 'B'] ['b', 'A']
## """ ['a', 'c', 'B']
## cdef char c ['a', 'c', 'B']
## print [ chr(c) for c in cstring[:3:-1] ] []
## print [ chr(c) for c in cstring[1:5:2] ] ['p', 't', 'q', 'C']
## print [ chr(c) for c in cstring[4:9:-1] ] ['p', 'q']
"""
cdef char c
print [ chr(c) for c in cstring[:3:-1] ]
print [ chr(c) for c in cstring[None:3:-1] ]
print [ chr(c) for c in cstring[1:5:2] ]
print [ chr(c) for c in cstring[:5:2] ]
print [ chr(c) for c in cstring[None:5:2] ]
print [ chr(c) for c in cstring[4:9:-1] ]
print [ chr(c) for c in cstring[8:4:-1] ]
print [ chr(c) for c in cstring[8:4:-2] ]
@cython.test_assert_path_exists("//ForFromStatNode", @cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode") "//ForFromStatNode//IndexNode")
......
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