Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java @ 16851:2db61eddcb97
Truffle-DSL: argument syntax support for guards
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 18 Aug 2014 18:41:16 +0200 |
parents | |
children | 08aa0372dad4 |
comparison
equal
deleted
inserted
replaced
16850:d6c002f4d2a9 | 16851:2db61eddcb97 |
---|---|
1 /* | |
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.oracle.truffle.dsl.processor.parser; | |
24 | |
25 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; | |
26 | |
27 import java.util.*; | |
28 | |
29 import javax.lang.model.element.*; | |
30 import javax.lang.model.type.*; | |
31 | |
32 import com.oracle.truffle.dsl.processor.java.*; | |
33 import com.oracle.truffle.dsl.processor.model.*; | |
34 | |
35 public final class MethodSpecParser { | |
36 | |
37 private boolean emitErrors = true; | |
38 private boolean useVarArgs = false; | |
39 | |
40 private final Template template; | |
41 | |
42 public MethodSpecParser(Template template) { | |
43 this.template = template; | |
44 } | |
45 | |
46 public Template getTemplate() { | |
47 return template; | |
48 } | |
49 | |
50 public TypeSystemData getTypeSystem() { | |
51 return template.getTypeSystem(); | |
52 } | |
53 | |
54 public boolean isEmitErrors() { | |
55 return emitErrors; | |
56 } | |
57 | |
58 public boolean isUseVarArgs() { | |
59 return useVarArgs; | |
60 } | |
61 | |
62 public void setEmitErrors(boolean emitErrors) { | |
63 this.emitErrors = emitErrors; | |
64 } | |
65 | |
66 public void setUseVarArgs(boolean useVarArgs) { | |
67 this.useVarArgs = useVarArgs; | |
68 } | |
69 | |
70 public TemplateMethod parse(MethodSpec methodSpecification, ExecutableElement method, AnnotationMirror annotation, int naturalOrder) { | |
71 if (methodSpecification == null) { | |
72 return null; | |
73 } | |
74 | |
75 methodSpecification.applyTypeDefinitions("types"); | |
76 | |
77 String id = method.getSimpleName().toString(); | |
78 TypeMirror returnType = method.getReturnType(); | |
79 List<TypeMirror> parameterTypes = new ArrayList<>(); | |
80 for (VariableElement var : method.getParameters()) { | |
81 parameterTypes.add(var.asType()); | |
82 } | |
83 | |
84 return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); | |
85 } | |
86 | |
87 public TemplateMethod parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, | |
88 List<TypeMirror> parameterTypes) { | |
89 ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); | |
90 Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); | |
91 if (returnTypeMirror == null) { | |
92 if (emitErrors) { | |
93 TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<Parameter> emptyList()); | |
94 String expectedReturnType = returnTypeSpec.toSignatureString(true); | |
95 String actualReturnType = ElementUtils.getSimpleName(returnType); | |
96 | |
97 String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, | |
98 methodSpecification.toSignatureString(method.getSimpleName().toString())); | |
99 invalidMethod.addError(message); | |
100 return invalidMethod; | |
101 } else { | |
102 return null; | |
103 } | |
104 } | |
105 | |
106 List<Parameter> parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); | |
107 if (parameters == null) { | |
108 if (isEmitErrors() && method != null) { | |
109 TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<Parameter> emptyList()); | |
110 String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), | |
111 methodSpecification.toSignatureString(method.getSimpleName().toString())); | |
112 invalidMethod.addError(message); | |
113 return invalidMethod; | |
114 } else { | |
115 return null; | |
116 } | |
117 } | |
118 | |
119 return new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters); | |
120 } | |
121 | |
122 private static String createActualSignature(ExecutableElement method) { | |
123 StringBuilder b = new StringBuilder("("); | |
124 String sep = ""; | |
125 if (method != null) { | |
126 for (VariableElement var : method.getParameters()) { | |
127 b.append(sep); | |
128 b.append(ElementUtils.getSimpleName(var.asType())); | |
129 sep = ", "; | |
130 } | |
131 } | |
132 b.append(")"); | |
133 return b.toString(); | |
134 } | |
135 | |
136 /* | |
137 * Parameter parsing tries to parse required arguments starting from offset 0 with increasing | |
138 * offset until it finds a signature end that matches the required specification. If there is no | |
139 * end matching the required arguments, parsing fails. Parameters prior to the parsed required | |
140 * ones are cut and used to parse the optional parameters. | |
141 */ | |
142 private List<Parameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes, boolean varArgs) { | |
143 List<Parameter> parsedRequired = null; | |
144 int offset = 0; | |
145 for (; offset <= parameterTypes.size(); offset++) { | |
146 List<TypeMirror> parameters = new ArrayList<>(); | |
147 parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); | |
148 parsedRequired = parseParametersRequired(spec, parameters, varArgs); | |
149 if (parsedRequired != null) { | |
150 break; | |
151 } | |
152 } | |
153 | |
154 if (parsedRequired == null) { | |
155 return null; | |
156 } | |
157 | |
158 if (parsedRequired.isEmpty() && offset == 0) { | |
159 offset = parameterTypes.size(); | |
160 } | |
161 List<TypeMirror> potentialOptionals = parameterTypes.subList(0, offset); | |
162 List<Parameter> parsedOptionals = parseParametersOptional(spec, potentialOptionals); | |
163 if (parsedOptionals == null) { | |
164 return null; | |
165 } | |
166 | |
167 List<Parameter> finalParameters = new ArrayList<>(); | |
168 finalParameters.addAll(parsedOptionals); | |
169 finalParameters.addAll(parsedRequired); | |
170 return finalParameters; | |
171 } | |
172 | |
173 private List<Parameter> parseParametersOptional(MethodSpec spec, List<TypeMirror> types) { | |
174 List<Parameter> parsedParams = new ArrayList<>(); | |
175 | |
176 int typeStartIndex = 0; | |
177 List<ParameterSpec> specifications = spec.getOptional(); | |
178 outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { | |
179 ParameterSpec specification = specifications.get(specIndex); | |
180 for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { | |
181 TypeMirror actualType = types.get(typeIndex); | |
182 Parameter optionalParam = matchParameter(specification, actualType, -1, -1); | |
183 if (optionalParam != null) { | |
184 parsedParams.add(optionalParam); | |
185 typeStartIndex = typeIndex + 1; | |
186 continue outer; | |
187 } | |
188 } | |
189 } | |
190 | |
191 if (typeStartIndex < types.size()) { | |
192 // not enough types found | |
193 return null; | |
194 } | |
195 return parsedParams; | |
196 } | |
197 | |
198 private List<Parameter> parseParametersRequired(MethodSpec spec, List<TypeMirror> types, boolean typeVarArgs) { | |
199 List<Parameter> parsedParams = new ArrayList<>(); | |
200 List<ParameterSpec> specifications = spec.getRequired(); | |
201 boolean specVarArgs = spec.isVariableRequiredParameters(); | |
202 int typeIndex = 0; | |
203 int specificationIndex = 0; | |
204 | |
205 ParameterSpec specification; | |
206 while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { | |
207 TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); | |
208 if (actualType == null) { | |
209 if (spec.isIgnoreAdditionalSpecifications()) { | |
210 break; | |
211 } | |
212 return null; | |
213 } | |
214 | |
215 int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; | |
216 int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; | |
217 | |
218 if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { | |
219 // both specifications and types have a variable number of arguments | |
220 // we would get into an endless loop if we would continue | |
221 break; | |
222 } | |
223 | |
224 Parameter resolvedParameter = matchParameter(specification, actualType, specVarArgsIndex, typeVarArgsIndex); | |
225 if (resolvedParameter == null) { | |
226 return null; | |
227 } | |
228 parsedParams.add(resolvedParameter); | |
229 typeIndex++; | |
230 specificationIndex++; | |
231 } | |
232 | |
233 if (typeIndex < types.size()) { | |
234 // additional types available | |
235 if (spec.isIgnoreAdditionalParameters()) { | |
236 return parsedParams; | |
237 } else { | |
238 return null; | |
239 } | |
240 } | |
241 | |
242 return parsedParams; | |
243 } | |
244 | |
245 private static ParameterSpec nextSpecification(List<ParameterSpec> specifications, int specIndex, boolean varArgs) { | |
246 if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { | |
247 return specifications.get(specifications.size() - 1); | |
248 } else if (specIndex < specifications.size()) { | |
249 return specifications.get(specIndex); | |
250 } else { | |
251 return null; | |
252 } | |
253 } | |
254 | |
255 private static TypeMirror nextActualType(List<TypeMirror> types, int typeIndex, boolean varArgs) { | |
256 if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { | |
257 // unpack varargs array argument | |
258 TypeMirror actualType = types.get(types.size() - 1); | |
259 if (actualType.getKind() == TypeKind.ARRAY) { | |
260 actualType = ((ArrayType) actualType).getComponentType(); | |
261 } | |
262 return actualType; | |
263 } else if (typeIndex < types.size()) { | |
264 return types.get(typeIndex); | |
265 } else { | |
266 return null; | |
267 } | |
268 } | |
269 | |
270 private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { | |
271 TypeMirror resolvedType = mirror; | |
272 if (hasError(resolvedType)) { | |
273 return null; | |
274 } | |
275 | |
276 if (!specification.matches(resolvedType)) { | |
277 return null; | |
278 } | |
279 | |
280 TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); | |
281 if (resolvedTypeData != null) { | |
282 return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); | |
283 } else { | |
284 return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); | |
285 } | |
286 } | |
287 | |
288 } |