Mercurial > hg > truffle
comparison truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java @ 21951:9c8c0937da41
Moving all sources into truffle subdirectory
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Wed, 17 Jun 2015 10:58:08 +0200 |
parents | graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java@476374f3fe9a |
children | dc83cc1f94f2 |
comparison
equal
deleted
inserted
replaced
21950:2a5011c7e641 | 21951:9c8c0937da41 |
---|---|
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.java.model; | |
24 | |
25 import static com.oracle.truffle.dsl.processor.java.model.CodeTreeKind.*; | |
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 | |
34 public class CodeTreeBuilder { | |
35 | |
36 private BuilderCodeTree currentElement; | |
37 private final BuilderCodeTree root; | |
38 | |
39 private int treeCount; | |
40 private Element enclosingElement; | |
41 | |
42 public CodeTreeBuilder(CodeTreeBuilder parent) { | |
43 this.root = new BuilderCodeTree(null, GROUP, null, null); | |
44 this.currentElement = root; | |
45 if (parent != null) { | |
46 this.enclosingElement = parent.enclosingElement; | |
47 } | |
48 } | |
49 | |
50 public void setEnclosingElement(Element enclosingElement) { | |
51 this.enclosingElement = enclosingElement; | |
52 } | |
53 | |
54 @Override | |
55 public String toString() { | |
56 return root.toString(); | |
57 } | |
58 | |
59 public int getTreeCount() { | |
60 return treeCount; | |
61 } | |
62 | |
63 public boolean isEmpty() { | |
64 return treeCount == 0; | |
65 } | |
66 | |
67 public CodeTreeBuilder statement(String statement) { | |
68 return startStatement().string(statement).end(); | |
69 } | |
70 | |
71 public CodeTreeBuilder statement(CodeTree statement) { | |
72 return startStatement().tree(statement).end(); | |
73 } | |
74 | |
75 public static CodeTreeBuilder createBuilder() { | |
76 return new CodeTreeBuilder(null); | |
77 } | |
78 | |
79 public static CodeTree singleString(String s) { | |
80 return createBuilder().string(s).build(); | |
81 } | |
82 | |
83 public static CodeTree singleType(TypeMirror s) { | |
84 return createBuilder().type(s).build(); | |
85 } | |
86 | |
87 private CodeTreeBuilder push(CodeTreeKind kind) { | |
88 return push(new BuilderCodeTree(currentElement, kind, null, null), kind == NEW_LINE); | |
89 } | |
90 | |
91 private CodeTreeBuilder push(String string) { | |
92 return push(new BuilderCodeTree(currentElement, CodeTreeKind.STRING, null, string), false); | |
93 } | |
94 | |
95 private CodeTreeBuilder push(TypeMirror type) { | |
96 return push(new BuilderCodeTree(currentElement, CodeTreeKind.TYPE, type, null), false); | |
97 } | |
98 | |
99 private CodeTreeBuilder push(CodeTreeKind kind, TypeMirror type, String string) { | |
100 return push(new BuilderCodeTree(currentElement, kind, type, string), kind == NEW_LINE); | |
101 } | |
102 | |
103 private CodeTreeBuilder push(BuilderCodeTree tree, boolean removeLast) { | |
104 if (currentElement != null) { | |
105 if (removeLast && !removeLastIfEnqueued(tree)) { | |
106 return this; | |
107 } | |
108 currentElement.add(tree); | |
109 } | |
110 switch (tree.getCodeKind()) { | |
111 case COMMA_GROUP: | |
112 case GROUP: | |
113 case INDENT: | |
114 currentElement = tree; | |
115 break; | |
116 } | |
117 treeCount++; | |
118 return this; | |
119 } | |
120 | |
121 private boolean removeLastIfEnqueued(BuilderCodeTree tree) { | |
122 if (tree.getCodeKind() == REMOVE_LAST) { | |
123 return !clearLastRec(tree.removeLast, currentElement.getEnclosedElements()); | |
124 } | |
125 List<CodeTree> childTree = tree.getEnclosedElements(); | |
126 if (childTree != null && !childTree.isEmpty()) { | |
127 CodeTree last = childTree.get(0); | |
128 if (last instanceof BuilderCodeTree) { | |
129 if (!removeLastIfEnqueued((BuilderCodeTree) last)) { | |
130 childTree.remove(0); | |
131 } | |
132 } | |
133 } | |
134 return true; | |
135 } | |
136 | |
137 private void clearLast(CodeTreeKind kind) { | |
138 if (clearLastRec(kind, currentElement.getEnclosedElements())) { | |
139 treeCount--; | |
140 } else { | |
141 // delay clearing the last | |
142 BuilderCodeTree tree = new BuilderCodeTree(currentElement, REMOVE_LAST, null, null); | |
143 tree.removeLast = kind; | |
144 push(tree, false); | |
145 } | |
146 } | |
147 | |
148 public CodeTreeBuilder startStatement() { | |
149 startGroup(); | |
150 registerCallBack(new EndCallback() { | |
151 | |
152 @Override | |
153 public void beforeEnd() { | |
154 string(";").newLine(); | |
155 } | |
156 | |
157 @Override | |
158 public void afterEnd() { | |
159 } | |
160 }); | |
161 return this; | |
162 } | |
163 | |
164 public CodeTreeBuilder startGroup() { | |
165 return push(CodeTreeKind.GROUP); | |
166 } | |
167 | |
168 public CodeTreeBuilder startCommaGroup() { | |
169 return push(CodeTreeKind.COMMA_GROUP); | |
170 } | |
171 | |
172 public CodeTreeBuilder startCall(String callSite) { | |
173 return startCall((CodeTree) null, callSite); | |
174 } | |
175 | |
176 public CodeTreeBuilder startCall(String receiver, String callSite) { | |
177 if (receiver != null) { | |
178 return startCall(singleString(receiver), callSite); | |
179 } else { | |
180 return startCall(callSite); | |
181 } | |
182 } | |
183 | |
184 public CodeTreeBuilder startCall(CodeTree receiver, String callSite) { | |
185 if (receiver == null) { | |
186 return startGroup().string(callSite).startParanthesesCommaGroup().endAfter(); | |
187 } else { | |
188 return startGroup().tree(receiver).string(".").string(callSite).startParanthesesCommaGroup().endAfter(); | |
189 } | |
190 } | |
191 | |
192 public CodeTreeBuilder startStaticCall(TypeMirror type, String methodName) { | |
193 return startGroup().push(CodeTreeKind.STATIC_METHOD_REFERENCE, type, methodName).startParanthesesCommaGroup().endAfter(); | |
194 } | |
195 | |
196 public CodeTreeBuilder startStaticCall(ExecutableElement method) { | |
197 return startStaticCall(ElementUtils.findNearestEnclosingType(method).asType(), method.getSimpleName().toString()); | |
198 } | |
199 | |
200 public CodeTreeBuilder staticReference(TypeMirror type, String fieldName) { | |
201 return push(CodeTreeKind.STATIC_FIELD_REFERENCE, type, fieldName); | |
202 } | |
203 | |
204 private CodeTreeBuilder endAndWhitespaceAfter() { | |
205 registerCallBack(new EndCallback() { | |
206 | |
207 @Override | |
208 public void beforeEnd() { | |
209 } | |
210 | |
211 @Override | |
212 public void afterEnd() { | |
213 string(" "); | |
214 end(); | |
215 } | |
216 }); | |
217 return this; | |
218 } | |
219 | |
220 private CodeTreeBuilder endAfter() { | |
221 registerCallBack(new EndCallback() { | |
222 | |
223 @Override | |
224 public void beforeEnd() { | |
225 } | |
226 | |
227 @Override | |
228 public void afterEnd() { | |
229 end(); | |
230 } | |
231 }); | |
232 return this; | |
233 } | |
234 | |
235 private CodeTreeBuilder startParanthesesCommaGroup() { | |
236 startGroup(); | |
237 string("(").startCommaGroup(); | |
238 registerCallBack(new EndCallback() { | |
239 | |
240 @Override | |
241 public void beforeEnd() { | |
242 } | |
243 | |
244 @Override | |
245 public void afterEnd() { | |
246 string(")"); | |
247 } | |
248 }); | |
249 endAfter(); | |
250 return this; | |
251 } | |
252 | |
253 private CodeTreeBuilder startCurlyBracesCommaGroup() { | |
254 startGroup(); | |
255 string("{").startCommaGroup(); | |
256 registerCallBack(new EndCallback() { | |
257 | |
258 @Override | |
259 public void beforeEnd() { | |
260 } | |
261 | |
262 @Override | |
263 public void afterEnd() { | |
264 string("}"); | |
265 } | |
266 }); | |
267 endAfter(); | |
268 return this; | |
269 } | |
270 | |
271 public CodeTreeBuilder startParantheses() { | |
272 startGroup(); | |
273 string("(").startGroup(); | |
274 registerCallBack(new EndCallback() { | |
275 | |
276 @Override | |
277 public void beforeEnd() { | |
278 } | |
279 | |
280 @Override | |
281 public void afterEnd() { | |
282 string(")"); | |
283 } | |
284 }); | |
285 endAfter(); | |
286 return this; | |
287 } | |
288 | |
289 public CodeTreeBuilder doubleQuote(String s) { | |
290 return startGroup().string("\"" + s + "\"").end(); | |
291 } | |
292 | |
293 public CodeTreeBuilder string(String chunk1) { | |
294 return push(chunk1); | |
295 } | |
296 | |
297 public CodeTreeBuilder string(String chunk1, String chunk2) { | |
298 return push(GROUP).string(chunk1).string(chunk2).end(); | |
299 } | |
300 | |
301 public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3) { | |
302 return push(GROUP).string(chunk1).string(chunk2).string(chunk3).end(); | |
303 } | |
304 | |
305 public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4) { | |
306 return push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4).end(); | |
307 } | |
308 | |
309 public CodeTreeBuilder tree(CodeTree treeToAdd) { | |
310 if (treeToAdd instanceof BuilderCodeTree) { | |
311 return push((BuilderCodeTree) treeToAdd, true).end(); | |
312 } else { | |
313 BuilderCodeTree tree = new BuilderCodeTree(currentElement, GROUP, null, null); | |
314 currentElement.add(treeToAdd); | |
315 return push(tree, true).end(); | |
316 } | |
317 } | |
318 | |
319 public CodeTreeBuilder trees(CodeTree... trees) { | |
320 for (CodeTree tree : trees) { | |
321 tree(tree); | |
322 } | |
323 return this; | |
324 } | |
325 | |
326 public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) { | |
327 push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4); | |
328 for (int i = 0; i < chunks.length; i++) { | |
329 string(chunks[i]); | |
330 } | |
331 return end(); | |
332 } | |
333 | |
334 public CodeTreeBuilder newLine() { | |
335 return push(NEW_LINE); | |
336 } | |
337 | |
338 public CodeTreeBuilder startWhile() { | |
339 return startGroup().string("while ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); | |
340 } | |
341 | |
342 public CodeTreeBuilder startDoBlock() { | |
343 return startGroup().string("do ").startBlock(); | |
344 } | |
345 | |
346 public CodeTreeBuilder startDoWhile() { | |
347 clearLast(CodeTreeKind.NEW_LINE); | |
348 return startStatement().string(" while ").startParanthesesCommaGroup().endAfter().startGroup().endAfter(); | |
349 } | |
350 | |
351 public CodeTreeBuilder startIf() { | |
352 return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); | |
353 } | |
354 | |
355 public CodeTreeBuilder startFor() { | |
356 return startGroup().string("for ").startParantheses().endAndWhitespaceAfter().startGroup().endAfter(); | |
357 } | |
358 | |
359 public boolean startIf(boolean elseIf) { | |
360 if (elseIf) { | |
361 startElseIf(); | |
362 } else { | |
363 startIf(); | |
364 } | |
365 return true; | |
366 } | |
367 | |
368 public CodeTreeBuilder startElseIf() { | |
369 clearLast(CodeTreeKind.NEW_LINE); | |
370 return startGroup().string(" else if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); | |
371 } | |
372 | |
373 public CodeTreeBuilder startElseBlock() { | |
374 clearLast(CodeTreeKind.NEW_LINE); | |
375 return startGroup().string(" else ").startBlock().endAfter(); | |
376 } | |
377 | |
378 private boolean clearLastRec(CodeTreeKind kind, List<CodeTree> children) { | |
379 if (children == null) { | |
380 return false; | |
381 } | |
382 for (int i = children.size() - 1; i >= 0; i--) { | |
383 CodeTree child = children.get(i); | |
384 if (child.getCodeKind() == kind) { | |
385 children.remove(children.get(i)); | |
386 return true; | |
387 } else { | |
388 if (clearLastRec(kind, child.getEnclosedElements())) { | |
389 return true; | |
390 } | |
391 } | |
392 } | |
393 return false; | |
394 } | |
395 | |
396 public CodeTreeBuilder startCase() { | |
397 startGroup().string("case "); | |
398 registerCallBack(new EndCallback() { | |
399 | |
400 @Override | |
401 public void beforeEnd() { | |
402 string(" :").newLine(); | |
403 } | |
404 | |
405 @Override | |
406 public void afterEnd() { | |
407 } | |
408 }); | |
409 return this; | |
410 } | |
411 | |
412 public CodeTreeBuilder caseDefault() { | |
413 return startGroup().string("default :").newLine().end(); | |
414 } | |
415 | |
416 public CodeTreeBuilder startSwitch() { | |
417 return startGroup().string("switch ").startParanthesesCommaGroup().endAndWhitespaceAfter(); | |
418 } | |
419 | |
420 public CodeTreeBuilder startReturn() { | |
421 ExecutableElement method = findMethod(); | |
422 if (method != null && ElementUtils.isVoid(method.getReturnType())) { | |
423 startGroup(); | |
424 registerCallBack(new EndCallback() { | |
425 | |
426 @Override | |
427 public void beforeEnd() { | |
428 string(";").newLine(); // complete statement to execute | |
429 } | |
430 | |
431 @Override | |
432 public void afterEnd() { | |
433 string("return").string(";").newLine(); // emit a return; | |
434 } | |
435 }); | |
436 return this; | |
437 } else { | |
438 return startStatement().string("return "); | |
439 } | |
440 } | |
441 | |
442 public CodeTreeBuilder startAssert() { | |
443 return startStatement().string("assert "); | |
444 } | |
445 | |
446 public CodeTreeBuilder startNewArray(ArrayType arrayType, CodeTree size) { | |
447 startGroup().string("new ").type(arrayType.getComponentType()).string("["); | |
448 if (size != null) { | |
449 tree(size); | |
450 } | |
451 string("]"); | |
452 if (size == null) { | |
453 string(" "); | |
454 startCurlyBracesCommaGroup().endAfter(); | |
455 } | |
456 return this; | |
457 } | |
458 | |
459 public CodeTreeBuilder startNew(TypeMirror uninializedNodeClass) { | |
460 return startGroup().string("new ").type(uninializedNodeClass).startParanthesesCommaGroup().endAfter(); | |
461 } | |
462 | |
463 public CodeTreeBuilder startNew(String typeName) { | |
464 return startGroup().string("new ").string(typeName).startParanthesesCommaGroup().endAfter(); | |
465 } | |
466 | |
467 public CodeTreeBuilder startIndention() { | |
468 return push(CodeTreeKind.INDENT); | |
469 } | |
470 | |
471 public CodeTreeBuilder end(int times) { | |
472 for (int i = 0; i < times; i++) { | |
473 end(); | |
474 } | |
475 return this; | |
476 } | |
477 | |
478 public CodeTreeBuilder end() { | |
479 BuilderCodeTree tree = currentElement; | |
480 EndCallback callback = tree.getAtEndListener(); | |
481 if (callback != null) { | |
482 callback.beforeEnd(); | |
483 toParent(); | |
484 callback.afterEnd(); | |
485 } else { | |
486 toParent(); | |
487 } | |
488 return this; | |
489 } | |
490 | |
491 private void toParent() { | |
492 CodeTree parentElement = currentElement.getParent(); | |
493 if (currentElement != root) { | |
494 this.currentElement = (BuilderCodeTree) parentElement; | |
495 } else { | |
496 this.currentElement = root; | |
497 } | |
498 } | |
499 | |
500 public CodeTreeBuilder startBlock() { | |
501 startGroup(); | |
502 string("{").newLine().startIndention(); | |
503 registerCallBack(new EndCallback() { | |
504 | |
505 @Override | |
506 public void beforeEnd() { | |
507 } | |
508 | |
509 @Override | |
510 public void afterEnd() { | |
511 string("}").newLine(); | |
512 } | |
513 }); | |
514 endAfter(); | |
515 return this; | |
516 } | |
517 | |
518 private void registerCallBack(EndCallback callback) { | |
519 currentElement.registerAtEnd(callback); | |
520 } | |
521 | |
522 public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) { | |
523 if (!ElementUtils.isVoid(type)) { | |
524 startStatement(); | |
525 type(type); | |
526 string(" "); | |
527 string(name); | |
528 string(" = "); | |
529 defaultValue(type); | |
530 end(); // statement | |
531 } | |
532 return this; | |
533 } | |
534 | |
535 public CodeTreeBuilder declaration(TypeMirror type, String name, String init) { | |
536 return declaration(type, name, singleString(init)); | |
537 } | |
538 | |
539 public CodeTreeBuilder declaration(String type, String name, CodeTree init) { | |
540 startStatement(); | |
541 string(type); | |
542 string(" "); | |
543 string(name); | |
544 if (init != null) { | |
545 string(" = "); | |
546 tree(init); | |
547 } | |
548 end(); // statement | |
549 return this; | |
550 } | |
551 | |
552 public CodeTreeBuilder declaration(String type, String name, String init) { | |
553 return declaration(type, name, singleString(init)); | |
554 } | |
555 | |
556 public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { | |
557 if (ElementUtils.isVoid(type)) { | |
558 startStatement(); | |
559 tree(init); | |
560 end(); | |
561 } else { | |
562 startStatement(); | |
563 type(type); | |
564 string(" "); | |
565 string(name); | |
566 if (init != null) { | |
567 string(" = "); | |
568 tree(init); | |
569 } | |
570 end(); // statement | |
571 } | |
572 return this; | |
573 } | |
574 | |
575 public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTreeBuilder init) { | |
576 if (init == this) { | |
577 throw new IllegalArgumentException("Recursive builder usage."); | |
578 } | |
579 return declaration(type, name, init.getTree()); | |
580 } | |
581 | |
582 public CodeTreeBuilder create() { | |
583 return new CodeTreeBuilder(this); | |
584 } | |
585 | |
586 public CodeTreeBuilder type(TypeMirror type) { | |
587 return push(type); | |
588 } | |
589 | |
590 public CodeTreeBuilder typeLiteral(TypeMirror type) { | |
591 return startGroup().type(ElementUtils.eraseGenericTypes(type)).string(".class").end(); | |
592 } | |
593 | |
594 private void assertRoot() { | |
595 if (currentElement != root) { | |
596 throw new IllegalStateException("CodeTreeBuilder was not ended properly."); | |
597 } | |
598 } | |
599 | |
600 public CodeTreeBuilder startCaseBlock() { | |
601 return startIndention(); | |
602 } | |
603 | |
604 public CodeTreeBuilder startThrow() { | |
605 return startStatement().string("throw "); | |
606 } | |
607 | |
608 public CodeTree getTree() { | |
609 assertRoot(); | |
610 return root; | |
611 } | |
612 | |
613 public CodeTree build() { | |
614 return root; | |
615 } | |
616 | |
617 public CodeTreeBuilder cast(TypeMirror type) { | |
618 string("(").type(type).string(") "); | |
619 return this; | |
620 } | |
621 | |
622 public CodeTreeBuilder cast(TypeMirror type, CodeTree content) { | |
623 if (ElementUtils.isVoid(type)) { | |
624 tree(content); | |
625 return this; | |
626 } else if (type.getKind() == TypeKind.DECLARED && ElementUtils.getQualifiedName(type).equals("java.lang.Object")) { | |
627 tree(content); | |
628 return this; | |
629 } else { | |
630 return startGroup().string("(").type(type).string(")").string(" ").tree(content).end(); | |
631 } | |
632 } | |
633 | |
634 public CodeTreeBuilder startSuperCall() { | |
635 return string("super").startParanthesesCommaGroup(); | |
636 } | |
637 | |
638 public CodeTreeBuilder returnFalse() { | |
639 return startReturn().string("false").end(); | |
640 } | |
641 | |
642 public CodeTreeBuilder returnStatement() { | |
643 return statement("return"); | |
644 } | |
645 | |
646 public ExecutableElement findMethod() { | |
647 if (enclosingElement != null && (enclosingElement.getKind() == ElementKind.METHOD || enclosingElement.getKind() == ElementKind.CONSTRUCTOR)) { | |
648 return (ExecutableElement) enclosingElement; | |
649 } | |
650 return null; | |
651 } | |
652 | |
653 public CodeTreeBuilder returnNull() { | |
654 return startReturn().string("null").end(); | |
655 } | |
656 | |
657 public CodeTreeBuilder returnTrue() { | |
658 return startReturn().string("true").end(); | |
659 } | |
660 | |
661 public CodeTreeBuilder instanceOf(CodeTree var, TypeMirror type) { | |
662 return tree(var).string(" instanceof ").type(type); | |
663 } | |
664 | |
665 public CodeTreeBuilder defaultValue(TypeMirror mirror) { | |
666 switch (mirror.getKind()) { | |
667 case VOID: | |
668 return string(""); | |
669 case ARRAY: | |
670 case DECLARED: | |
671 case PACKAGE: | |
672 case NULL: | |
673 return string("null"); | |
674 case BOOLEAN: | |
675 return string("false"); | |
676 case BYTE: | |
677 return string("(byte) 0"); | |
678 case CHAR: | |
679 return string("(char) 0"); | |
680 case DOUBLE: | |
681 return string("0.0D"); | |
682 case LONG: | |
683 return string("0L"); | |
684 case INT: | |
685 return string("0"); | |
686 case FLOAT: | |
687 return string("0.0F"); | |
688 case SHORT: | |
689 return string("(short) 0"); | |
690 default: | |
691 throw new AssertionError(); | |
692 } | |
693 } | |
694 | |
695 public CodeTreeBuilder startTryBlock() { | |
696 return string("try ").startBlock(); | |
697 } | |
698 | |
699 public CodeTreeBuilder startCatchBlock(TypeMirror exceptionType, String localVarName) { | |
700 clearLast(CodeTreeKind.NEW_LINE); | |
701 string(" catch (").type(exceptionType).string(" ").string(localVarName).string(") "); | |
702 return startBlock(); | |
703 } | |
704 | |
705 public CodeTreeBuilder startCatchBlock(TypeMirror[] exceptionTypes, String localVarName) { | |
706 clearLast(CodeTreeKind.NEW_LINE); | |
707 string(" catch ("); | |
708 | |
709 for (int i = 0; i < exceptionTypes.length; i++) { | |
710 if (i != 0) { | |
711 string(" | "); | |
712 } | |
713 type(exceptionTypes[i]); | |
714 } | |
715 | |
716 string(" ").string(localVarName).string(") "); | |
717 return startBlock(); | |
718 } | |
719 | |
720 public CodeTreeBuilder startFinallyBlock() { | |
721 clearLast(CodeTreeKind.NEW_LINE); | |
722 string(" finally "); | |
723 return startBlock(); | |
724 } | |
725 | |
726 public CodeTreeBuilder nullLiteral() { | |
727 return string("null"); | |
728 } | |
729 | |
730 private static class BuilderCodeTree extends CodeTree { | |
731 | |
732 private EndCallback atEndListener; | |
733 private CodeTreeKind removeLast; | |
734 | |
735 public BuilderCodeTree(CodeTree parent, CodeTreeKind kind, TypeMirror type, String string) { | |
736 super(parent, kind, type, string); | |
737 } | |
738 | |
739 public void registerAtEnd(EndCallback atEnd) { | |
740 if (this.atEndListener != null) { | |
741 this.atEndListener = new CompoundCallback(this.atEndListener, atEnd); | |
742 } else { | |
743 this.atEndListener = atEnd; | |
744 } | |
745 } | |
746 | |
747 public EndCallback getAtEndListener() { | |
748 return atEndListener; | |
749 } | |
750 | |
751 @Override | |
752 public String toString() { | |
753 final StringBuilder b = new StringBuilder(); | |
754 new Printer(b).visitTree(this, null, null); | |
755 return b.toString(); | |
756 } | |
757 | |
758 private static class CompoundCallback implements EndCallback { | |
759 | |
760 private final EndCallback callback1; | |
761 private final EndCallback callback2; | |
762 | |
763 public CompoundCallback(EndCallback callback1, EndCallback callback2) { | |
764 this.callback1 = callback1; | |
765 this.callback2 = callback2; | |
766 } | |
767 | |
768 @Override | |
769 public void afterEnd() { | |
770 callback1.afterEnd(); | |
771 callback2.afterEnd(); | |
772 } | |
773 | |
774 @Override | |
775 public void beforeEnd() { | |
776 callback1.beforeEnd(); | |
777 callback1.beforeEnd(); | |
778 } | |
779 } | |
780 | |
781 } | |
782 | |
783 private interface EndCallback { | |
784 | |
785 void beforeEnd(); | |
786 | |
787 void afterEnd(); | |
788 } | |
789 | |
790 private static class Printer extends CodeElementScanner<Void, Void> { | |
791 | |
792 private int indent; | |
793 private boolean newLine; | |
794 private final String ln = "\n"; | |
795 | |
796 private final StringBuilder b; | |
797 | |
798 Printer(StringBuilder b) { | |
799 this.b = b; | |
800 } | |
801 | |
802 @Override | |
803 public void visitTree(CodeTree e, Void p, Element enclosingElement) { | |
804 switch (e.getCodeKind()) { | |
805 case COMMA_GROUP: | |
806 List<CodeTree> children = e.getEnclosedElements(); | |
807 if (children != null) { | |
808 for (int i = 0; i < children.size(); i++) { | |
809 visitTree(children.get(i), p, enclosingElement); | |
810 if (i < e.getEnclosedElements().size() - 1) { | |
811 b.append(", "); | |
812 } | |
813 } | |
814 } | |
815 break; | |
816 case GROUP: | |
817 super.visitTree(e, p, enclosingElement); | |
818 break; | |
819 case INDENT: | |
820 indent(); | |
821 super.visitTree(e, p, enclosingElement); | |
822 dedent(); | |
823 break; | |
824 case NEW_LINE: | |
825 writeLn(); | |
826 break; | |
827 case STRING: | |
828 if (e.getString() != null) { | |
829 write(e.getString()); | |
830 } else { | |
831 write("null"); | |
832 } | |
833 break; | |
834 case TYPE: | |
835 write(ElementUtils.getSimpleName(e.getType())); | |
836 break; | |
837 default: | |
838 assert false; | |
839 return; | |
840 } | |
841 } | |
842 | |
843 private void indent() { | |
844 indent++; | |
845 } | |
846 | |
847 private void dedent() { | |
848 indent--; | |
849 } | |
850 | |
851 private void writeLn() { | |
852 write(ln); | |
853 newLine = true; | |
854 } | |
855 | |
856 private void write(String m) { | |
857 if (newLine && m != ln) { | |
858 writeIndent(); | |
859 newLine = false; | |
860 } | |
861 b.append(m); | |
862 } | |
863 | |
864 private void writeIndent() { | |
865 for (int i = 0; i < indent; i++) { | |
866 b.append(" "); | |
867 } | |
868 } | |
869 } | |
870 | |
871 public CodeTreeBuilder returnDefault() { | |
872 ExecutableElement method = findMethod(); | |
873 if (ElementUtils.isVoid(method.getReturnType())) { | |
874 returnStatement(); | |
875 } else { | |
876 startReturn().defaultValue(method.getReturnType()).end(); | |
877 } | |
878 return this; | |
879 | |
880 } | |
881 | |
882 } |