Skip to content

Commit adb6ad4

Browse files
committed
[GR-9908] There are not implemented inplace operations.
PullRequest: graalpython-open/58
2 parents 9928c54 + b39c6ba commit adb6ad4

File tree

12 files changed

+462
-12
lines changed

12 files changed

+462
-12
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/grammar/BinaryArithTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public void int64() {
131131
public void NonePlusInt() {
132132
String source = "a = None\n" + //
133133
"a += 1\n";
134-
assertLastLineError("TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'\n", source);
134+
assertLastLineError("TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'\n", source);
135135
}
136136

137137
}

graalpython/com.oracle.graal.python.test/src/tests/list_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ def test_slice(self):
541541
u = self.type2test("spam")
542542
u[:2] = "h"
543543
self.assertEqual(u, list("ham"))
544-
'''
544+
545545
def test_iadd(self):
546546
super().test_iadd()
547547
u = self.type2test([0, 1])
@@ -554,7 +554,7 @@ def test_iadd(self):
554554
self.assertEqual(u, self.type2test("spameggs"))
555555

556556
self.assertRaises(TypeError, u.__iadd__, None)
557-
557+
'''
558558
def test_imul(self):
559559
u = self.type2test([0, 1])
560560
u *= 3
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Copyright (c) 2018, Oracle and/or its affiliates.
2+
#
3+
# The Universal Permissive License (UPL), Version 1.0
4+
#
5+
# Subject to the condition set forth below, permission is hereby granted to any
6+
# person obtaining a copy of this software, associated documentation and/or data
7+
# (collectively the "Software"), free of charge and under any and all copyright
8+
# rights in the Software, and any and all patent rights owned or freely
9+
# licensable by each licensor hereunder covering either (i) the unmodified
10+
# Software as contributed to or provided by such licensor, or (ii) the Larger
11+
# Works (as defined below), to deal in both
12+
#
13+
# (a) the Software, and
14+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
15+
# one is included with the Software (each a "Larger Work" to which the
16+
# Software is contributed by such licensors),
17+
#
18+
# without restriction, including without limitation the rights to copy, create
19+
# derivative works of, display, perform, and distribute the Software and make,
20+
# use, sell, offer for sale, import, export, have made, and have sold the
21+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
22+
# either these or other terms.
23+
#
24+
# This license is subject to the following condition:
25+
#
26+
# The above copyright notice and either this complete permission notice or at a
27+
# minimum a reference to the UPL must be included in all copies or substantial
28+
# portions of the Software.
29+
#
30+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
# SOFTWARE.
37+
38+
import unittest
39+
40+
class InplaceAssignmentTest(unittest.TestCase):
41+
42+
def test_iadd_01(self):
43+
44+
class MyInt(int):
45+
def __iadd__(self, value):
46+
return 7
47+
def __add__(self, value):
48+
return 6
49+
50+
a = MyInt(10)
51+
a += 4
52+
self.assertEqual(a, 7)
53+
54+
a = MyInt(10)
55+
a = a + 4
56+
self.assertEqual(a, 6)
57+
58+
def test_iadd_02(self):
59+
60+
class MyInt(int):
61+
def __add__(self, value):
62+
return 6
63+
64+
a = MyInt(10)
65+
a += 4
66+
self.assertEqual(a, 6)
67+
68+
a = MyInt(10)
69+
a = a + 4
70+
self.assertEqual(a, 6)
71+
72+
def test_iadd_03(self):
73+
74+
class MyInt(int):
75+
def __new__(cls, value):
76+
return int.__new__(cls, value)
77+
def __iadd__(self, value):
78+
return self + value + 1
79+
80+
a = MyInt(1)
81+
a += 1
82+
self.assertEqual(a, 3)

graalpython/com.oracle.graal.python.test/src/tests/test_list.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ def __index__(self):
430430
a.insert(False, -1)
431431
self.assertEqual([-1,0,1], a)
432432

