allow slice assignments for arrays
authorStefan Behnel <scoder@users.berlios.de>
Thu, 13 Nov 2008 22:17:51 +0000 (23:17 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 13 Nov 2008 22:17:51 +0000 (23:17 +0100)
Cython/Compiler/ExprNodes.py

index 86bdec15556ed19cfc329281fc4042a65e510532..44c7120f12154fc5d3e5568b42cee54e40ff6994 100644 (file)
@@ -1779,19 +1779,29 @@ class SliceIndexNode(ExprNode):
             self.start.analyse_types(env)
         if self.stop:
             self.stop.analyse_types(env)
-        self.base = self.base.coerce_to_pyobject(env)
+        if self.base.type.is_array or self.base.type.is_ptr:
+            # we need a ptr type here instead of an array type, as
+            # array types can result in invalid type casts in the C
+            # code
+            self.type = PyrexTypes.CPtrType(self.base.type.base_type)
+        else:
+            self.base = self.base.coerce_to_pyobject(env)
+            self.type = py_object_type
         c_int = PyrexTypes.c_py_ssize_t_type
         if self.start:
             self.start = self.start.coerce_to(c_int, env)
         if self.stop:
             self.stop = self.stop.coerce_to(c_int, env)
-        self.type = py_object_type
         self.gil_check(env)
         self.is_temp = 1
 
     gil_message = "Slicing Python object"
 
     def generate_result_code(self, code):
+        if not self.type.is_pyobject:
+            error(self.pos,
+                  "Slicing is not currently supported for '%s'." % self.type)
+            return
         code.putln(
             "%s = PySequence_GetSlice(%s, %s, %s); %s" % (
                 self.result(),
@@ -1802,16 +1812,38 @@ class SliceIndexNode(ExprNode):
     
     def generate_assignment_code(self, rhs, code):
         self.generate_subexpr_evaluation_code(code)
-        code.put_error_if_neg(self.pos, 
-            "PySequence_SetSlice(%s, %s, %s, %s)" % (
-                self.base.py_result(),
-                self.start_code(),
-                self.stop_code(),
-                rhs.result()))
+        if self.type.is_pyobject:
+            code.put_error_if_neg(self.pos, 
+                "PySequence_SetSlice(%s, %s, %s, %s)" % (
+                    self.base.py_result(),
+                    self.start_code(),
+                    self.stop_code(),
+                    rhs.result()))
+        else:
+            if rhs.type.is_array:
+                # FIXME: we should check both array sizes here
+                array_length = rhs.type.size
+            else:
+                array_length = self.base.type.size
+            start_offset = ''
+            if self.start:
+                start_offset = self.start_code()
+                if start_offset == '0':
+                    start_offset = ''
+                else:
+                    start_offset += '+'
+            for i in range(array_length):
+                code.putln("%s[%s%s] = %s[%d];" % (
+                        self.base.result(), start_offset, i,
+                        rhs.result(), i))
         self.generate_subexpr_disposal_code(code)
         rhs.generate_disposal_code(code)
 
     def generate_deletion_code(self, code):
+        if not self.type.is_pyobject:
+            error(self.pos,
+                  "Deleting slices is only supported for Python types, not '%s'." % self.type)
+            return
         self.generate_subexpr_evaluation_code(code)
         code.put_error_if_neg(self.pos,
             "PySequence_DelSlice(%s, %s, %s)" % (
@@ -1829,6 +1861,8 @@ class SliceIndexNode(ExprNode):
     def stop_code(self):
         if self.stop:
             return self.stop.result()
+        elif self.base.type.is_array:
+            return self.base.type.size
         else:
             return "PY_SSIZE_T_MAX"