|
40 | 40 | */
|
41 | 41 | package com.oracle.graal.python.processor;
|
42 | 42 |
|
43 |
| -import static java.lang.String.format; |
44 |
| - |
45 | 43 | import java.util.Arrays;
|
| 44 | +import java.util.Collections; |
46 | 45 | import java.util.HashSet;
|
47 | 46 | import java.util.List;
|
48 | 47 | import java.util.Set;
|
|
55 | 54 | import com.oracle.graal.python.annotations.ArgumentClinic.PrimitiveType;
|
56 | 55 |
|
57 | 56 | public class ArgumentClinicModel {
|
58 |
| - static final class BuiltinConvertor { |
59 |
| - public static final String CLINIC_PACKAGE = "com.oracle.graal.python.nodes.function.builtins.clinic"; |
60 |
| - |
61 |
| - public static String getCodeSnippet(ArgumentClinic annotation, BuiltinAnnotation builtin) { |
62 |
| - switch (annotation.conversion()) { |
63 |
| - case Boolean: |
64 |
| - return format("JavaBooleanConvertorNodeGen.create(%s)", annotation.defaultValue()); |
65 |
| - case String: |
66 |
| - String defaultVal = annotation.defaultValue(); |
67 |
| - if (defaultVal.isEmpty()) { |
68 |
| - return format("JavaStringConvertorNodeGen.create(\"%s\")", builtin.name); |
69 |
| - } else { |
70 |
| - return format("JavaStringConvertorWithDefaultValueNodeGen.create(\"%s\", %s, %s)", builtin.name, defaultVal, annotation.useDefaultForNone()); |
71 |
| - } |
72 |
| - case Int: |
73 |
| - return format("JavaIntConversionNodeGen.create(%s, %s)", annotation.defaultValue(), annotation.useDefaultForNone()); |
74 |
| - case CodePoint: |
75 |
| - return format("CodePointConversionNodeGen.create(\"%s\", %s, %s)", builtin.name, annotation.defaultValue(), annotation.useDefaultForNone()); |
76 |
| - case Buffer: |
77 |
| - return "BufferConversionNodeGen.create()"; |
78 |
| - case Index: |
79 |
| - return format("IndexConversionNodeGen.create(%s, %s)", annotation.defaultValue(), annotation.useDefaultForNone()); |
80 |
| - case None: |
81 |
| - return format("DefaultValueNode.create(%s, %s)", annotation.defaultValue(), annotation.useDefaultForNone()); |
82 |
| - default: |
83 |
| - throw new IllegalArgumentException(annotation.conversion().toString()); |
84 |
| - } |
85 |
| - } |
86 |
| - |
87 |
| - public static void addImports(ArgumentClinic annotation, Set<String> imports) { |
88 |
| - // We may add imports for some other prominent constants |
89 |
| - // Another possibility is to introduce something like ArgumentClinicImportStatic |
90 |
| - // annotation, or piggy-back on Truffle DSL's ImportStatic annotation, but then we can |
91 |
| - // also use fully qualified names in such rare cases |
92 |
| - if (annotation.defaultValue().startsWith("PNone.")) { |
93 |
| - imports.add("com.oracle.graal.python.builtins.objects.PNone"); |
94 |
| - } |
95 |
| - if (annotation.conversion() != ClinicConversion.None || (annotation.customConversion().isEmpty() && !annotation.defaultValue().isEmpty())) { |
96 |
| - imports.add(CLINIC_PACKAGE + '.' + getConvertorImport(annotation)); |
97 |
| - } |
98 |
| - } |
99 |
| - |
100 |
| - private static String getConvertorImport(ArgumentClinic annotation) { |
101 |
| - switch (annotation.conversion()) { |
102 |
| - case Boolean: |
103 |
| - return "JavaBooleanConvertorNodeGen"; |
104 |
| - case String: |
105 |
| - return annotation.defaultValue().isEmpty() ? "JavaStringConvertorNodeGen" : "JavaStringConvertorWithDefaultValueNodeGen"; |
106 |
| - case Int: |
107 |
| - return "JavaIntConversionNodeGen"; |
108 |
| - case Index: |
109 |
| - return "IndexConversionNodeGen"; |
110 |
| - case CodePoint: |
111 |
| - return "CodePointConversionNodeGen"; |
112 |
| - case Buffer: |
113 |
| - return "BufferConversionNodeGen"; |
114 |
| - case None: |
115 |
| - return "DefaultValueNode"; |
116 |
| - default: |
117 |
| - throw new IllegalArgumentException(annotation.conversion().toString()); |
118 |
| - } |
119 |
| - } |
120 |
| - |
121 |
| - public static PrimitiveType[] getAcceptedPrimitiveTypes(ArgumentClinic annotation) { |
122 |
| - switch (annotation.conversion()) { |
123 |
| - case Boolean: |
124 |
| - return new PrimitiveType[]{PrimitiveType.Boolean}; |
125 |
| - case String: |
126 |
| - case CodePoint: |
127 |
| - case Buffer: |
128 |
| - return new PrimitiveType[0]; |
129 |
| - case Int: |
130 |
| - case Index: |
131 |
| - return new PrimitiveType[]{PrimitiveType.Int}; |
132 |
| - case None: |
133 |
| - return new PrimitiveType[]{PrimitiveType.Boolean, PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Double}; |
134 |
| - default: |
135 |
| - throw new IllegalArgumentException(annotation.conversion().toString()); |
136 |
| - } |
137 |
| - } |
138 |
| - } |
139 | 57 |
|
140 | 58 | /**
|
141 | 59 | * Mirrors the data of the {@code Builtin} annotation, which cannot be in the "annotations"
|
142 | 60 | * project because of its dependence on other GraalPython runtime classes.
|
143 | 61 | */
|
144 |
| - static final class BuiltinAnnotation { |
| 62 | + public static final class BuiltinAnnotation { |
145 | 63 | public final String name;
|
146 | 64 | public final String[] argumentNames;
|
147 | 65 |
|
@@ -188,38 +106,73 @@ static final class ArgumentClinicData {
|
188 | 106 | public final int index;
|
189 | 107 | public final Set<PrimitiveType> acceptedPrimitiveTypes;
|
190 | 108 | public final String castNodeFactory;
|
| 109 | + public final Set<String> imports; |
191 | 110 |
|
192 |
| - public ArgumentClinicData(ArgumentClinic annotation, int index, Set<PrimitiveType> acceptedPrimitiveTypes, String castNodeFactory) { |
| 111 | + private ArgumentClinicData(ArgumentClinic annotation, int index, Set<PrimitiveType> acceptedPrimitiveTypes, String castNodeFactory, Set<String> imports) { |
193 | 112 | this.annotation = annotation;
|
194 | 113 | this.index = index;
|
195 | 114 | this.acceptedPrimitiveTypes = acceptedPrimitiveTypes;
|
196 | 115 | this.castNodeFactory = castNodeFactory;
|
| 116 | + this.imports = imports; |
197 | 117 | }
|
198 | 118 |
|
199 |
| - public boolean isClinicArgument() { |
200 |
| - return annotation != null; |
| 119 | + private static ConverterFactory getFactory(ArgumentClinic annotation, TypeElement type, ConverterFactory factory) throws ProcessingError { |
| 120 | + if (factory == null && annotation.args().length != 0) { |
| 121 | + throw new ProcessingError(type, "No conversionClass specified but arguments were provided"); |
| 122 | + } |
| 123 | + if (factory != null) { |
| 124 | + return factory; |
| 125 | + } |
| 126 | + if (annotation.conversion() == ClinicConversion.None && annotation.defaultValue().isEmpty()) { |
| 127 | + throw new ProcessingError(type, "ArgumentClinic annotation must declare either builtin conversion or custom conversion."); |
| 128 | + } |
| 129 | + return ConverterFactory.getBuiltin(annotation); |
201 | 130 | }
|
202 | 131 |
|
203 |
| - public static ArgumentClinicData create(ArgumentClinic annotation, TypeElement type, BuiltinAnnotation builtinAnnotation, int index) throws ProcessingError { |
| 132 | + public static ArgumentClinicData create(ArgumentClinic annotation, TypeElement type, BuiltinAnnotation builtinAnnotation, int index, ConverterFactory annotationFactory) |
| 133 | + throws ProcessingError { |
204 | 134 | if (annotation == null) {
|
205 |
| - return new ArgumentClinicData(null, index, new HashSet<>(Arrays.asList(PrimitiveType.values())), null); |
| 135 | + return new ArgumentClinicData(null, index, new HashSet<>(Arrays.asList(PrimitiveType.values())), null, Collections.emptySet()); |
| 136 | + } |
| 137 | + ConverterFactory factory = getFactory(annotation, type, annotationFactory); |
| 138 | + if (annotation.args().length != factory.extraParamCount) { |
| 139 | + throw new ProcessingError(type, "Conversion %s.%s expects %d arguments", factory.fullClassName, factory.methodName, factory.extraParamCount); |
206 | 140 | }
|
207 | 141 |
|
208 |
| - PrimitiveType[] acceptedPrimitives = new PrimitiveType[0]; |
209 |
| - String castNodeFactory; |
210 |
| - if (annotation.customConversion().isEmpty()) { |
211 |
| - if (annotation.conversion() == ClinicConversion.None && annotation.defaultValue().isEmpty()) { |
212 |
| - throw new ProcessingError(type, "ArgumentClinic annotation must declare either builtin conversion or custom conversion."); |
| 142 | + String[] args = new String[factory.params.length]; |
| 143 | + int extraParamIndex = 0; |
| 144 | + for (int i = 0; i < args.length; ++i) { |
| 145 | + switch (factory.params[i]) { |
| 146 | + case BuiltinName: |
| 147 | + args[i] = String.format("\"%s\"", builtinAnnotation.name); |
| 148 | + break; |
| 149 | + case ArgumentIndex: |
| 150 | + args[i] = String.valueOf(index); |
| 151 | + break; |
| 152 | + case ArgumentName: |
| 153 | + args[i] = String.format("\"%s\"", builtinAnnotation.argumentNames[index]); |
| 154 | + break; |
| 155 | + case DefaultValue: |
| 156 | + args[i] = annotation.defaultValue(); |
| 157 | + break; |
| 158 | + case UseDefaultForNone: |
| 159 | + args[i] = String.valueOf(annotation.useDefaultForNone()); |
| 160 | + break; |
| 161 | + case Extra: |
| 162 | + args[i] = annotation.args()[extraParamIndex++]; |
| 163 | + break; |
| 164 | + default: |
| 165 | + throw new IllegalStateException("Unsupported ClinicArgument: " + factory.params[i]); |
213 | 166 | }
|
214 |
| - castNodeFactory = BuiltinConvertor.getCodeSnippet(annotation, builtinAnnotation); |
215 |
| - acceptedPrimitives = BuiltinConvertor.getAcceptedPrimitiveTypes(annotation); |
216 |
| - } else { |
217 |
| - castNodeFactory = type.getQualifiedName().toString() + '.' + annotation.customConversion() + "()"; |
218 | 167 | }
|
219 |
| - if (annotation.shortCircuitPrimitive().length > 0) { |
220 |
| - acceptedPrimitives = annotation.shortCircuitPrimitive(); |
| 168 | + String castNodeFactory = String.format("%s.%s(%s)", factory.className, factory.methodName, String.join(", ", args)); |
| 169 | + Set<String> imports = new HashSet<>(); |
| 170 | + imports.add(factory.fullClassName); |
| 171 | + if (annotation.defaultValue().startsWith("PNone.")) { |
| 172 | + imports.add("com.oracle.graal.python.builtins.objects.PNone"); |
221 | 173 | }
|
222 |
| - return new ArgumentClinicData(annotation, index, new HashSet<>(Arrays.asList(acceptedPrimitives)), castNodeFactory); |
| 174 | + |
| 175 | + return new ArgumentClinicData(annotation, index, new HashSet<>(Arrays.asList(factory.acceptedPrimitiveTypes)), castNodeFactory, imports); |
223 | 176 | }
|
224 | 177 | }
|
225 | 178 | }
|
0 commit comments