Skip to content

Commit 4114adf

Browse files
committed
[GR-25469] Use cast nodes in format nodes.
PullRequest: graalpython/1179
2 parents 1ef433f + 59a5be1 commit 4114adf

File tree

9 files changed

+228
-102
lines changed

9 files changed

+228
-102
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ def test_formatting():
8888
assert format(1234.5, "+n").startswith("+")
8989

9090

91+
def test_int_format():
92+
class PolymorphInt(int):
93+
def __float__(self):
94+
return 42.5
95+
96+
assert format(PolymorphInt(2), "g") == '42.5'
97+
98+
9199
class MyComplex(complex):
92100
def __repr__(self):
93101
return 'wrong answer'

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -957,8 +957,9 @@ Object floatFromLong(Object cls, long arg) {
957957
return factory().createFloat(cls, arg);
958958
}
959959

960-
@Specialization(guards = "!isNativeClass(cls)")
961-
Object floatFromPInt(Object cls, PInt arg) {
960+
@Specialization(guards = {"!isNativeClass(cls)", "cannotBeOverridden(plib.getLazyPythonClass(arg))"})
961+
Object floatFromPInt(Object cls, PInt arg,
962+
@CachedLibrary(limit = "1") @SuppressWarnings("unused") PythonObjectLibrary plib) {
962963
double value = arg.doubleValue();
963964
if (Double.isInfinite(value)) {
964965
throw raise(OverflowError, ErrorMessages.TOO_LARGE_TO_CONVERT_TO, "int", "float");
@@ -1096,11 +1097,14 @@ Object floatFromNone(Object cls, @SuppressWarnings("unused") PNone arg) {
10961097
return factory().createFloat(cls, 0.0);
10971098
}
10981099

1099-
static boolean isHandledType(Object o) {
1100+
static boolean isHandledType(PythonObjectLibrary lib, Object o) {
1101+
if (o instanceof PInt) {
1102+
return PGuards.cannotBeOverridden(lib.getLazyPythonClass(o));
1103+
}
11001104
return PGuards.canBeInteger(o) || PGuards.isDouble(o) || o instanceof String || PGuards.isPNone(o);
11011105
}
11021106

1103-
@Specialization(guards = {"isPrimitiveFloat(cls)", "!isHandledType(obj)"})
1107+
@Specialization(guards = {"isPrimitiveFloat(cls)", "!isHandledType(lib, obj)"})
11041108
double doubleFromObject(VirtualFrame frame, @SuppressWarnings("unused") Object cls, Object obj,
11051109
@CachedLibrary(limit = "1") PythonObjectLibrary lib) {
11061110
// Follows logic from PyNumber_Float:
@@ -3181,11 +3185,6 @@ private String getStringArg(Object arg) {
31813185
throw raise(SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
31823186
}
31833187
}
3184-
3185-
@TruffleBoundary
3186-
private static byte[] toBytes(String data) {
3187-
return data.getBytes();
3188-
}
31893188
}
31903189

31913190
@Builtin(name = "cell", constructsClass = PythonBuiltinClassType.PCell, isPublic = false)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.objects.common;
42+
43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
44+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
45+
46+
import com.oracle.graal.python.nodes.ErrorMessages;
47+
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
48+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
49+
import com.oracle.graal.python.nodes.util.CannotCastException;
50+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
51+
import com.oracle.truffle.api.CompilerDirectives;
52+
53+
public abstract class FormatNodeBase extends PythonBinaryBuiltinNode {
54+
@Child private LookupAndCallUnaryNode strCall;
55+
56+
protected LookupAndCallUnaryNode ensureStrCallNode() {
57+
if (strCall == null) {
58+
CompilerDirectives.transferToInterpreterAndInvalidate();
59+
strCall = insert(LookupAndCallUnaryNode.create(__STR__));
60+
}
61+
return strCall;
62+
}
63+
64+
protected String castFormatString(Object obj, CastToJavaStringNode castNode) {
65+
try {
66+
return castNode.execute(obj);
67+
} catch (CannotCastException ex) {
68+
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", obj);
69+
}
70+
}
71+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,19 @@
8383
import com.oracle.graal.python.builtins.PythonBuiltins;
8484
import com.oracle.graal.python.builtins.objects.PNone;
8585
import com.oracle.graal.python.builtins.objects.PNotImplemented;
86+
import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
8687
import com.oracle.graal.python.builtins.objects.floats.FloatBuiltins;
8788
import com.oracle.graal.python.builtins.objects.ints.PInt;
8889
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
8990
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
9091
import com.oracle.graal.python.nodes.ErrorMessages;
91-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
9292
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
9393
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
9494
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
9595
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
9696
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9797
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
98+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
9899
import com.oracle.graal.python.nodes.util.CoerceToComplexNode;
99100
import com.oracle.graal.python.runtime.PythonCore;
100101
import com.oracle.graal.python.runtime.exception.PythonErrorType;
@@ -734,29 +735,27 @@ abstract static class StrNode extends ReprNode {
734735
@Builtin(name = __FORMAT__, minNumOfPositionalArgs = 2)
735736
@GenerateNodeFactory
736737
@TypeSystemReference(PythonArithmeticTypes.class)
737-
abstract static class FormatNode extends PythonBinaryBuiltinNode {
738-
739-
@Specialization(guards = "formatString.isEmpty()")
740-
Object emptyFormat(VirtualFrame frame, Object self, @SuppressWarnings("unused") String formatString,
741-
@Cached("create(__STR__)") LookupAndCallUnaryNode strCall) {
742-
return strCall.executeObject(frame, self);
738+
abstract static class FormatNode extends FormatNodeBase {
739+
@Specialization
740+
Object format(VirtualFrame frame, PComplex self, Object formatStringObj,
741+
@Cached CastToJavaStringNode castToStringNode) {
742+
String formatString = castFormatString(formatStringObj, castToStringNode);
743+
if (formatString.isEmpty()) {
744+
return ensureStrCallNode().executeObject(frame, self);
745+
}
746+
PythonCore core = getCore();
747+
InternalFormat.Spec spec = InternalFormat.fromText(core, formatString, __FORMAT__);
748+
validateSpec(spec);
749+
return doFormat(self, spec, core);
743750
}
744751

745-
@Specialization(guards = "!formatString.isEmpty()")
746752
@TruffleBoundary
747-
String format(PComplex self, String formatString) {
748-
InternalFormat.Spec spec = InternalFormat.fromText(getCore(), formatString, __FORMAT__);
749-
validateSpec(spec);
750-
ComplexFormatter formatter = new ComplexFormatter(getCore(), validateAndPrepareForFloat(spec, getCore(), "complex"));
753+
private static Object doFormat(PComplex self, Spec spec, PythonCore core) {
754+
ComplexFormatter formatter = new ComplexFormatter(core, validateAndPrepareForFloat(spec, core, "complex"));
751755
formatter.format(self);
752756
return formatter.pad().getResult();
753757
}
754758

755-
@Fallback
756-
Object doOther(@SuppressWarnings("unused") Object self, Object format) {
757-
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", format);
758-
}
759-
760759
private void validateSpec(Spec spec) {
761760
if (spec.getFill(' ') == '0') {
762761
throw raise(ValueError, ErrorMessages.ZERO_PADDING_NOT_ALLOWED_FOR_COMPLEX_FMT);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java

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

2828
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError;
29-
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
3029
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
3130
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ABS__;
3231
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ADD__;
@@ -81,13 +80,13 @@
8180
import com.oracle.graal.python.builtins.objects.PNotImplemented;
8281
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.FromNativeSubclassNode;
8382
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
83+
import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
8484
import com.oracle.graal.python.builtins.objects.ints.PInt;
8585
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
8686
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
8787
import com.oracle.graal.python.nodes.ErrorMessages;
8888
import com.oracle.graal.python.nodes.SpecialMethodNames;
8989
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
90-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
9190
import com.oracle.graal.python.nodes.call.special.LookupAndCallVarargsNode;
9291
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
9392
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -97,7 +96,9 @@
9796
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9897
import com.oracle.graal.python.nodes.object.GetClassNode;
9998
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
99+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
100100
import com.oracle.graal.python.runtime.PythonContext;
101+
import com.oracle.graal.python.runtime.PythonCore;
101102
import com.oracle.graal.python.runtime.exception.PythonErrorType;
102103
import com.oracle.graal.python.runtime.formatting.FloatFormatter;
103104
import com.oracle.graal.python.runtime.formatting.InternalFormat;
@@ -169,28 +170,34 @@ abstract static class ReprNode extends StrNode {
169170

170171
@Builtin(name = __FORMAT__, minNumOfPositionalArgs = 2)
171172
@GenerateNodeFactory
172-
@TypeSystemReference(PythonArithmeticTypes.class)
173-
abstract static class FormatNode extends PythonBinaryBuiltinNode {
173+
abstract static class FormatNode extends FormatNodeBase {
174+
@Specialization
175+
Object formatPF(VirtualFrame frame, PFloat self, Object formatStringObj,
176+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
177+
String formatString = castFormatString(formatStringObj, castToStringNode);
178+
if (formatString.isEmpty()) {
179+
return ensureStrCallNode().executeObject(frame, self);
180+
}
181+
return doFormat(self.getValue(), formatString, getCore());
182+
}
174183

175-
@Specialization(guards = "formatString.isEmpty()")
176-
Object emptyFormat(VirtualFrame frame, Object self, @SuppressWarnings("unused") String formatString,
177-
@Cached("create(__STR__)") LookupAndCallUnaryNode strCall) {
178-
return strCall.executeObject(frame, self);
184+
@Specialization
185+
Object formatD(VirtualFrame frame, double self, Object formatStringObj,
186+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
187+
String formatString = castFormatString(formatStringObj, castToStringNode);
188+
if (formatString.isEmpty()) {
189+
return ensureStrCallNode().executeObject(frame, self);
190+
}
191+
return doFormat(self, formatString, getCore());
179192
}
180193

181-
@Specialization(guards = "!formatString.isEmpty()")
182194
@TruffleBoundary
183-
String format(double self, String formatString) {
184-
InternalFormat.Spec spec = InternalFormat.fromText(getCore(), formatString, __FORMAT__);
185-
FloatFormatter formatter = new FloatFormatter(getCore(), validateAndPrepareForFloat(spec, getCore(), "float"));
195+
private String doFormat(double self, String formatString, PythonCore core) {
196+
InternalFormat.Spec spec = InternalFormat.fromText(core, formatString, __FORMAT__);
197+
FloatFormatter formatter = new FloatFormatter(core, validateAndPrepareForFloat(spec, getCore(), "float"));
186198
formatter.format(self);
187199
return formatter.pad().getResult();
188200
}
189-
190-
@Fallback
191-
String other(@SuppressWarnings("unused") Object self, Object formatString) {
192-
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", formatString);
193-
}
194201
}
195202

196203
@Builtin(name = __ABS__, minNumOfPositionalArgs = 1)

0 commit comments

Comments
 (0)