Skip to content

Commit 2206833

Browse files
committed
Support iterable unpacking in ListLiteralNode.
1 parent 75ef574 commit 2206833

File tree

6 files changed

+112
-46
lines changed

6 files changed

+112
-46
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ def test_basic(self):
5454
l[0] = "hello"
5555
self.assertEqual(l, ["hello", 1, 2, 3, 4])
5656

57+
def test_literal(self):
58+
self.assertEqual([1,2,3], [*[1,2,3]])
59+
self.assertEqual([1,2,3], [*(1,2,3)])
60+
self.assertEqual([1,2,3,4,5,6], [*(1,2,3), *(4,5,6)])
61+
62+
# this will certainly create a list where the capacity of the storage is not exhausted, i.e., 'length < cap',
63+
# and so the storage contains null elements
64+
l = []
65+
for c in "abcdefghijk":
66+
l.append(c)
67+
self.assertEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'], [*l])
68+
5769
def test_truth(self):
5870
super().test_truth()
5971
self.assertTrue(not [])

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ def test_constructors(self):
2222
self.assertEqual(tuple(''), ())
2323
self.assertEqual(tuple('spam'), ('s', 'p', 'a', 'm'))
2424

25+
def test_literal(self):
26+
self.assertEqual((1,2,3), (*[1,2,3],))
27+
2528
def test_truth(self):
2629
super().test_truth()
2730
self.assertTrue(not ())

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/CastToListExpressionNode.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4444

4545
import com.oracle.graal.python.PythonLanguage;
46+
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetSequenceStorageNode;
4647
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
4748
import com.oracle.graal.python.builtins.objects.list.PList;
4849
import com.oracle.graal.python.builtins.objects.object.PythonObject;
@@ -78,15 +79,15 @@
7879

