comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java @ 7291:a748e4d44694

Truffle API to specify type-specalized Node classes; annotation processor for automatic code generation of the type-specialized Node classes during the build process
author Christian Humer <christian.humer@gmail.com>
date Fri, 21 Dec 2012 10:44:31 -0800
parents
children 6343a09b2ec1
comparison
equal deleted inserted replaced
7290:a81db08fe930 7291:a748e4d44694
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.codegen.processor.codewriter;
24
25 import static com.oracle.truffle.codegen.processor.Utils.*;
26
27 import java.io.*;
28 import java.util.*;
29
30 import javax.lang.model.element.*;
31 import javax.lang.model.type.*;
32 import javax.lang.model.util.*;
33
34 import com.oracle.truffle.codegen.processor.*;
35 import com.oracle.truffle.codegen.processor.ast.*;
36
37 public abstract class AbstractCodeWriter extends CodeElementScanner<Void, Void> {
38
39 protected Writer writer;
40 private int indent;
41 private boolean newLine;
42
43 private OrganizedImports imports;
44
45 public void visitCompilationUnit(CodeCompilationUnit e) {
46 for (TypeElement clazz : e.getEnclosedElements()) {
47 clazz.accept(this, null);
48 }
49 }
50
51 protected abstract Writer createWriter(CodeTypeElement clazz) throws IOException;
52
53 @Override
54 public Void visitType(CodeTypeElement e, Void p) {
55 if (e.isTopLevelClass()) {
56 Writer w = null;
57 try {
58 imports = OrganizedImports.organize(e);
59
60 w = createWriter(e);
61 writer = w;
62 writeRootClass(e);
63 } catch (IOException ex) {
64 throw new RuntimeException(ex);
65 } finally {
66 if (w != null) {
67 try {
68 w.close();
69 } catch (Throwable e1) {
70 // see eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=361378
71 // TODO temporary suppress errors on close.
72 }
73 }
74 writer = null;
75 }
76 } else {
77 writeClassImpl(e);
78 }
79 return null;
80 }
81
82 private void writeRootClass(CodeTypeElement e) {
83 writeHeader();
84 write("package ").write(e.getPackageName()).write(";").writeLn();
85 writeEmptyLn();
86
87 Set<CodeImport> generateImports = imports.generateImports();
88 List<CodeImport> typeImports = new ArrayList<>();
89 List<CodeImport> staticImports = new ArrayList<>();
90
91 for (CodeImport codeImport : generateImports) {
92 if (codeImport.isStaticImport()) {
93 staticImports.add(codeImport);
94 } else {
95 typeImports.add(codeImport);
96 }
97 }
98 Collections.sort(typeImports);
99 Collections.sort(staticImports);
100
101 for (CodeImport imp : staticImports) {
102 imp.accept(this, null);
103 writeLn();
104 }
105 if (!staticImports.isEmpty()) {
106 writeEmptyLn();
107 }
108
109 for (CodeImport imp : typeImports) {
110 imp.accept(this, null);
111 writeLn();
112 }
113 if (!typeImports.isEmpty()) {
114 writeEmptyLn();
115 }
116
117 writeClassImpl(e);
118 }
119
120 private void writeClassImpl(CodeTypeElement e) {
121 for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
122 visitAnnotation(annotation);
123 writeLn();
124 }
125
126 writeModifiers(e.getModifiers());
127 if (e.getKind() == ElementKind.ENUM) {
128 write("enum ");
129 } else {
130 write("class ");
131 }
132 write(e.getSimpleName());
133 if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) {
134 write(" extends ").write(typeSimpleName(e.getSuperclass()));
135 }
136 if (e.getImplements().size() > 0) {
137 write(" implements ");
138 for (int i = 0; i < e.getImplements().size(); i++) {
139 write(typeSimpleName(e.getImplements().get(i)));
140 if (i < e.getImplements().size() - 1) {
141 write(", ");
142 }
143 }
144 }
145
146 write(" {").writeLn();
147 writeEmptyLn();
148 indent();
149
150 List<VariableElement> staticFields = getStaticFields(e);
151 List<VariableElement> instanceFields = getInstanceFields(e);
152
153 for (int i = 0; i < staticFields.size(); i++) {
154 VariableElement field = staticFields.get(i);
155 field.accept(this, null);
156 if (e.getKind() == ElementKind.ENUM && i < staticFields.size() - 1) {
157 write(",");
158 writeLn();
159 } else {
160 write(";");
161 writeLn();
162 }
163 }
164
165 if (staticFields.size() > 0) {
166 writeEmptyLn();
167 }
168
169 for (VariableElement field : instanceFields) {
170 field.accept(this, null);
171 write(";");
172 writeLn();
173 }
174 if (instanceFields.size() > 0) {
175 writeEmptyLn();
176 }
177
178 for (ExecutableElement method : getInstanceMethods(e)) {
179 method.accept(this, null);
180 }
181
182 for (ExecutableElement method : getStaticMethods(e)) {
183 method.accept(this, null);
184 }
185
186 for (TypeElement clazz : e.getInnerClasses()) {
187 clazz.accept(this, null);
188 }
189
190 dedent();
191 write("}");
192 writeEmptyLn();
193 }
194
195 private static List<VariableElement> getStaticFields(CodeTypeElement clazz) {
196 List<VariableElement> staticFields = new ArrayList<>();
197 for (VariableElement field : clazz.getFields()) {
198 if (field.getModifiers().contains(Modifier.STATIC)) {
199 staticFields.add(field);
200 }
201 }
202 return staticFields;
203 }
204
205 private static List<VariableElement> getInstanceFields(CodeTypeElement clazz) {
206 List<VariableElement> instanceFields = new ArrayList<>();
207 for (VariableElement field : clazz.getFields()) {
208 if (!field.getModifiers().contains(Modifier.STATIC)) {
209 instanceFields.add(field);
210 }
211 }
212 return instanceFields;
213 }
214
215 private static List<ExecutableElement> getStaticMethods(CodeTypeElement clazz) {
216 List<ExecutableElement> staticMethods = new ArrayList<>();
217 for (ExecutableElement method : clazz.getMethods()) {
218 if (method.getModifiers().contains(Modifier.STATIC)) {
219 staticMethods.add(method);
220 }
221 }
222 return staticMethods;
223 }
224
225 private static List<ExecutableElement> getInstanceMethods(CodeTypeElement clazz) {
226 List<ExecutableElement> instanceMethods = new ArrayList<>();
227 for (ExecutableElement method : clazz.getMethods()) {
228 if (!method.getModifiers().contains(Modifier.STATIC)) {
229 instanceMethods.add(method);
230 }
231 }
232 return instanceMethods;
233 }
234
235 @Override
236 public Void visitVariable(VariableElement f, Void p) {
237 Element parent = f.getEnclosingElement();
238
239 for (AnnotationMirror annotation : f.getAnnotationMirrors()) {
240 visitAnnotation(annotation);
241 writeLn();
242 }
243
244 CodeTree init = null;
245 if (f instanceof CodeVariableElement) {
246 init = ((CodeVariableElement) f).getInit();
247 }
248
249
250 if (parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) {
251 write(f.getSimpleName());
252 if (init != null) {
253 if (init != null) {
254 write("(");
255 init.acceptCodeElementScanner(this, p);
256 write(")");
257 }
258 }
259 } else {
260 writeModifiers(f.getModifiers());
261 write(typeSimpleName(f.asType()));
262 write(" ");
263 write(f.getSimpleName());
264 if (init != null) {
265 write(" = ");
266 init.acceptCodeElementScanner(this, p);
267 }
268 }
269 return null;
270 }
271
272 public void visitAnnotation(AnnotationMirror e) {
273 write("@").write(typeSimpleName(e.getAnnotationType()));
274
275 if (!e.getElementValues().isEmpty()) {
276 write("(");
277 final ExecutableElement defaultElement = findExecutableElement(e.getAnnotationType(), "value");
278
279 Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
280 if (defaultElement != null && values.size() == 1 && values.get(defaultElement) != null) {
281 visitAnnotationValue(values.get(defaultElement));
282 } else {
283 Set<? extends ExecutableElement> methodsSet = values.keySet();
284 List<ExecutableElement> methodsList = new ArrayList<>();
285 for (ExecutableElement method : methodsSet) {
286 if (values.get(method) == null) {
287 continue;
288 }
289 methodsList.add(method);
290 }
291
292 Collections.sort(methodsList, new Comparator<ExecutableElement>() {
293 @Override
294 public int compare(ExecutableElement o1, ExecutableElement o2) {
295 return o1.getSimpleName().toString().compareTo(o2.getSimpleName().toString());
296 }
297 });
298
299 for (int i = 0; i < methodsList.size(); i++) {
300 ExecutableElement method = methodsList.get(i);
301 AnnotationValue value = values.get(method);
302 write(method.getSimpleName().toString());
303 write(" = ");
304 visitAnnotationValue(value);
305
306 if (i < methodsList.size() - 1) {
307 write(", ");
308 }
309 }
310 }
311
312 write(")");
313 }
314 }
315
316 public void visitAnnotationValue(AnnotationValue e) {
317 e.accept(new AnnotationValueWriterVisitor(), null);
318 }
319
320 private class AnnotationValueWriterVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
321 @Override
322 public Void visitBoolean(boolean b, Void p) {
323 write(Boolean.toString(b));
324 return null;
325 }
326 @Override
327 public Void visitByte(byte b, Void p) {
328 write(Byte.toString(b));
329 return null;
330 }
331 @Override
332 public Void visitChar(char c, Void p) {
333 write(Character.toString(c));
334 return null;
335 }
336 @Override
337 public Void visitDouble(double d, Void p) {
338 write(Double.toString(d));
339 return null;
340 }
341 @Override
342 public Void visitFloat(float f, Void p) {
343 write(Float.toString(f));
344 return null;
345 }
346 @Override
347 public Void visitInt(int i, Void p) {
348 write(Integer.toString(i));
349 return null;
350 }
351 @Override
352 public Void visitLong(long i, Void p) {
353 write(Long.toString(i));
354 return null;
355 }
356 @Override
357 public Void visitShort(short s, Void p) {
358 write(Short.toString(s));
359 return null;
360 }
361 @Override
362 public Void visitString(String s, Void p) {
363 write("\"");
364 write(s);
365 write("\"");
366 return null;
367 }
368 @Override
369 public Void visitType(TypeMirror t, Void p) {
370 write(typeSimpleName(t));
371 write(".class");
372 return null;
373 }
374 @Override
375 public Void visitEnumConstant(VariableElement c, Void p) {
376 write(typeSimpleName(c.asType()));
377 write(".");
378 write(c.getSimpleName().toString());
379 return null;
380 }
381 @Override
382 public Void visitAnnotation(AnnotationMirror a, Void p) {
383 AbstractCodeWriter.this.visitAnnotation(a);
384 return null;
385 }
386 @Override
387 public Void visitArray(List< ? extends AnnotationValue> vals, Void p) {
388 write("{");
389 for (int i = 0; i < vals.size(); i++) {
390 AnnotationValue value = vals.get(i);
391 AbstractCodeWriter.this.visitAnnotationValue(value);
392 if (i < vals.size() - 1) {
393 write(", ");
394 }
395 }
396 write("}");
397 return null;
398 }
399 }
400
401 public ExecutableElement findExecutableElement(DeclaredType type, String name) {
402 List<? extends ExecutableElement> elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements());
403 for (ExecutableElement executableElement : elements) {
404 if (executableElement.getSimpleName().toString().equals(name)) {
405 return executableElement;
406 }
407 }
408 return null;
409 }
410
411 @Override
412 public void visitImport(CodeImport e, Void p) {
413 if (e.isStaticImport()) {
414 write("import static ").write(e.getImportString()).write(";");
415 } else {
416 write("import ").write(e.getImportString()).write(";");
417 }
418 }
419
420 // @Override
421 // public void visitParameter(CodeVariableElement e) {
422 // for (CodeAnnotationMirror annotation : e.getAnnotationMirrors()) {
423 // annotation.accept(this);
424 // }
425 // write(typeSimpleName(e.getType()));
426 // write(" ");
427 // write(e.getSimpleName());
428 // }
429
430 @Override
431 public Void visitExecutable(CodeExecutableElement e, Void p) {
432 for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
433 visitAnnotation(annotation);
434 writeLn();
435 }
436
437 writeModifiers(e.getModifiers());
438
439 if (e.getReturnType() != null) {
440 write(typeSimpleName(e.getReturnType()));
441 write(" ");
442 }
443 write(e.getSimpleName());
444 write("(");
445
446 for (int i = 0; i < e.getParameters().size(); i++) {
447 VariableElement param = e.getParameters().get(i);
448 param.accept(this, p);
449 if (i < e.getParameters().size() - 1) {
450 write(", ");
451 }
452 }
453 write(")");
454
455 List<TypeMirror> throwables = e.getThrownTypes();
456 if (throwables.size() > 0) {
457 write(" throws ");
458 for (int i = 0; i < throwables.size(); i++) {
459 write(typeSimpleName(throwables.get(i)));
460 if (i < throwables.size() - 1) {
461 write(", ");
462 }
463 }
464 }
465
466 if (e.getModifiers().contains(Modifier.ABSTRACT)) {
467 writeLn(";");
468 } else if (e.getBodyTree() != null) {
469 writeLn(" {");
470 indent();
471 e.getBodyTree().acceptCodeElementScanner(this, p);
472 dedent();
473 writeLn("}");
474 } else if (e.getBody() != null) {
475 write(" {");
476 write(e.getBody());
477 writeLn("}");
478 } else {
479 writeLn("{ }");
480 }
481 writeEmptyLn();
482 return null;
483 }
484
485 @Override
486 public void visitTree(CodeTree e, Void p) {
487 CodeTreeKind kind = e.getCodeKind();
488
489 switch (kind) {
490 case COMMA_GROUP:
491 List<CodeTree> children = e.getEnclosedElements();
492 for (int i = 0; i < children.size(); i++) {
493 children.get(i).acceptCodeElementScanner(this, p);
494 if (i < e.getEnclosedElements().size() - 1) {
495 write(", ");
496 }
497 }
498 break;
499 case GROUP:
500 for (CodeTree tree : e.getEnclosedElements()) {
501 tree.acceptCodeElementScanner(this, p);
502 }
503 break;
504 case INDENT:
505 indent();
506 for (CodeTree tree : e.getEnclosedElements()) {
507 tree.acceptCodeElementScanner(this, p);
508 }
509 dedent();
510 break;
511 case NEW_LINE:
512 writeLn();
513 break;
514 case STRING:
515 if (e.getString() != null) {
516 write(e.getString());
517 } else {
518 write("null");
519 }
520 break;
521 case STATIC_FIELD_REFERENCE:
522 if (e.getString() != null) {
523 write(imports.useStaticFieldImport(e.getType(), e.getString()));
524 } else {
525 write("null");
526 }
527 break;
528 case STATIC_METHOD_REFERENCE:
529 if (e.getString() != null) {
530 write(imports.useStaticMethodImport(e.getType(), e.getString()));
531 } else {
532 write("null");
533 }
534 break;
535 case TYPE:
536 write(imports.useImport(e.getType()));
537 break;
538 default:
539 assert false;
540 return;
541 }
542 }
543
544 private static String typeSimpleName(TypeMirror type) {
545 return Utils.getSimpleName(type);
546 }
547
548 protected void writeHeader() {
549 // default implementation does nothing
550 }
551
552 private void writeModifiers(Set<Modifier> modifiers) {
553 if (modifiers != null) {
554 for (Modifier modifier : modifiers) {
555 write(modifier.toString());
556 write(" ");
557 }
558 }
559 }
560
561 private static final String LN = "\n";
562
563 protected void indent() {
564 indent++;
565 }
566
567 protected void dedent() {
568 indent--;
569 }
570
571 protected void writeLn() {
572 write(LN);
573 newLine = true;
574 }
575
576 protected void writeLn(String text) {
577 write(text);
578 write(LN);
579 newLine = true;
580 }
581
582 protected void writeEmptyLn() {
583 writeLn();
584 }
585
586 private AbstractCodeWriter write(Name name) {
587 return write(name.toString());
588 }
589
590 private AbstractCodeWriter write(String m) {
591 try {
592 if (newLine && m != LN) {
593 writeIndent();
594 newLine = false;
595 }
596 writer.write(m);
597 } catch (IOException e) {
598 throw new RuntimeException(e);
599 }
600 return this;
601 }
602
603 private void writeIndent() throws IOException {
604 for (int i = 0; i < indent; i++) {
605 writer.write(" ");
606 }
607 }
608 }