|
123 | 123 | import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode;
|
124 | 124 | import com.oracle.graal.python.nodes.argument.ReadVarArgsNode;
|
125 | 125 | import com.oracle.graal.python.nodes.attributes.DeleteAttributeNode;
|
| 126 | +import com.oracle.graal.python.nodes.attributes.GetAttributeNode; |
126 | 127 | import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode;
|
127 | 128 | import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
|
128 | 129 | import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
|
|
153 | 154 | import com.oracle.graal.python.nodes.subscript.GetItemNode;
|
154 | 155 | import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
|
155 | 156 | import com.oracle.graal.python.nodes.util.CastToIntegerFromIndexNode;
|
156 |
| -import com.oracle.graal.python.runtime.PythonContext; |
| 157 | +import com.oracle.graal.python.nodes.util.CastToStringNode; |
157 | 158 | import com.oracle.graal.python.runtime.PythonCore;
|
158 | 159 | import com.oracle.graal.python.runtime.PythonOptions;
|
159 | 160 | import com.oracle.graal.python.runtime.PythonParser.ParserMode;
|
160 | 161 | import com.oracle.graal.python.runtime.exception.PException;
|
161 | 162 | import com.oracle.graal.python.runtime.exception.PythonErrorType;
|
162 | 163 | import com.oracle.graal.python.runtime.sequence.PSequence;
|
163 |
| -import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; |
| 164 | +import com.oracle.truffle.api.Assumption; |
164 | 165 | import com.oracle.truffle.api.CompilerDirectives;
|
| 166 | +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; |
165 | 167 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
166 | 168 | import com.oracle.truffle.api.Truffle;
|
167 | 169 | import com.oracle.truffle.api.dsl.Cached;
|
@@ -1326,45 +1328,113 @@ public int ord(PBytes chr,
|
1326 | 1328 | }
|
1327 | 1329 |
|
1328 | 1330 | // print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
|
1329 |
| - @Builtin(name = PRINT, fixedNumOfPositionalArgs = 5) |
| 1331 | + @Builtin(name = PRINT, takesVarArgs = true, keywordArguments = {"sep", "end", "file", "flush"}, doc = "\n" + |
| 1332 | + "print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n" + |
| 1333 | + "\n" + |
| 1334 | + "Prints the values to a stream, or to sys.stdout by default.\n" + |
| 1335 | + "Optional keyword arguments:\n" + |
| 1336 | + "file: a file-like object (stream); defaults to the current sys.stdout.\n" + |
| 1337 | + "sep: string inserted between values, default a space.\n" + |
| 1338 | + "end: string appended after the last value, default a newline.\n" + |
| 1339 | + "flush: whether to forcibly flush the stream.") |
1330 | 1340 | @GenerateNodeFactory
|
1331 | 1341 | public abstract static class PrintNode extends PythonBuiltinNode {
|
1332 |
| - @SuppressWarnings("unused") |
| 1342 | + private static final String DEFAULT_END = "\n"; |
| 1343 | + private static final String DEFAULT_SEPARATOR = " "; |
| 1344 | + @Child ReadAttributeFromObjectNode readStdout; |
| 1345 | + @Child GetAttributeNode getWrite = GetAttributeNode.create("write", null); |
| 1346 | + @Child CallNode callWrite = CallNode.create(); |
| 1347 | + @Child CastToStringNode toString = CastToStringNode.createCoercing(); |
| 1348 | + @Child private LookupAndCallUnaryNode callFlushNode; |
| 1349 | + @CompilationFinal private Assumption singleContextAssumption; |
| 1350 | + @CompilationFinal private PythonModule cachedSys; |
| 1351 | + |
1333 | 1352 | @Specialization
|
1334 |
| - public Object print(PTuple values, String sep, String end, Object file, boolean flush, |
1335 |
| - @Cached("create()") SequenceStorageNodes.LenNode lenNode, |
1336 |
| - @Cached("createNotNormalized()") SequenceStorageNodes.GetItemNode getItemNode, |
1337 |
| - @Cached("create(__STR__)") LookupAndCallUnaryNode callStr) { |
1338 |
| - try { |
1339 |
| - PythonContext context = getContext(); |
1340 |
| - if (lenNode.execute(values.getSequenceStorage()) == 0) { |
1341 |
| - write(context, end); |
1342 |
| - } else { |
1343 |
| - SequenceStorage store = values.getSequenceStorage(); |
1344 |
| - StringBuilder sb = new StringBuilder(); |
1345 |
| - for (int i = 0; i < store.length() - 1; i++) { |
1346 |
| - append(sb, callStr.executeObject(getItemNode.execute(store, i))); |
1347 |
| - append(sb, " "); |
1348 |
| - } |
1349 |
| - append(sb, callStr.executeObject(getItemNode.execute(store, store.length() - 1))); |
1350 |
| - append(sb, end); |
1351 |
| - write(context, sb.toString()); |
| 1353 | + PNone printNoKeywords(VirtualFrame frame, Object[] values, @SuppressWarnings("unused") PNone sep, @SuppressWarnings("unused") PNone end, @SuppressWarnings("unused") PNone file, |
| 1354 | + @SuppressWarnings("unused") PNone flush) { |
| 1355 | + Object stdout = getStdout(); |
| 1356 | + return printAllGiven(frame, values, DEFAULT_SEPARATOR, DEFAULT_END, stdout, false); |
| 1357 | + } |
| 1358 | + |
| 1359 | + @Specialization(guards = {"!isNone(file)", "!isNoValue(file)"}) |
| 1360 | + PNone printAllGiven(VirtualFrame frame, Object[] values, String sep, String end, Object file, boolean flush) { |
| 1361 | + int lastValue = values.length - 1; |
| 1362 | + Object write = getWrite.executeObject(file); |
| 1363 | + for (int i = 0; i < lastValue; i++) { |
| 1364 | + callWrite.execute(frame, write, toString.execute(values[i])); |
| 1365 | + callWrite.execute(frame, write, sep); |
| 1366 | + } |
| 1367 | + if (lastValue >= 0) { |
| 1368 | + callWrite.execute(frame, write, toString.execute(values[lastValue])); |
| 1369 | + } |
| 1370 | + callWrite.execute(frame, write, end); |
| 1371 | + if (flush) { |
| 1372 | + if (callFlushNode == null) { |
| 1373 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1374 | + callFlushNode = insert(LookupAndCallUnaryNode.create("flush")); |
1352 | 1375 | }
|
1353 |
| - } catch (IOException e) { |
1354 |
| - // pass through |
| 1376 | + callFlushNode.executeObject(file); |
1355 | 1377 | }
|
1356 |
| - |
1357 | 1378 | return PNone.NONE;
|
1358 | 1379 | }
|
1359 | 1380 |
|
1360 |
| - @TruffleBoundary(transferToInterpreterOnException = false) |
1361 |
| - private static void append(StringBuilder sb, Object o) { |
1362 |
| - sb.append(o); |
| 1381 | + @Specialization(replaces = {"printAllGiven", "printNoKeywords"}) |
| 1382 | + PNone printGeneric(VirtualFrame frame, Object[] values, Object sepIn, Object endIn, Object fileIn, Object flushIn, |
| 1383 | + @Cached("createCoercing()") CastToStringNode castSep, |
| 1384 | + @Cached("createCoercing()") CastToStringNode castEnd, |
| 1385 | + @Cached("createIfTrueNode()") CastToBooleanNode castFlush) { |
| 1386 | + String sep; |
| 1387 | + if (sepIn instanceof PNone) { |
| 1388 | + sep = DEFAULT_SEPARATOR; |
| 1389 | + } else { |
| 1390 | + sep = castSep.execute(sepIn); |
| 1391 | + } |
| 1392 | + String end; |
| 1393 | + if (endIn instanceof PNone) { |
| 1394 | + end = DEFAULT_END; |
| 1395 | + } else { |
| 1396 | + end = castEnd.execute(endIn); |
| 1397 | + } |
| 1398 | + Object file; |
| 1399 | + if (fileIn instanceof PNone) { |
| 1400 | + file = getStdout(); |
| 1401 | + } else { |
| 1402 | + file = fileIn; |
| 1403 | + } |
| 1404 | + boolean flush; |
| 1405 | + if (flushIn instanceof PNone) { |
| 1406 | + flush = false; |
| 1407 | + } else { |
| 1408 | + flush = castFlush.executeWith(flushIn); |
| 1409 | + } |
| 1410 | + return printAllGiven(frame, values, sep, end, file, flush); |
1363 | 1411 | }
|
1364 | 1412 |
|
1365 |
| - @TruffleBoundary |
1366 |
| - private static void write(PythonContext context, String string) throws IOException { |
1367 |
| - context.getStandardOut().write(string.getBytes()); |
| 1413 | + private Object getStdout() { |
| 1414 | + if (singleContextAssumption == null) { |
| 1415 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1416 | + singleContextAssumption = singleContextAssumption(); |
| 1417 | + } |
| 1418 | + PythonModule sys; |
| 1419 | + if (singleContextAssumption.isValid()) { |
| 1420 | + if (cachedSys == null) { |
| 1421 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1422 | + cachedSys = getContext().getCore().lookupBuiltinModule("sys"); |
| 1423 | + } |
| 1424 | + sys = cachedSys; |
| 1425 | + } else { |
| 1426 | + if (cachedSys != null) { |
| 1427 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1428 | + cachedSys = null; |
| 1429 | + } |
| 1430 | + sys = getContext().getCore().lookupBuiltinModule("sys"); |
| 1431 | + } |
| 1432 | + if (readStdout == null) { |
| 1433 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1434 | + readStdout = insert(ReadAttributeFromObjectNode.create()); |
| 1435 | + } |
| 1436 | + Object stdout = readStdout.execute(sys, "stdout"); |
| 1437 | + return stdout; |
1368 | 1438 | }
|
1369 | 1439 | }
|
1370 | 1440 |
|
|
0 commit comments