Skip to content

Commit e81734b

Browse files
committed
Add more conversion nodes
1 parent 8b00b65 commit e81734b

File tree

3 files changed

+389
-0
lines changed

3 files changed

+389
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__FLOAT__;
44+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INDEX__;
45+
46+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
47+
import com.oracle.graal.python.builtins.objects.PNone;
48+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
49+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
50+
import com.oracle.graal.python.nodes.PNodeWithContext;
51+
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
52+
import com.oracle.graal.python.nodes.object.GetClassNode;
53+
import com.oracle.truffle.api.dsl.Cached;
54+
import com.oracle.truffle.api.dsl.GenerateUncached;
55+
import com.oracle.truffle.api.dsl.Specialization;
56+
import com.oracle.truffle.api.interop.InteropLibrary;
57+
import com.oracle.truffle.api.library.CachedLibrary;
58+
59+
/**
60+
* Checks whether a value can be converted to {@code double} using {@link PyFloatAsDoubleNode} o
61+
* {@link PyNumberFloatNode}. There is no direct CPython function equivalent, as CPython typically
62+
* checks for the {@code nb_float} and {@code nb_index} slots directly.
63+
*/
64+
@GenerateUncached
65+
public abstract class CanBeDoubleNode extends PNodeWithContext {
66+
public abstract boolean execute(Object object);
67+
68+
@Specialization
69+
static boolean doDouble(@SuppressWarnings("unused") Double object) {
70+
return true;
71+
}
72+
73+
@Specialization
74+
static boolean doInt(@SuppressWarnings("unused") Integer object) {
75+
return true;
76+
}
77+
78+
@Specialization
79+
static boolean doLong(@SuppressWarnings("unused") Long object) {
80+
return true;
81+
}
82+
83+
@Specialization
84+
static boolean doPythonObject(PythonAbstractObject object,
85+
@Cached GetClassNode getClassNode,
86+
@Cached LookupAttributeInMRONode.Dynamic lookupFloat,
87+
@Cached LookupAttributeInMRONode.Dynamic lookupIndex) {
88+
Object type = getClassNode.execute(object);
89+
return lookupFloat.execute(type, __FLOAT__) != PNone.NO_VALUE || lookupIndex.execute(type, __INDEX__) != PNone.NO_VALUE;
90+
}
91+
92+
@Specialization
93+
static boolean doBoolean(@SuppressWarnings("unused") Boolean object) {
94+
return true;
95+
}
96+
97+
@Specialization
98+
static boolean doString(@SuppressWarnings("unused") String object) {
99+
return false;
100+
}
101+
102+
@Specialization
103+
static boolean doPBCT(@SuppressWarnings("unused") PythonBuiltinClassType object) {
104+
return false;
105+
}
106+
107+
@Specialization(replaces = "doPythonObject", limit = "3")
108+
static boolean doGeneric(Object object,
109+
@CachedLibrary("object") PythonObjectLibrary lib,
110+
@CachedLibrary(limit = "3") InteropLibrary interopLibrary,
111+
@Cached LookupAttributeInMRONode.Dynamic lookupFloat,
112+
@Cached LookupAttributeInMRONode.Dynamic lookupIndex,
113+
@Cached GetClassNode getClassNode) {
114+
if (lib.isForeignObject(object)) {
115+
return interopLibrary.fitsInDouble(object) || interopLibrary.fitsInLong(object) || interopLibrary.isBoolean(object);
116+
}
117+
Object type = getClassNode.execute(object);
118+
return lookupFloat.execute(type, __FLOAT__) != PNone.NO_VALUE || lookupIndex.execute(type, __INDEX__) != PNone.NO_VALUE;
119+
}
120+
121+
public static CanBeDoubleNode create() {
122+
return CanBeDoubleNodeGen.create();
123+
}
124+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
44+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
45+
46+
import com.oracle.graal.python.builtins.objects.floats.FloatUtils;
47+
import com.oracle.graal.python.builtins.objects.object.ObjectNodes;
48+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
49+
import com.oracle.graal.python.nodes.ErrorMessages;
50+
import com.oracle.graal.python.nodes.PNodeWithContext;
51+
import com.oracle.graal.python.nodes.PRaiseNode;
52+
import com.oracle.graal.python.nodes.util.CannotCastException;
53+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
54+
import com.oracle.graal.python.runtime.exception.PException;
55+
import com.oracle.graal.python.util.PythonUtils;
56+
import com.oracle.truffle.api.CompilerDirectives;
57+
import com.oracle.truffle.api.dsl.Cached;
58+
import com.oracle.truffle.api.dsl.Cached.Shared;
59+
import com.oracle.truffle.api.dsl.GenerateUncached;
60+
import com.oracle.truffle.api.dsl.Specialization;
61+
import com.oracle.truffle.api.frame.Frame;
62+
import com.oracle.truffle.api.frame.VirtualFrame;
63+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
64+
import com.oracle.truffle.api.library.CachedLibrary;
65+
66+
/**
67+
* Equivalent of CPython's {@code PyFloat_FromString}. Converts a string to a python float (Java
68+
* {@code double}). Raises {@code ValueError} when the conversion fails.
69+
*/
70+
@GenerateUncached
71+
public abstract class PyFloatFromString extends PNodeWithContext {
72+
public abstract double execute(Frame frame, Object obj);
73+
74+
public abstract double execute(Frame frame, String obj);
75+
76+
@Specialization
77+
double doString(VirtualFrame frame, String object,
78+
@Shared("repr") @Cached ObjectNodes.ReprAsJavaStringNode reprNode,
79+
@Shared("raise") @Cached PRaiseNode raiseNode) {
80+
return convertStringToDouble(frame, object, object, reprNode, raiseNode);
81+
}
82+
83+
@Specialization
84+
double doGeneric(VirtualFrame frame, Object object,
85+
@Cached CastToJavaStringNode cast,
86+
@CachedLibrary(limit = "3") PythonObjectLibrary lib,
87+
@Shared("repr") @Cached ObjectNodes.ReprAsJavaStringNode reprNode,
88+
@Shared("raise") @Cached PRaiseNode raiseNode) {
89+
String string = null;
90+
try {
91+
string = cast.execute(object);
92+
} catch (CannotCastException e) {
93+
if (lib.isBuffer(object)) {
94+
try {
95+
byte[] bytes = lib.getBufferBytes(object);
96+
string = PythonUtils.newString(bytes);
97+
} catch (UnsupportedMessageException e1) {
98+
throw CompilerDirectives.shouldNotReachHere();
99+
}
100+
}
101+
}
102+
if (string != null) {
103+
return convertStringToDouble(frame, string, object, reprNode, raiseNode);
104+
}
105+
throw raiseNode.raise(TypeError, ErrorMessages.ARG_MUST_BE_STRING_OR_NUMBER, "float()", object);
106+
}
107+
108+
private static double convertStringToDouble(VirtualFrame frame, String src, Object origObj, ObjectNodes.ReprAsJavaStringNode reprNode, PRaiseNode raiseNode) {
109+
String str = FloatUtils.removeUnicodeAndUnderscores(src);
110+
// Adapted from CPython's float_from_string_inner
111+
if (str != null) {
112+
int len = str.length();
113+
int offset = FloatUtils.skipAsciiWhitespace(str, 0, len);
114+
FloatUtils.StringToDoubleResult res = FloatUtils.stringToDouble(str, offset, len);
115+
if (res != null) {
116+
int end = FloatUtils.skipAsciiWhitespace(str, res.position, len);
117+
if (end == len) {
118+
return res.value;
119+
}
120+
}
121+
}
122+
String repr;
123+
try {
124+
repr = reprNode.execute(frame, origObj);
125+
} catch (PException e) {
126+
// Failed to format the message. Mirrors CPython behavior when the repr fails
127+
throw raiseNode.raise(ValueError);
128+
}
129+
throw raiseNode.raise(ValueError, ErrorMessages.COULD_NOT_CONVERT_STRING_TO_FLOAT, repr);
130+
}
131+
132+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.DeprecationWarning;
44+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
45+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__FLOAT__;
46+
47+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
48+
import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins;
49+
import com.oracle.graal.python.builtins.objects.PNone;
50+
import com.oracle.graal.python.nodes.ErrorMessages;
51+
import com.oracle.graal.python.nodes.PGuards;
52+
import com.oracle.graal.python.nodes.PNodeWithContext;
53+
import com.oracle.graal.python.nodes.PRaiseNode;
54+
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
55+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode;
56+
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
57+
import com.oracle.graal.python.nodes.object.GetClassNode;
58+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
59+
import com.oracle.graal.python.nodes.util.CastToJavaDoubleNode;
60+
import com.oracle.truffle.api.dsl.Cached;
61+
import com.oracle.truffle.api.dsl.GenerateUncached;
62+
import com.oracle.truffle.api.dsl.ImportStatic;
63+
import com.oracle.truffle.api.dsl.Specialization;
64+
import com.oracle.truffle.api.frame.Frame;
65+
import com.oracle.truffle.api.frame.VirtualFrame;
66+
67+
/**
68+
* Equivalent of CPython's {@code PyNumber_Float}. Converts the argument to a Java {@code double}
69+
* using its {@code __float__} special method. If not available, falls back to {@code __index__}
70+
* special method. If not available, falls back to {@link PyFloatFromString}. Otherwise, raises a
71+
* {@code TypeError}. Can raise {@code OverflowError} when using {@code __index__} and the returned
72+
* integer wouldn't fit into double.
73+
*/
74+
@GenerateUncached
75+
@ImportStatic({PGuards.class, PythonBuiltinClassType.class})
76+
public abstract class PyNumberFloatNode extends PNodeWithContext {
77+
public abstract double execute(Frame frame, Object object);
78+
79+
@Specialization
80+
double doDouble(double object) {
81+
return object;
82+
}
83+
84+
@Specialization
85+
double doInt(int object) {
86+
return object;
87+
}
88+
89+
@Specialization
90+
double doLong(long object) {
91+
return object;
92+
}
93+
94+
@Specialization
95+
double doBoolean(boolean object) {
96+
return object ? 1.0 : 0.0;
97+
}
98+
99+
@Specialization(guards = {"!isDouble(object)", "!isInteger(object)", "!isBoolean(object)"})
100+
double doObject(VirtualFrame frame, Object object,
101+
@Cached GetClassNode getClassNode,
102+
@Cached LookupSpecialMethodNode.Dynamic lookup,
103+
@Cached CallUnaryMethodNode call,
104+
@Cached GetClassNode resultClassNode,
105+
@Cached IsBuiltinClassProfile resultProfile,
106+
@Cached IsSubtypeNode resultSubtypeNode,
107+
@Cached PyIndexCheckNode indexCheckNode,
108+
@Cached PyNumberIndexNode indexNode,
109+
@Cached CastToJavaDoubleNode cast,
110+
@Cached WarningsModuleBuiltins.WarnNode warnNode,
111+
@Cached PRaiseNode raiseNode,
112+
@Cached PyFloatFromString fromString) {
113+
Object floatDescr = lookup.execute(frame, getClassNode.execute(object), __FLOAT__, object, false);
114+
if (floatDescr != PNone.NO_VALUE) {
115+
Object result = call.executeObject(frame, floatDescr, object);
116+
Object resultType = resultClassNode.execute(result);
117+
if (!resultProfile.profileClass(resultType, PythonBuiltinClassType.PFloat)) {
118+
if (!resultSubtypeNode.execute(resultType, PythonBuiltinClassType.PFloat)) {
119+
throw raiseNode.raise(TypeError, ErrorMessages.RETURNED_NON_FLOAT, object, result);
120+
} else {
121+
warnNode.warnFormat(frame, null, DeprecationWarning, 1,
122+
ErrorMessages.WARN_P_RETURNED_NON_P, object, __FLOAT__, "float", result, "float");
123+
}
124+
}
125+
return cast.execute(result);
126+
}
127+
if (indexCheckNode.execute(object)) {
128+
Object index = indexNode.execute(frame, object);
129+
return cast.execute(index);
130+
}
131+
return fromString.execute(frame, object);
132+
}
133+
}

0 commit comments

Comments
 (0)