7980
public abstract class CastToListExpressionNode extends UnaryOpNode {
8081

81-
public Object[] getArray(VirtualFrame frame) {
82+
@Child private GetSequenceStorageNode getSequenceStorageNode;
83+
84+
public final SequenceStorage getStorage(VirtualFrame frame) {
8285
Object result = execute(frame);
83-
if (result instanceof PTuple) {
84-
return ((PTuple) result).getSequenceStorage().getInternalArray();
85-
} else if (result instanceof PList) {
86-
return ((PList) result).getSequenceStorage().getInternalArray();
87-
} else {
88-
throw new RuntimeException("Got an unexpected result when casting to a list");
86+
if (getSequenceStorageNode == null) {
87+
CompilerDirectives.transferToInterpreterAndInvalidate();
88+
getSequenceStorageNode = insert(GetSequenceStorageNode.create());
8989
}
90+
return getSequenceStorageNode.execute(result);
9091
}
9192

9293
@Specialization

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/literal/ListLiteralNode.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727

2828
import java.lang.reflect.Array;
2929

30+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
31+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ListGeneralizationNode;
3032
import com.oracle.graal.python.builtins.objects.list.PList;
3133
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
34+
import com.oracle.graal.python.nodes.PNode;
3235
import com.oracle.graal.python.nodes.expression.ExpressionNode;
3336
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
3437
import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage;
@@ -40,6 +43,7 @@
4043
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage.ListStorageType;
4144
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorageFactory;
4245
import com.oracle.graal.python.runtime.sequence.storage.TupleSequenceStorage;
46+
import com.oracle.truffle.api.CompilerDirectives;
4347
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4448
import com.oracle.truffle.api.frame.VirtualFrame;
4549
import com.oracle.truffle.api.nodes.ExplodeLoop;
@@ -48,20 +52,55 @@
4852
public final class ListLiteralNode extends LiteralNode {
4953
@Child private PythonObjectFactory factory = PythonObjectFactory.create();
5054
@Children protected final ExpressionNode[] values;
55+
@Child private SequenceStorageNodes.ConcatNode concatStoragesNode;
56+
@Child private SequenceStorageNodes.AppendNode appendNode;
57+
58+
private final boolean hasStarredExpressions;
5159

5260
@CompilationFinal private ListStorageType type = ListStorageType.Uninitialized;
5361

5462
public ListLiteralNode(ExpressionNode[] values) {
5563
this.values = values;
64+
for (PNode v : values) {
65+
if (v instanceof StarredExpressionNode) {
66+
hasStarredExpressions = true;
67+
return;
68+
}
69+
}
70+
hasStarredExpressions = false;
5671
}
5772

5873
public ExpressionNode[] getValues() {
5974
return values;
6075
}
6176

77+
@ExplodeLoop
78+
private PList expandingList(VirtualFrame frame) {
79+
// we will usually have more than 'values.length' elements
80+
SequenceStorage storage = new ObjectSequenceStorage(values.length);
81+
for (ExpressionNode n : values) {
82+
if (n instanceof StarredExpressionNode) {
83+
SequenceStorage addElements = ((StarredExpressionNode) n).getStorage(frame);
84+
storage = ensureConcatStoragesNode().execute(storage, addElements);
85+
} else {
86+
Object element = n.execute(frame);
87+
storage = ensureAppendNode().execute(storage, element, ListGeneralizationNode.SUPPLIER);
88+
}
89+
}
90+
return factory.createList(storage);
91+
}
92+
6293
@Override
94+
public PList execute(VirtualFrame frame) {
95+
if (!hasStarredExpressions) {
96+
return directList(frame);
97+
} else {
98+
return expandingList(frame);
99+
}
100+
}
101+
63102
@ExplodeLoop
64-
public Object execute(VirtualFrame frame) {
103+
private PList directList(VirtualFrame frame) {
65104
SequenceStorage storage;
66105
if (type == ListStorageType.Uninitialized) {
67106
try {
@@ -169,6 +208,22 @@ private SequenceStorage genericFallback(VirtualFrame frame, Object array, int co
169208
return new ObjectSequenceStorage(elements);
170209
}
171210

211+
private SequenceStorageNodes.ConcatNode ensureConcatStoragesNode() {
212+
if (concatStoragesNode == null) {
213+
CompilerDirectives.transferToInterpreterAndInvalidate();
214+
concatStoragesNode = insert(SequenceStorageNodes.ConcatNode.create(ListGeneralizationNode::create));
215+
}
216+
return concatStoragesNode;
217+
}
218+
219+
private SequenceStorageNodes.AppendNode ensureAppendNode() {
220+
if (appendNode == null) {
221+
CompilerDirectives.transferToInterpreterAndInvalidate();
222+
appendNode = insert(SequenceStorageNodes.AppendNode.create());
223+
}
224+
return appendNode;
225+
}
226+
172227
public static ListLiteralNode create(ExpressionNode[] values) {
173228
return new ListLiteralNode(values);
174229
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/literal/StarredExpressionNode.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.oracle.graal.python.nodes.expression.CastToListExpressionNode;
4444
import com.oracle.graal.python.nodes.expression.CastToListExpressionNodeGen;
4545
import com.oracle.graal.python.nodes.expression.ExpressionNode;
46+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
4647
import com.oracle.truffle.api.frame.VirtualFrame;
4748

4849
public final class StarredExpressionNode extends LiteralNode {
@@ -60,8 +61,8 @@ public ExpressionNode getValue() {
6061
return childNode.getOperand();
6162
}
6263

63-
public Object[] getArray(VirtualFrame frame) {
64-
return childNode.getArray(frame);
64+
public SequenceStorage getStorage(VirtualFrame frame) {
65+
return childNode.getStorage(frame);
6566
}
6667

6768
@Override

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/literal/TupleLiteralNode.java

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,23 @@
2525
*/
2626
package com.oracle.graal.python.nodes.literal;
2727

28-
import java.util.ArrayList;
29-
import java.util.Arrays;
30-
import java.util.List;
31-
28+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
29+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.NoGeneralizationNode;
3230
import com.oracle.graal.python.nodes.PNode;
3331
import com.oracle.graal.python.nodes.expression.ExpressionNode;
3432
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
35-
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
33+
import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage;
34+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
35+
import com.oracle.truffle.api.CompilerDirectives;
3636
import com.oracle.truffle.api.frame.VirtualFrame;
3737
import com.oracle.truffle.api.nodes.ExplodeLoop;
3838

3939
public final class TupleLiteralNode extends LiteralNode {
4040
@Child private PythonObjectFactory factory = PythonObjectFactory.create();
4141
@Children private final ExpressionNode[] values;
42-
protected final boolean hasStarredExpressions;
42+
@Child private SequenceStorageNodes.ConcatNode concatStoragesNode;
43+
@Child private SequenceStorageNodes.AppendNode appendNode;
44+
private final boolean hasStarredExpressions;
4345

4446
public ExpressionNode[] getValues() {
4547
return values;
@@ -67,42 +69,18 @@ public Object execute(VirtualFrame frame) {
6769

6870
@ExplodeLoop
6971
private Object expandingTuple(VirtualFrame frame) {
70-
List<Object> elements = makeList();
72+
// we will usually have more than 'values.length' elements
73+
SequenceStorage storage = new ObjectSequenceStorage(values.length);
7174
for (ExpressionNode n : values) {
7275
if (n instanceof StarredExpressionNode) {
73-
Object[] array = ((StarredExpressionNode) n).getArray(frame);
74-
addAllElements(elements, array);
76+
SequenceStorage addElements = ((StarredExpressionNode) n).getStorage(frame);
77+
storage = ensureConcatStoragesNode().execute(storage, addElements);
7578
} else {
7679
Object element = n.execute(frame);
77-
addElement(elements, element);
80+
storage = ensureAppendNode().execute(storage, element, NoGeneralizationNode.DEFAULT);
7881
}
7982
}
80-
return factory.createTuple(listToArray(elements));
81-
}
82-
83-
@TruffleBoundary
84-
private static Object[] listToArray(List<Object> elements) {
85-
return elements.toArray();
86-
}
87-
88-
@TruffleBoundary
89-
private static void addElement(List<Object> elements, Object element) {
90-
elements.add(element);
91-
}
92-
93-
@TruffleBoundary
94-
private static void addAllElements(List<Object> elements, Object[] array) {
95-
elements.addAll(asList(array));
96-
}
97-
98-
@TruffleBoundary
99-
private static List<Object> asList(Object[] results) {
100-
return Arrays.asList(results);
101-
}
102-
103-
@TruffleBoundary
104-
private ArrayList<Object> makeList() {
105-
return new ArrayList<>(values.length);
83+
return factory.createTuple(storage);
10684
}
10785

10886
@ExplodeLoop
@@ -113,4 +91,20 @@ private Object directTuple(VirtualFrame frame) {
11391
}
11492
return factory.createTuple(elements);
11593
}
94+
95+
private SequenceStorageNodes.ConcatNode ensureConcatStoragesNode() {
96+
if (concatStoragesNode == null) {
97+
CompilerDirectives.transferToInterpreterAndInvalidate();
98+
concatStoragesNode = insert(SequenceStorageNodes.ConcatNode.create());
99+
}
100+
return concatStoragesNode;
101+
}
102+
103+
private SequenceStorageNodes.AppendNode ensureAppendNode() {
104+
if (appendNode == null) {
105+
CompilerDirectives.transferToInterpreterAndInvalidate();
106+
appendNode = insert(SequenceStorageNodes.AppendNode.create());
107+
}
108+
return appendNode;
109+
}
116110
}

0 commit comments

Comments
 (0)