433-
def testStopIteration(self):
433+
def test_StopIteration(self):
434434
l = [1.0]
435435
i = l.__iter__()
436436
i.__next__()
@@ -454,3 +454,28 @@ def testStopIteration(self):
454454
self.assertRaises(StopIteration, i.__next__)
455455
l.append(3)
456456
self.assertRaises(StopIteration, i.__next__)
457+
458+
def test_iadd_special(self):
459+
a = [1]
460+
a += (2,3)
461+
self.assertEqual([1,2,3], a)
462+
463+
a += {'a' : 1, 'b' : 2}
464+
self.assertEqual([1,2,3,'a','b'], a)
465+
466+
a = [1]
467+
a += range(2,5)
468+
self.assertEqual([1,2,3,4], a)
469+
self.assertRaises(TypeError, a.__iadd__, 1)
470+
471+
class MyList(list):
472+
def __iadd__(self, value):
473+
return super().__iadd__([100])
474+
475+
mya = MyList([1,2])
476+
mya += [3]
477+
self.assertEqual([1,2,100], mya)
478+
479+
a = [1,2]
480+
a += a
481+
self.assertEqual([1,2,1,2], a)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.oracle.graal.python.builtins.objects.list;
2727

2828
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ADD__;
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__IADD__;
2930
import static com.oracle.graal.python.nodes.SpecialMethodNames.__BOOL__;
3031
import static com.oracle.graal.python.nodes.SpecialMethodNames.__CONTAINS__;
3132
import static com.oracle.graal.python.nodes.SpecialMethodNames.__DELITEM__;
@@ -487,6 +488,8 @@ protected boolean isKnownStorage(PList list) {
487488
@GenerateNodeFactory
488489
public abstract static class ListExtendNode extends PythonBuiltinNode {
489490

491+
public abstract PNone execute(PList list, Object source);
492+
490493
@Specialization(guards = {"isPSequenceWithStorage(source)"}, rewriteOn = {SequenceStoreException.class})
491494
public PNone extendSequenceStore(PList list, Object source) throws SequenceStoreException {
492495
SequenceStorage target = list.getSequenceStorage();
@@ -1092,16 +1095,70 @@ PList doPList(PList left, PList right) {
10921095
}
10931096
}
10941097

1095-
protected boolean isList(Object o) {
1096-
return o instanceof PList;
1097-
}
1098-
10991098
@Specialization(guards = "!isList(right)")
11001099
Object doGeneric(@SuppressWarnings("unused") Object left, Object right) {
11011100
throw raise(TypeError, "can only concatenate list (not \"%p\") to list", right);
11021101
}
11031102
}
11041103

1104+
@Builtin(name = __IADD__, fixedNumOfArguments = 2)
1105+
@GenerateNodeFactory
1106+
abstract static class IAddNode extends PythonBuiltinNode {
1107+
1108+
@Specialization(guards = "areBothIntStorage(left,right)")
1109+
PList doPListInt(PList left, PList right) {
1110+
IntSequenceStorage leftStore = (IntSequenceStorage) left.getSequenceStorage();
1111+
IntSequenceStorage rightStore = (IntSequenceStorage) right.getSequenceStorage();
1112+
leftStore.extendWithIntStorage(rightStore);
1113+
return left;
1114+
}
1115+
1116+
@Specialization(guards = "areBothLongStorage(left,right)")
1117+
PList doPListLong(PList left, PList right) {
1118+
LongSequenceStorage leftStore = (LongSequenceStorage) left.getSequenceStorage();
1119+
LongSequenceStorage rightStore = (LongSequenceStorage) right.getSequenceStorage();
1120+
leftStore.extendWithLongStorage(rightStore);
1121+
return left;
1122+
}
1123+
1124+
@Specialization(guards = "areBothDoubleStorage(left,right)")
1125+
PList doPListDouble(PList left, PList right) {
1126+
DoubleSequenceStorage leftStore = (DoubleSequenceStorage) left.getSequenceStorage();
1127+
DoubleSequenceStorage rightStore = (DoubleSequenceStorage) right.getSequenceStorage();
1128+
leftStore.extendWithDoubleStorage(rightStore);
1129+
return left;
1130+
}
1131+
1132+
@Specialization(guards = "areBothObjectStorage(left,right)")
1133+
PList doPListObject(PList left, PList right) {
1134+
ObjectSequenceStorage leftStore = (ObjectSequenceStorage) left.getSequenceStorage();
1135+
ObjectSequenceStorage rightStore = (ObjectSequenceStorage) right.getSequenceStorage();
1136+
leftStore.extend(rightStore);
1137+
return left;
1138+
}
1139+
1140+
@Specialization(guards = "isNotSameStorage(left, right)")
1141+
PList doPList(PList left, PList right) {
1142+
left.extend(right);
1143+
return left;
1144+
}
1145+
1146+
@Specialization(guards = "!isList(right)")
1147+
PList doPList(PList left, Object right,
1148+
@Cached("createExtendNode()") ListExtendNode extendNode) {
1149+
extendNode.execute(left, right);
1150+
return left;
1151+
}
1152+
1153+
protected ListExtendNode createExtendNode() {
1154+
return ListBuiltinsFactory.ListExtendNodeFactory.create(new PNode[0]);
1155+
}
1156+
1157+
protected boolean isNotSameStorage(PList left, PList right) {
1158+
return !(PGuards.areBothIntStorage(right, left) || PGuards.areBothDoubleStorage(right, left) || PGuards.areBothLongStorage(right, left) || PGuards.areBothObjectStorage(right, left));
1159+
}
1160+
}
1161+
11051162
@Builtin(name = __MUL__, fixedNumOfArguments = 2)
11061163
@GenerateNodeFactory
11071164
abstract static class MulNode extends PythonBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/NodeFactory.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
6262
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
6363
import com.oracle.graal.python.nodes.expression.CastToBooleanNode;
64+
import com.oracle.graal.python.nodes.expression.InplaceArithmetic;
6465
import com.oracle.graal.python.nodes.expression.IsNode;
6566
import com.oracle.graal.python.nodes.expression.OrNode;
6667
import com.oracle.graal.python.nodes.expression.UnaryArithmetic;
@@ -310,6 +311,39 @@ public PNode createUnaryOperation(String string, PNode operand) {
310311
}
311312
}
312313

