Skip to content

Commit 9c6f74b

Browse files
committed
Argument clinic: add long converters & support static fields in defaultValue
1 parent 0b217ac commit 9c6f74b

File tree

6 files changed

+287
-5
lines changed

6 files changed

+287
-5
lines changed

graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/ArgumentClinic.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@
6666

6767
/**
6868
* The string should contain valid Java constant value expression, for example, {@code true}, or
69-
* {@code \"some string\"}. You may have to update the annotation processor to include import of
70-
* necessary packages or use fully qualified names.
69+
* {@code \"some string\"}. Another supported value is an identifier of a static field inside
70+
* the annotated class. For anything else, you may have to update the annotation processor to
71+
* include import of necessary packages or use fully qualified names.
7172
*/
7273
String defaultValue() default "";
7374

@@ -122,10 +123,21 @@ enum ClinicConversion {
122123
*/
123124
Int,
124125
/**
125-
* Corresponds to CPython's {@code Py_ssize_t} converter. Supports {@link #defaultValue()},
126-
* and {@link #useDefaultForNone()}.
126+
* Corresponds to CPython's {@code long} converter ("L"/"l" for old style conversions).
127+
* Supports {@link #defaultValue()}, and {@link #useDefaultForNone()}.
128+
*/
129+
Long,
130+
/**
131+
* Corresponds to CPython's {@code Py_ssize_t} converter, except that it converts the result
132+
* into Java integer. Supports {@link #defaultValue()}, and {@link #useDefaultForNone()}.
127133
*/
128134
Index,
135+
/**
136+
* Roughly corresponds to CPython's legacy "n" converter: calls the __index__ and then
137+
* converts it to Java long. Supports {@link #defaultValue()}, and
138+
* {@link #useDefaultForNone()}.
139+
*/
140+
LongIndex,
129141
/**
130142
* Corresponds to CPython's {@code slice_index} converter. Supports {@link #defaultValue()},
131143
* and {@link #useDefaultForNone()}.

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/ArgumentClinicModel.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@
4444
import java.util.Collections;
4545
import java.util.HashSet;
4646
import java.util.List;
47+
import java.util.Optional;
4748
import java.util.Set;
4849
import java.util.function.Predicate;
50+
import java.util.stream.Stream;
4951

52+
import javax.lang.model.element.Element;
53+
import javax.lang.model.element.ElementKind;
5054
import javax.lang.model.element.TypeElement;
5155

5256
import com.oracle.graal.python.annotations.ArgumentClinic;
@@ -173,7 +177,15 @@ public static ArgumentClinicData create(ArgumentClinic annotation, TypeElement t
173177
// factory method
174178
continue factoryLoop;
175179
}
176-
args[i] = annotation.defaultValue();
180+
String defaultValue = annotation.defaultValue();
181+
Stream<? extends Element> eclosedElements = type.getEnclosedElements().stream();
182+
eclosedElements = eclosedElements.filter(x -> x.getKind() == ElementKind.FIELD && x.getSimpleName().toString().equals(defaultValue));
183+
Optional<? extends Element> typeElement = eclosedElements.findFirst();
184+
if (typeElement.isPresent()) {
185+
args[i] = type.getQualifiedName() + "." + typeElement.get().getSimpleName();
186+
} else {
187+
args[i] = defaultValue;
188+
}
177189
break;
178190
case UseDefaultForNone:
179191
args[i] = String.valueOf(annotation.useDefaultForNone());

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/ConverterFactory.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,11 @@ public enum Param {
9494
private static ConverterFactory[] BuiltinString;
9595
private static ConverterFactory[] BuiltinStringWithDefaultValue;
9696
private static ConverterFactory[] BuiltinInt;
97+
private static ConverterFactory[] BuiltinLong;
9798
private static ConverterFactory[] BuiltinCodePoint;
9899
private static ConverterFactory[] BuiltinBuffer;
99100
private static ConverterFactory[] BuiltinIndex;
101+
private static ConverterFactory[] BuiltinLongIndex;
100102
private static ConverterFactory[] BuiltinSliceIndex;
101103
private static ConverterFactory[] BuiltinNone;
102104
private static ConverterFactory[] BuiltinDouble;
@@ -127,6 +129,8 @@ public static ConverterFactory[] getBuiltin(ArgumentClinic annotation) {
127129
return annotation.defaultValue().isEmpty() ? BuiltinString : BuiltinStringWithDefaultValue;
128130
case Int:
129131
return BuiltinInt;
132+
case Long:
133+
return BuiltinLong;
130134
case Double:
131135
return BuiltinDouble;
132136
case CodePoint:
@@ -135,6 +139,8 @@ public static ConverterFactory[] getBuiltin(ArgumentClinic annotation) {
135139
return BuiltinBuffer;
136140
case Index:
137141
return BuiltinIndex;
142+
case LongIndex:
143+
return BuiltinLongIndex;
138144
case SliceIndex:
139145
return BuiltinSliceIndex;
140146
case None:
@@ -209,10 +215,12 @@ public static void initBuiltins(Elements elementUtils) throws ProcessingError {
209215
BuiltinString = forBuiltin(elementUtils, "JavaStringConverterNode");
210216
BuiltinStringWithDefaultValue = forBuiltin(elementUtils, "JavaStringConverterWithDefaultValueNode");
211217
BuiltinInt = forBuiltin(elementUtils, "JavaIntConversionNode");
218+
BuiltinLong = forBuiltin(elementUtils, "JavaLongConversionNode");
212219
BuiltinDouble = forBuiltin(elementUtils, "JavaDoubleConversionNode");
213220
BuiltinCodePoint = forBuiltin(elementUtils, "CodePointConversionNode");
214221
BuiltinBuffer = forBuiltin(elementUtils, "BufferConversionNode");
215222
BuiltinIndex = forBuiltin(elementUtils, "IndexConversionNode");
223+
BuiltinLongIndex = forBuiltin(elementUtils, "LongIndexConverterNode");
216224
BuiltinSliceIndex = forBuiltin(elementUtils, "SliceIndexConversionNode");
217225
BuiltinNone = forBuiltin(elementUtils, "DefaultValueNode");
218226
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2020, 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.nodes.function.builtins.clinic;
42+
43+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
44+
45+
import com.oracle.graal.python.annotations.ArgumentClinic.PrimitiveType;
46+
import com.oracle.graal.python.annotations.ClinicConverterFactory;
47+
import com.oracle.graal.python.annotations.ClinicConverterFactory.DefaultValue;
48+
import com.oracle.graal.python.annotations.ClinicConverterFactory.UseDefaultForNone;
49+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
50+
import com.oracle.graal.python.builtins.objects.function.PArguments;
51+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
52+
import com.oracle.graal.python.nodes.ErrorMessages;
53+
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
54+
import com.oracle.graal.python.nodes.util.CastToJavaLongLossyNode;
55+
import com.oracle.truffle.api.dsl.Cached;
56+
import com.oracle.truffle.api.dsl.Specialization;
57+
import com.oracle.truffle.api.frame.VirtualFrame;
58+
import com.oracle.truffle.api.library.CachedLibrary;
59+
import com.oracle.truffle.api.profiles.BranchProfile;
60+
61+
public abstract class JavaLongConversionNode extends LongConversionBaseNode {
62+
protected JavaLongConversionNode(long defaultValue, boolean useDefaultForNone) {
63+
super(defaultValue, useDefaultForNone);
64+
}
65+
66+
@Specialization(guards = "!isHandledPNone(value)", limit = "3")
67+
long doOthers(VirtualFrame frame, Object value,
68+
@Cached IsSubtypeNode isSubtypeNode,
69+
@Cached BranchProfile isFloatProfile,
70+
@CachedLibrary("value") PythonObjectLibrary lib,
71+
@Cached CastToJavaLongLossyNode castToLongNode) {
72+
if (isSubtypeNode.execute(lib.getLazyPythonClass(value), PythonBuiltinClassType.PFloat)) {
73+
isFloatProfile.enter();
74+
throw raise(TypeError, ErrorMessages.INTEGER_EXPECTED_GOT_FLOAT);
75+
}
76+
return castToLongNode.execute(lib.asPIntWithState(value, PArguments.getThreadState(frame)));
77+
}
78+
79+
@ClinicConverterFactory(shortCircuitPrimitive = PrimitiveType.Int)
80+
public static JavaLongConversionNode create(@DefaultValue long defaultValue, @UseDefaultForNone boolean useDefaultForNone) {
81+
return JavaLongConversionNodeGen.create(defaultValue, useDefaultForNone);
82+
}
83+
84+
@ClinicConverterFactory(shortCircuitPrimitive = PrimitiveType.Int)
85+
public static JavaLongConversionNode create(@UseDefaultForNone boolean useDefaultForNone) {
86+
assert !useDefaultForNone : "defaultValue must be provided if useDefaultForNone is true";
87+
return JavaLongConversionNodeGen.create(0, false);
88+
}
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2020, 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.nodes.function.builtins.clinic;
42+
43+
import com.oracle.graal.python.builtins.objects.PNone;
44+
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentCastNode.ArgumentCastNodeWithRaise;
45+
import com.oracle.truffle.api.dsl.Specialization;
46+
import com.oracle.truffle.api.frame.VirtualFrame;
47+
48+
public abstract class LongConversionBaseNode extends ArgumentCastNodeWithRaise {
49+
private final long defaultValue;
50+
protected final boolean useDefaultForNone;
51+
52+
protected LongConversionBaseNode(long defaultValue, boolean useDefaultForNone) {
53+
this.defaultValue = defaultValue;
54+
this.useDefaultForNone = useDefaultForNone;
55+
}
56+
57+
public abstract long executeLong(VirtualFrame frame, Object value);
58+
59+
@Specialization(guards = {"!useDefaultForNone", "isNoValue(none)"})
60+
long doNoValue(@SuppressWarnings("unused") PNone none) {
61+
return defaultValue;
62+
}
63+
64+
@Specialization(guards = "useDefaultForNone")
65+
long doNoValueAndNone(@SuppressWarnings("unused") PNone none) {
66+
return defaultValue;
67+
}
68+
69+
@Specialization
70+
static long doInt(int i) {
71+
return i;
72+
}
73+
74+
@Specialization
75+
static long doLong(long l) {
76+
return l;
77+
}
78+
79+
protected boolean isHandledPNone(Object value) {
80+
return isHandledPNone(useDefaultForNone, value);
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2020, 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.nodes.function.builtins.clinic;
42+
43+
import com.oracle.graal.python.annotations.ArgumentClinic.PrimitiveType;
44+
import com.oracle.graal.python.annotations.ClinicConverterFactory;
45+
import com.oracle.graal.python.annotations.ClinicConverterFactory.DefaultValue;
46+
import com.oracle.graal.python.annotations.ClinicConverterFactory.UseDefaultForNone;
47+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
48+
import com.oracle.truffle.api.dsl.Specialization;
49+
import com.oracle.truffle.api.frame.VirtualFrame;
50+
import com.oracle.truffle.api.library.CachedLibrary;
51+
52+
public abstract class LongIndexConverterNode extends LongConversionBaseNode {
53+
protected LongIndexConverterNode(long defaultValue, boolean useDefaultForNone) {
54+
super(defaultValue, useDefaultForNone);
55+
}
56+
57+
@Specialization(guards = "!isHandledPNone(value)", limit = "3")
58+
long doOthers(VirtualFrame frame, Object value,
59+
@CachedLibrary("value") PythonObjectLibrary lib,
60+
@CachedLibrary(limit = "1") PythonObjectLibrary indexLib) {
61+
Object index = lib.asIndexWithFrame(value, frame);
62+
return indexLib.asJavaLong(index, frame);
63+
}
64+
65+
@ClinicConverterFactory(shortCircuitPrimitive = {PrimitiveType.Int, PrimitiveType.Long})
66+
public static LongIndexConverterNode create(@DefaultValue long defaultValue, @UseDefaultForNone boolean useDefaultForNone) {
67+
return LongIndexConverterNodeGen.create(defaultValue, useDefaultForNone);
68+
}
69+
70+
@ClinicConverterFactory(shortCircuitPrimitive = {PrimitiveType.Int, PrimitiveType.Long})
71+
public static LongIndexConverterNode create(@UseDefaultForNone boolean useDefaultForNone) {
72+
assert !useDefaultForNone : "defaultValue must be provided if useDefaultForNone is true";
73+
return LongIndexConverterNodeGen.create(0L, false);
74+
}
75+
76+
public static LongIndexConverterNode create() {
77+
return LongIndexConverterNode.create(false);
78+
}
79+
}

0 commit comments

Comments
 (0)