314+
public PNode createInplaceOperation(String string, PNode left, PNode right) {
315+
switch (string) {
316+
case "+=":
317+
return InplaceArithmetic.IAdd.create(left, right);
318+
case "-=":
319+
return InplaceArithmetic.ISub.create(left, right);
320+
case "*=":
321+
return InplaceArithmetic.IMul.create(left, right);
322+
case "/=":
323+
return InplaceArithmetic.ITrueDiv.create(left, right);
324+
case "//=":
325+
return InplaceArithmetic.IFloorDiv.create(left, right);
326+
case "%=":
327+
return InplaceArithmetic.IMod.create(left, right);
328+
case "**=":
329+
return InplaceArithmetic.IPow.create(left, right);
330+
case "<<=":
331+
return InplaceArithmetic.ILShift.create(left, right);
332+
case ">>=":
333+
return InplaceArithmetic.IRShift.create(left, right);
334+
case "&=":
335+
return InplaceArithmetic.IAnd.create(left, right);
336+
case "|=":
337+
return InplaceArithmetic.IOr.create(left, right);
338+
case "^=":
339+
return InplaceArithmetic.IXor.create(left, right);
340+
case "@=":
341+
return InplaceArithmetic.IMatMul.create(left, right);
342+
default:
343+
throw new RuntimeException("unexpected operation: " + string);
344+
}
345+
}
346+
313347
public PNode createBinaryOperation(String string, PNode left, PNode right) {
314348
switch (string) {
315349
case "+":

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ public static boolean isDoubleStorage(PList list) {
139139
return list.getSequenceStorage() instanceof DoubleSequenceStorage;
140140
}
141141

142+
public static boolean areBothDoubleStorage(PList first, PList second) {
143+
return first.getSequenceStorage() instanceof DoubleSequenceStorage && second.getSequenceStorage() instanceof DoubleSequenceStorage;
144+
}
145+
142146
public static boolean isListStorage(PList list) {
143147
return list.getSequenceStorage() instanceof ListSequenceStorage;
144148
}
@@ -155,6 +159,10 @@ public static boolean areBothObjectStorage(PList first, PList second) {
155159
return first.getSequenceStorage() instanceof ObjectSequenceStorage && second.getSequenceStorage() instanceof ObjectSequenceStorage;
156160
}
157161

162+
public static boolean isList(Object o) {
163+
return o instanceof PList;
164+
}
165+
158166
public static boolean isObjectStorageIterator(PSequenceIterator iterator) {
159167
if (!iterator.isPSequence()) {
160168
return false;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/SpecialMethodNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ public abstract class SpecialMethodNames {
120120
public static final String __IDIVMOD__ = "__idivmod__";
121121
public static final String __IPOW__ = "__ipow__";
122122
public static final String __ILSHIFT__ = "__ilshift__";
123+
public static final String __IRSHIFT__ = "__irshift__";
123124
public static final String __IAND__ = "__iand__";
124125
public static final String __IXOR__ = "__ixor__";
125126
public static final String __IOR__ = "__ior__";

0 commit comments

Comments
 (0)