View Javadoc
1   package net.sourceforge.jenesis4java.impl;
2   
3   /*
4    * #%L
5    * Jenesis 4 Java Code Generator
6    * %%
7    * Copyright (C) 2000 - 2015 jenesis4java
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  
25  /**
26   * Copyright (C) 2008, 2010 Richard van Nieuwenhoven - ritchie [at] gmx [dot] at
27   * Copyright (C) 2000, 2001 Paul Cody Johnston - pcj@inxar.org <br>
28   * This file is part of Jenesis4java. Jenesis4java is free software: you can
29   * redistribute it and/or modify it under the terms of the GNU Lesser General
30   * Public License as published by the Free Software Foundation, either version 3
31   * of the License, or (at your option) any later version.<br>
32   * Jenesis4java is distributed in the hope that it will be useful, but WITHOUT
33   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
34   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
35   * details.<br>
36   * You should have received a copy of the GNU Lesser General Public License
37   * along with Jenesis4java. If not, see <http://www.gnu.org/licenses/>.
38   */
39  
40  import net.sourceforge.jenesis4java.*;
41  import net.sourceforge.jenesis4java.Access.AccessType;
42  import net.sourceforge.jenesis4java.exceptions.ImportConflictException;
43  import net.sourceforge.jenesis4java.impl.util.*;
44  
45  import java.io.File;
46  import java.io.Serializable;
47  import java.util.ArrayList;
48  import java.util.Collections;
49  import java.util.Comparator;
50  import java.util.List;
51  
52  /**
53   * Standard {@code Declaration} implementations.
54   */
55  abstract class MDeclaration extends MVM.MCodeable {
56  
57      /**
58       * BLOCK DECLARATION
59       */
60      static class BlockDeclaration extends MMember {
61  
62          List<Statement> vs = new ArrayList<>();
63  
64          BlockDeclaration(MVM vm) {
65              super(vm);
66          }
67  
68          @Override
69          public List<Statement> codeableList() {
70              return getStatements();
71          }
72  
73          public List<Statement> getStatements() {
74              return ListTypeSelector.select(vs, Statement.class);
75          }
76  
77          public Statement insertStatement(int index, Expression expression) {
78              ExpressionStatement expressionStatement = new MStatement.MExpressionStatement((MVM) vm(), expression);
79              vs.add(index, expressionStatement);
80              return expressionStatement;
81          }
82  
83          public void insertStatement(int index, Statement statement) {
84              vs.add(index, statement);
85  
86          }
87  
88          @Override
89          public boolean isBlockWithAbruptCompletion() {
90              return BlockUtil.isBlockWithAbruptCompletion(getStatements());
91          }
92  
93          public Break newBreak() {
94              Break x = new MStatement.MBreak(vm);
95              vs.add(x);
96              return x;
97          }
98  
99          public Continue newContinue() {
100             Continue x = new MStatement.MContinue(vm);
101             vs.add(x);
102             return x;
103         }
104 
105         public Let newDeclarationLet(Type type) {
106             Let x = new MStatement.MLet(vm, type);
107             int index = 0;
108             while (index < vs.size() && vs.get(index) instanceof Let) {
109                 index++;
110             }
111             vs.add(index, x);
112             return x;
113         }
114 
115         public DoWhile newDoWhile(Expression e) {
116             DoWhile x = new MStatement.MDoWhile(vm, e);
117             vs.add(x);
118             return x;
119         }
120 
121         public Empty newEmpty() {
122             Empty x = new MStatement.MEmpty(vm);
123             vs.add(x);
124             return x;
125         }
126 
127         public For newFor() {
128             For x = new MStatement.MFor(vm);
129             vs.add(x);
130             return x;
131         }
132 
133         public If newIf(Expression e) {
134             If x = new MStatement.MIf(vm, e);
135             vs.add(x);
136             return x;
137         }
138 
139         public Let newLet(Type type) {
140             Let x = new MStatement.MLet(vm, type);
141             vs.add(x);
142             return x;
143         }
144 
145         public LocalBlock newLocalBlock() {
146             LocalBlock x = new MStatement.MLocalBlock(vm);
147             vs.add(x);
148             return x;
149         }
150 
151         public LocalClass newLocalClass(String name) {
152             return newLocalClass(name, new MemberComparator());
153         }
154 
155         public LocalClass newLocalClass(String name, Comparator comparator) {
156             LocalClass x = new MLocalClass(vm, name, comparator);
157             vs.add(x);
158             return x;
159         }
160 
161         public Return newReturn() {
162             Return x = new MStatement.MReturn(vm);
163             vs.add(x);
164             return x;
165         }
166 
167         public ExpressionStatement newStmt(Expression expr) {
168             ExpressionStatement x = new MStatement.MExpressionStatement(vm, expr);
169             vs.add(x);
170             return x;
171         }
172 
173         public Switch newSwitch(Expression e) {
174             Switch x = new MStatement.MSwitch(vm, e);
175             vs.add(x);
176             return x;
177         }
178 
179         public Synchronized newSynchronized(Expression e) {
180             Synchronized x = new MStatement.MSynchronized(vm, e);
181             vs.add(x);
182             return x;
183         }
184 
185         public Throw newThrow(Expression e) {
186             Throw x = new MStatement.MThrow(vm, e);
187             vs.add(x);
188             return x;
189         }
190 
191         public Try newTry() {
192             Try x = new MTry(vm);
193             vs.add(x);
194             return x;
195         }
196 
197         public While newWhile(Expression e) {
198             While x = new MStatement.MWhile(vm, e);
199             vs.add(x);
200             return x;
201         }
202 
203         public void removeStmt(Statement statement) {
204             vs.remove(statement);
205         }
206 
207         @Override
208         public void visit(ReplacingVisitor visitor) {
209             super.visit(visitor);
210             VisitorUtils.visit(vs, this, visitor);
211         }
212     }
213 
214     /**
215      * ABSTRACT METHOD DECLARATION
216      */
217     static class MAbstractMethod extends MMethod implements AbstractMethod {
218 
219         MAbstractMethod(MVM vm, Type type, String name) {
220             super(vm, type, name);
221             isAbstract = true;
222         }
223 
224         @Override
225         public CodeWriter toCode(CodeWriter out) {
226             super.toCode(out);
227 
228             AccessType.toCode(access, out);
229 
230             writeTypeParametersAndThrow(name, type, parameters, throwz, out);
231 
232             out.write(';');
233 
234             return out;
235         }
236     }
237 
238     /**
239      * CLASS DECLARATION
240      */
241     static class MClassDeclaration extends MTypeDeclaration implements ClassDeclaration {
242 
243         String ex;
244 
245         boolean isAbstract;
246 
247         List<String> implementations = new ArrayList<>();
248 
249         MClassDeclaration(MVM vm, MCompilationUnit unit) {
250             super(vm, unit);
251         }
252 
253         @Override
254         public MClassDeclaration addImplements(String type) {
255             implementations.add(type);
256             return this;
257         }
258 
259         @Override
260         public Import addImport(Class<?> clazz) {
261             return addImport(clazz.getName());
262         }
263 
264         @Override
265         public Import addImport(String name) {
266             return getUnit().addImport(name);
267         }
268 
269         @Override
270         public ClassType asClassType() {
271             return vm().newType(getUnit().getNamespace().getName() + "." + getName());
272         }
273 
274         @Override
275         public List<Constructor> getConstructors() {
276             return ListTypeSelector.select(members, Constructor.class);
277         }
278 
279         @Override
280         public String getExtends() {
281             return ex;
282         }
283 
284         @Override
285         public List<ClassField> getFields() {
286             return ListTypeSelector.select(members, ClassField.class);
287         }
288 
289         @Override
290         public List<String> getImplements() {
291             return ListTypeSelector.select(implementations);
292         }
293 
294         public List<InitializationDeclaration> getInitializations() {
295             return ListTypeSelector.select(members, InitializationDeclaration.class);
296         }
297 
298         @Override
299         public List<InnerClass> getInnerClasses() {
300             return ListTypeSelector.select(members, InnerClass.class);
301         }
302 
303         @Override
304         public List<Member> getMembers() {
305             return ListTypeSelector.select(members, Member.class);
306         }
307 
308         @Override
309         public List<ClassMethod> getMethods() {
310             return ListTypeSelector.select(members, ClassMethod.class);
311         }
312 
313         @Override
314         public List<ClassMethod> getMethods(String methodName) {
315             List<ClassMethod> list = new ArrayList<>();
316             for (ClassMethod method : getMethods()) {
317                 if (method.getName().equals(methodName)) {
318                     list.add(method);
319                 }
320             }
321             return list;
322         }
323 
324         @Override
325         public List<StaticInitializer> getStaticInitializers() {
326             return ListTypeSelector.select(members, StaticInitializer.class);
327         }
328 
329         @Override
330         public boolean isAbstract() {
331             return isAbstract;
332         }
333 
334         @Override
335         public MClassDeclaration isAbstract(boolean value) {
336             isAbstract = value;
337             return this;
338         }
339 
340         @Override
341         public boolean isMethodAlreadyDefined(Type type, String name) {
342             for (ClassMethod cm : getMethods()) {
343                 if (cm.getName().equals(name) && cm.getType().equals(type)) {
344                     return true;
345                 }
346             }
347             return false;
348         }
349 
350         @Override
351         public Constructor newConstructor() {
352             Constructor x = new MConstructor(vm, name);
353             members.add(x);
354             return x;
355         }
356 
357         @Override
358         public ClassField newField(Class<?> type, String name) {
359             if (!type.getName().startsWith("java.lang.")) {
360                 Class<?> typeToImport = type;
361                 if (typeToImport.isArray()) {
362                     typeToImport = typeToImport.getComponentType();
363                 }
364                 if (typeToImport != null) {
365                     addImport(typeToImport);
366                 }
367             }
368             return newField(vm.newType(type.getSimpleName()), name);
369         }
370 
371         @Override
372         public ClassField newField(Type type, String name) {
373             ClassField x = new MClassField(vm, type, name);
374             members.add(x);
375             return x;
376         }
377 
378         @Override
379         public InnerClass newInnerClass(String name) {
380             InnerClass x = new MInnerClass(vm, unit, this, name);
381             members.add(x);
382             return x;
383         }
384 
385         @Override
386         public InnerInterface newInnerInterface(String name) {
387             MInnerInterface x = new MInnerInterface(vm, unit, this, name);
388             members.add(x);
389             return x;
390         }
391 
392         @Override
393         public ClassMethod newMethod(String name) {
394             return newMethod(vm().newType(Type.VOID), name);
395         }
396 
397         @Override
398         public ClassMethod newMethod(Type type, String name) {
399             ClassMethod x = new MClassMethod(vm, type, name);
400             members.add(x);
401             return x;
402         }
403 
404         @Override
405         public StaticInitializer newStaticInitializer() {
406             StaticInitializer x = new MStaticInitializer(vm);
407             members.add(x);
408             return x;
409         }
410 
411         @Override
412         public MClassDeclaration setExtends(String ex) {
413             this.ex = ex;
414             return this;
415         }
416 
417         @Override
418         public CodeWriter toCode(CodeWriter out) {
419             super.toCode(out);
420 
421             AccessType.toCode(access, out);
422 
423             if (isAbstract) {
424                 out.write("abstract ");
425             }
426             if (isStatic) {
427                 out.write("static ");
428             }
429             if (isFinal) {
430                 out.write("final ");
431             }
432 
433             // write the class and name
434             out.write("class ").write(name);
435 
436             // write the extends clause, if there is one
437             if (ex != null) {
438                 out.space().write("extends ").write(ex);
439             }
440 
441             // write the implements clause if there are any
442             if (!implementations.isEmpty()) {
443                 out.space().write("implements ");
444                 for (int i = 0; i < implementations.size(); i++) {
445                     if (i > 0) {
446                         out.write(", ");
447                     }
448                     out.write(implementations.get(i));
449                 }
450             }
451             writeBlock(out, vm.getStyle("class"));
452             return out;
453         }
454 
455         @Override
456         public boolean removeImplements(String interfaceName) {
457             return implementations.remove(interfaceName);
458         }
459     }
460 
461     /**
462      * CLASS FIELD DECLARATION
463      */
464     static class MClassField extends MField implements ClassField {
465 
466         // the transient flag
467         boolean isTransient;
468 
469         // the volatile flag
470         boolean isVolatile;
471 
472         public MClassField(MVM vm, Type type, String name) {
473             super(vm, type, name);
474         }
475 
476         @Override
477         public boolean isTransient() {
478             return isTransient;
479         }
480 
481         @Override
482         public MClassField isTransient(boolean isTransient) {
483             this.isTransient = isTransient;
484             return this;
485         }
486 
487         @Override
488         public boolean isVolatile() {
489             return isVolatile;
490         }
491 
492         @Override
493         public MClassField isVolatile(boolean isVolatile) {
494             this.isVolatile = isVolatile;
495             return this;
496         }
497 
498         @Override
499         public CodeWriter toCode(CodeWriter out) {
500             super.toCode(out);
501             AccessType.toCode(access, out);
502 
503             if (isTransient) {
504                 out.write("transient ");
505             }
506             if (isVolatile) {
507                 out.write("volatile ");
508             }
509             if (isStatic) {
510                 out.write("static ");
511             }
512             if (isFinal) {
513                 out.write("final ");
514             }
515 
516             // write the class and name
517             out.write(type).space().write(name);
518 
519             if (expr != null) {
520                 out.write(" = ").write(expr);
521             }
522 
523             out.write(';');
524             if (comment != null && comment.getType() == Comment.TRAILING) {
525                 out.write(comment);
526             }
527 
528             return out;
529         }
530     }
531 
532     /**
533      * CLASS METHOD DECLARATION
534      */
535     static class MClassMethod extends MMethod implements ClassMethod {
536 
537         boolean isNative;
538 
539         boolean isSynchronized;
540 
541         MClassMethod(MVM vm, Type type, String name) {
542             super(vm, type, name);
543         }
544 
545         @Override
546         public boolean isNative() {
547             return isNative;
548         }
549 
550         @Override
551         public MClassMethod isNative(boolean isNative) {
552             this.isNative = isNative;
553             return this;
554         }
555 
556         @Override
557         public boolean isSynchronized() {
558             return isSynchronized;
559         }
560 
561         @Override
562         public MClassMethod isSynchronized(boolean isSynchronized) {
563             this.isSynchronized = isSynchronized;
564             return this;
565         }
566 
567         @Override
568         public CodeWriter toCode(CodeWriter out) {
569             super.toCode(out);
570             AccessType.toCode(access, out);
571 
572             if (isAbstract) {
573                 out.write("abstract ");
574             }
575             if (isNative) {
576                 out.write("native ");
577             }
578             if (isSynchronized) {
579                 out.write("synchronized ");
580             }
581             if (isStatic) {
582                 out.write("static ");
583             }
584             if (isFinal) {
585                 out.write("final ");
586             }
587 
588             writeTypeParametersAndThrow(name, type, parameters, throwz, out);
589             if (isAbstract) {
590                 out.write(";");
591             } else {
592                 writeBlock(out, vm.getStyle("method"));
593             }
594 
595             return out;
596         }
597 
598     }
599 
600     /**
601      * COMPILATION UNIT DECLARATION
602      */
603     static class MCompilationUnit extends MDeclaration implements CompilationUnit {
604 
605         boolean isEncoded; // flag to track if we have encoded yet.
606 
607         List<TypeDeclaration> types = new ArrayList<>();
608 
609         List<MImport> imports = new ArrayList<>();
610 
611         final String codebase;
612 
613         Namespace namespace;
614 
615         MCompilationUnit(MVM vm, String codebase) {
616             super(vm);
617             this.codebase = codebase;
618         }
619 
620         @Override
621         public Import addImport(Class<?> clazz) {
622             if (clazz == null) {
623                 throw new IllegalArgumentException("Null is no legal import.");
624             }
625 
626             return addImport(clazz.getName());
627         }
628 
629         @Override
630         public Import addImport(String name) {
631             if (name == null) {
632                 throw new IllegalArgumentException("Null is no legal import.");
633             } else if (name.trim().isEmpty()) {
634                 throw new IllegalArgumentException("Empty import not supported.");
635             }
636 
637             for (MImport im : imports) {
638                 if (im.isClassnamePartOfImport(name)) {
639                     return im;
640                 }
641                 if (im.isClassNameAlreadyUsed(name)) {
642                     throw new ImportConflictException(im.getName(), name);
643                 }
644             }
645             MImport x = new MImport(vm, name);
646             imports.add(x);
647             return x;
648         }
649 
650         @Override
651         public MCompilationUnit encode() {
652             // have we already called this method?
653             if (isEncoded) {
654                 return this;
655             }
656             vm.getEncoder().encode(this);
657             isEncoded = true;
658             return this;
659         }
660 
661         @Override
662         public String getCodebase() {
663             return codebase;
664         }
665 
666         public String getFileName() {
667             // make the fileName of the target file as the concatenation
668             // of the sourcepath, the package name, and the className,
669             // and the ending dot java
670             StringBuilder file;
671 
672             // was a path specified?
673             if (codebase != null && codebase.length() > 0) {
674                 file = new StringBuilder(codebase);
675                 // does the codebase end with a slash?
676                 if (!codebase.endsWith(Character.toString(File.separatorChar))) {
677                     // make it so...
678                     file.append(File.separatorChar);
679                 }
680             } else {
681                 file = new StringBuilder();
682             }
683 
684             // append to the filepath if exists
685             if (namespace != null) {
686                 // fetch the package name
687                 String pkg = namespace.getName();
688                 if (pkg != null) {
689                     // append the package name
690                     file.append(pkg.replace('.', java.io.File.separatorChar));
691                 }
692             }
693 
694             // add a separator, the top level name, and the extention
695             String topLevelTypeName = getTopLevelType().getName();
696             int indexOfGeneric = topLevelTypeName.indexOf('<');
697             if (indexOfGeneric > 0) {
698                 topLevelTypeName = topLevelTypeName.substring(0, indexOfGeneric).trim();
699             }
700             file.append(java.io.File.separatorChar).append(topLevelTypeName).append(".java");
701 
702             // done
703             return file.toString();
704         }
705 
706         @Override
707         public List<Import> getImports() {
708             return ListTypeSelector.generalize(imports, Import.class);
709         }
710 
711         @Override
712         public Namespace getNamespace() {
713             if (namespace == null) {
714                 namespace = new MNamespace(vm, null);
715             }
716             return namespace;
717         }
718 
719         @Override
720         public PackageClass getPackageClass(String name) {
721             if (name == null) {
722                 return null;
723             }
724             for (PackageClass pc : ListTypeSelector.select(getTypes(), PackageClass.class)) {
725                 if (pc.getName().equals(name)) {
726                     return pc;
727                 }
728             }
729             return null;
730         }
731 
732         @Override
733         public TypeDeclaration getTopLevelType() {
734             return types.isEmpty() ? null : types.get(0);
735         }
736 
737         @Override
738         public List<TypeDeclaration> getTypes() {
739             return ListTypeSelector.select(types, TypeDeclaration.class);
740         }
741 
742         @Override
743         public PackageClass newClass(String name) {
744             PackageClass x = new MPackageClass(vm, this);
745             x.setName(name);
746             types.add(x);
747             return x;
748         }
749 
750         @Override
751         public Interface newInterface(String name) {
752             Interface x = new MInterface(vm, this);
753             x.setName(name);
754             types.add(x);
755             return x;
756         }
757 
758         @Override
759         public PackageClass newPublicClass(String name) {
760             return newClass(name)//
761                     .setAccess(AccessType.PUBLIC)//
762                     .cast(PackageClass.class);
763         }
764 
765         @Override
766         public Interface newPublicInterface(String name) {
767             return newInterface(name)//
768                     .setAccess(AccessType.PUBLIC)//
769                     .cast(Interface.class);
770         }
771 
772         @Override
773         public Namespace setNamespace(String name) {
774             namespace = new MNamespace(vm, name);
775             return namespace;
776         }
777 
778         @Override
779         public CodeWriter toCode(CodeWriter out) {
780             out.setCompilationUnit(this);
781             if (comment != null) {
782                 out.write(comment).newLine();
783             }
784 
785             if (namespace != null) {
786                 out.write(namespace).newLine();
787             }
788 
789             if (!getImports().isEmpty()) {
790                 out.write(getImports());
791             }
792 
793             out.write(getTypes());
794 
795             return out;
796         }
797 
798         @Override
799         public void visit(ReplacingVisitor visitor) {
800             super.visit(visitor);
801             namespace = VisitorUtils.visit(namespace, this, visitor);
802             VisitorUtils.visit(imports, this, visitor);
803             VisitorUtils.visit(types, this, visitor);
804         }
805 
806     }
807 
808     /**
809      * CONSTANT DECLARATION
810      */
811     static class MConstant extends MField implements Constant {
812 
813         public MConstant(MVM vm, Type type, String name) {
814             super(vm, type, name);
815             isStatic = true;
816             isFinal = true;
817         }
818 
819         @Override
820         public CodeWriter toCode(CodeWriter out) {
821             super.toCode(out);
822 
823             // write the class and name
824             out.write("static final ").write(type).space().write(name);
825 
826             if (expr != null) {
827                 out.write(" = ").write(expr);
828             }
829 
830             out.write(';');
831             return out;
832         }
833     }
834 
835     /**
836      * CONSTRUCTOR DECLARATION
837      */
838     static class MConstructor extends MMethod implements Constructor {
839 
840         private ConstructorForwarding forwarding;
841 
842         MConstructor(MVM vm, String name) {
843             super(vm, null, name);
844         }
845 
846         @Override
847         public ConstructorForwarding forwardCall(ForwardingTarget target) {
848             if (target == null) {
849                 forwarding = null;
850             } else {
851                 forwarding = new MStatement.MConstructorForwarding(vm, target);
852             }
853             return forwarding;
854         }
855 
856         @Override
857         public MConstructor addThrows(String name) {
858             super.addThrows(name);
859             return this;
860         }
861 
862         @Override
863         public CodeWriter toCode(CodeWriter out) {
864             super.toCode(out);
865             AccessType.toCode(access, out);
866 
867             writeTypeParametersAndThrow(name, null, parameters, throwz, out);
868 
869             writeBlock(out, vm.getStyle("constructor"));
870 
871             return out;
872         }
873 
874         @Override
875         public List<Statement> codeableList() {
876             if (forwarding != null) {
877                 List<Statement> statements = new ArrayList<>();
878                 statements.add(forwarding);
879                 statements.addAll(super.codeableList());
880                 return statements;
881             } else {
882                 return super.codeableList();
883             }
884         }
885 
886         @Override
887         public void visit(ReplacingVisitor visitor) {
888             super.visit(visitor);
889             forwarding = VisitorUtils.visit(forwarding, this, visitor);
890         }
891     }
892 
893     /**
894      * FIELD DECLARATION
895      */
896     abstract static class MField extends MMember implements Field {
897 
898         // the type
899         Type type;
900 
901         // the init expr
902         Expression expr;
903 
904         public MField(MVM vm, Type type, String name) {
905             super(vm);
906             this.type = type;
907             this.name = name;
908         }
909 
910         @Override
911         public Expression getExpression() {
912             return expr;
913         }
914 
915         @Override
916         public Type getType() {
917             return type;
918         }
919 
920         @Override
921         public MField setExpression(Expression expr) {
922             this.expr = expr;
923             return this;
924         }
925 
926         @Override
927         public MField setType(Type type) {
928             this.type = type;
929             return this;
930         }
931 
932         @Override
933         public CodeWriter toCode(CodeWriter out) {
934             // special treatment for class fields
935             // always ensure exactly one line is emptyfree at the top
936 
937             out.ensureNewLine().newLine();
938 
939             if (comment != null && comment.getType() != Comment.TRAILING) {
940                 out.write(comment);
941             }
942 
943             if (!annotations.isEmpty()) {
944                 for (Annotation annotation : getAnnotations()) {
945                     out.write(annotation);
946                     out.newLine();
947                 }
948             }
949             out.ensureNewLine();
950 
951             return out;
952         }
953 
954         @Override
955         public void visit(ReplacingVisitor visitor) {
956             super.visit(visitor);
957             type = VisitorUtils.visit(type, this, visitor);
958             expr = VisitorUtils.visit(expr, this, visitor);
959         }
960 
961         // never called
962         @Override
963         List<Codeable> codeableList() {
964             return null;
965         }
966     }
967 
968     /**
969      * FORMAL PARAMETER DECLARATION
970      */
971     static class MFormalParameter extends MDeclaration implements FormalParameter {
972 
973         Type type;
974 
975         String name;
976 
977         boolean isFinal;
978 
979         MFormalParameter(MVM vm, Type type, String name) {
980             super(vm);
981             this.type = type;
982             this.name = name;
983         }
984 
985         @Override
986         public String getName() {
987             return name;
988         }
989 
990         @Override
991         public Type getType() {
992             return type;
993         }
994 
995         @Override
996         public boolean isFinal() {
997             return isFinal;
998         }
999 
1000         @Override
1001         public MFormalParameter isFinal(boolean value) {
1002             isFinal = value;
1003             return this;
1004         }
1005 
1006         @Override
1007         public MFormalParameter setName(String name) {
1008             this.name = name;
1009             return this;
1010         }
1011 
1012         @Override
1013         public MFormalParameter setType(Type type) {
1014             this.type = type;
1015             return this;
1016         }
1017 
1018         @Override
1019         public CodeWriter toCode(CodeWriter out) {
1020             out.queue(comment);
1021             if (isFinal) {
1022                 out.write("final ");
1023             }
1024             out.write(type).space().write(name);
1025             return out;
1026         }
1027 
1028         @Override
1029         public void visit(ReplacingVisitor visitor) {
1030             super.visit(visitor);
1031             type = VisitorUtils.visit(type, this, visitor);
1032         }
1033     }
1034 
1035     /**
1036      * IMPORT DECLARATION
1037      */
1038     static class MImport extends MDeclaration implements Import {
1039 
1040         String name;
1041 
1042         MImport(MVM vm, String name) {
1043             super(vm);
1044             this.name = name;
1045         }
1046 
1047         private static String baseClassName(String fullclassname) {
1048             int indexOfDot = fullclassname.lastIndexOf('.');
1049             return (indexOfDot < 0) ? fullclassname : fullclassname.substring(indexOfDot);
1050         }
1051 
1052         @Override
1053         public String getName() {
1054             return name;
1055         }
1056 
1057         public boolean isClassnamePartOfImport(String fullclassname) {
1058             if (isSingle()) {
1059                 return getName().equals(fullclassname);
1060             } else {
1061                 String packagename = getName().substring(0, getName().lastIndexOf('.'));
1062                 return packagename.equals(fullclassname.substring(0, fullclassname.lastIndexOf('.')));
1063             }
1064         }
1065 
1066         public boolean isClassNameAlreadyUsed(String fullclassname) {
1067             return isSingle() && baseClassName(getName()).equals(baseClassName(fullclassname));
1068         }
1069 
1070         @Override
1071         public boolean isSingle() {
1072             return !name.endsWith("*");
1073         }
1074 
1075         @Override
1076         public MImport setName(String name) {
1077             this.name = name;
1078             return this;
1079         }
1080 
1081         @Override
1082         public CodeWriter toCode(CodeWriter out) {
1083             out.ensureNewLine();
1084             super.toCode(out);
1085             out.write("import ").write(name).write(';').newLine();
1086             return out;
1087         }
1088     }
1089 
1090     /**
1091      * INNER CLASS DECLARATION
1092      */
1093     static class MInnerClass extends MClassDeclaration implements InnerClass {
1094 
1095         final MClassDeclaration parent;
1096 
1097         MInnerClass(MVM vm, MCompilationUnit unit, MClassDeclaration parent, String name) {
1098             super(vm, unit);
1099             this.parent = parent;
1100             this.name = name;
1101             this.setComparator(parent.getComparator());
1102         }
1103 
1104         @Override
1105         public ClassDeclaration getParentClass() {
1106             return parent;
1107         }
1108 
1109         @Override
1110         public void visit(ReplacingVisitor visitor) {
1111             super.visit(visitor);
1112             // skip parent that would be an endless loop
1113         }
1114     }
1115 
1116     /**
1117      * INNER CLASS DECLARATION
1118      */
1119     static class MInnerInterface extends MInterface implements InnerInterface {
1120 
1121         final MClassDeclaration parent;
1122 
1123         MInnerInterface(MVM vm, MCompilationUnit unit, MClassDeclaration parent, String name) {
1124             super(vm, unit);
1125             this.parent = parent;
1126             this.name = name;
1127             this.setComparator(parent.getComparator());
1128         }
1129 
1130         @Override
1131         public ClassDeclaration getParentClass() {
1132             return parent;
1133         }
1134 
1135         @Override
1136         public void visit(ReplacingVisitor visitor) {
1137             super.visit(visitor);
1138             // skip parent that would be an endless loop
1139         }
1140     }
1141 
1142     /**
1143      * INTERFACE DECLARATION
1144      */
1145     static class MInterface extends MTypeDeclaration implements Interface {
1146 
1147         List<String> extendz = new ArrayList<>();
1148 
1149         MInterface(MVM vm, MCompilationUnit unit) {
1150             super(vm, unit);
1151         }
1152 
1153         @Override
1154         public Interface addExtends(String ex) {
1155             extendz.add(ex);
1156             return this;
1157         }
1158 
1159         @Override
1160         public ClassType asClassType() {
1161             return vm().newType(getUnit().getNamespace().getName() + "." + getName());
1162         }
1163 
1164         @Override
1165         public List<String> getExtends() {
1166             return ListTypeSelector.select(extendz);
1167         }
1168 
1169         @Override
1170         public Constant newConstant(String name, int val) {
1171             Constant x = new MConstant(vm, vm.INT, name);
1172             x.setExpression(new MLiteral.MIntLiteral(vm, val));
1173             members.add(x);
1174             return x;
1175         }
1176 
1177         @Override
1178         public Constant newConstant(Type type, String name) {
1179             Constant x = new MConstant(vm, type, name);
1180             members.add(x);
1181             return x;
1182         }
1183 
1184         @Override
1185         public AbstractMethod newMethod(String name) {
1186             return newMethod(vm().newType(Type.VOID), name);
1187         }
1188 
1189         @Override
1190         public AbstractMethod newMethod(Type type, String name) {
1191             AbstractMethod x = new MAbstractMethod(vm, type, name);
1192             members.add(x);
1193             return x;
1194         }
1195 
1196         @Override
1197         public CodeWriter toCode(CodeWriter out) {
1198             super.toCode(out);
1199 
1200             AccessType.toCode(access, out);
1201 
1202             if (isFinal) {
1203                 out.write("final ");
1204             }
1205             out.write("interface ").write(name);
1206 
1207             if (!extendz.isEmpty()) {
1208                 out.newLine().write("extends ");
1209 
1210                 for (int i = 0; i < extendz.size(); i++) {
1211                     if (i > 0) {
1212                         out.write(", ");
1213                     }
1214                     out.write(extendz.get(i));
1215                 }
1216             }
1217 
1218             writeBlock(out, vm.getStyle("interface"));
1219             return out;
1220         }
1221 
1222         @Override
1223         public boolean removeExtends(String className) {
1224             return extendz.remove(className);
1225         }
1226     }
1227 
1228     /**
1229      * LOCAL CLASS DECLARATION
1230      */
1231     static class MLocalClass extends MClassDeclaration implements LocalClass {
1232 
1233         String label;
1234 
1235         MLocalClass(MVM vm, String name, Comparator comparator) {
1236             super(vm, null); /*
1237                               * * *| NOTE: we are passing null and thus cannot
1238                               * load() a local class! |* *
1239                               */
1240             this.name = name;
1241             setComparator(comparator);
1242         }
1243 
1244         @Override
1245         public Comment comment(String text) {
1246             Comment sl = new MComment.MSingleLineComment(vm, text);
1247             comment = sl;
1248             return sl;
1249         }
1250 
1251         @Override
1252         public String getLabel() {
1253             return label;
1254         }
1255 
1256         @Override
1257         public boolean isAbruptCompletionStatement() {
1258             return false;
1259         }
1260 
1261         @Override
1262         public MLocalClass setLabel(String label) {
1263             this.label = label;
1264             return this;
1265         }
1266 
1267         @Override
1268         public CodeWriter toCode(CodeWriter out) {
1269             super.toCode(out);
1270 
1271             out.write(";");
1272 
1273             return out;
1274         }
1275 
1276         @Override
1277         public void visit(ReplacingVisitor visitor) {
1278             super.visit(visitor);
1279             // skip parent that would be an endless loop
1280         }
1281     }
1282 
1283     /**
1284      * MEMBER DECLARATION
1285      */
1286     abstract static class MMember extends MDeclaration implements Member {
1287 
1288         String name;
1289 
1290         AccessType access = Access.PACKAGE;
1291 
1292         boolean isFinal;
1293 
1294         boolean isStatic;
1295 
1296         List<Annotation> annotations = new ArrayList<>();
1297 
1298         MMember(MVM vm) {
1299             super(vm);
1300         }
1301 
1302         @Override
1303         public MMember addAnnotation(Annotation annotation) {
1304             annotations.add(annotation);
1305             return this;
1306         }
1307 
1308         @Override
1309         public Annotation addAnnotation(String text) {
1310             Annotation x = new MAnnotation(vm, text);
1311             annotations.add(x);
1312             return x;
1313         }
1314 
1315         @Override
1316         public AccessType getAccess() {
1317             return access;
1318         }
1319 
1320         @Override
1321         public List<Annotation> getAnnotations() {
1322             return ListTypeSelector.select(annotations, Annotation.class);
1323         }
1324 
1325         @Override
1326         public String getName() {
1327             return name;
1328         }
1329 
1330         @Override
1331         public boolean isFinal() {
1332             return isFinal;
1333         }
1334 
1335         @Override
1336         public MMember isFinal(boolean value) {
1337             isFinal = value;
1338             return this;
1339         }
1340 
1341         @Override
1342         public boolean isStatic() {
1343             return isStatic;
1344         }
1345 
1346         @Override
1347         public MMember isStatic(boolean value) {
1348             isStatic = value;
1349             return this;
1350         }
1351 
1352         @Override
1353         public MMember setAccess(AccessType access) {
1354             this.access = access;
1355             return this;
1356         }
1357 
1358         @Override
1359         public MMember setName(String name) {
1360             this.name = name;
1361             return this;
1362         }
1363 
1364         @Override
1365         public CodeWriter toCode(CodeWriter out) {
1366             out.ensureNewLine().newLine();
1367 
1368             if (comment != null && comment.getType() != Comment.TRAILING) {
1369                 out.write(comment);
1370             }
1371 
1372             if (!annotations.isEmpty()) {
1373                 out.ensureNewLine();
1374                 for (Annotation annotation : getAnnotations()) {
1375                     out.write(annotation);
1376                     out.newLine();
1377                 }
1378             }
1379             out.ensureNewLine();
1380 
1381             return out;
1382         }
1383 
1384         @Override
1385         public void visit(ReplacingVisitor visitor) {
1386             super.visit(visitor);
1387             VisitorUtils.visit(annotations, this, visitor);
1388         }
1389 
1390         abstract List<? extends Codeable> codeableList();
1391 
1392         void writeBlock(CodeWriter out, BlockStyle style) {
1393             style.toCode(out, codeableList(), comment);
1394         }
1395     }
1396 
1397     /**
1398      * METHOD DECLARATION
1399      */
1400     abstract static class MMethod extends BlockDeclaration implements Method {
1401 
1402         boolean isAbstract;
1403 
1404         List<FormalParameter> parameters = new ArrayList<>();
1405 
1406         List<String> throwz = new ArrayList<>();
1407 
1408         Type type;
1409 
1410         MMethod(MVM vm, Type type, String name) {
1411             super(vm);
1412             this.type = type;
1413             this.name = name;
1414         }
1415 
1416         @Override
1417         public FormalParameter addParameter(Class type, String name) {
1418             return addParameter(vm.newType(type), name);
1419         }
1420 
1421         @Override
1422         public FormalParameter addParameter(Type type, String name) {
1423             FormalParameter x = new MFormalParameter(vm, type, name);
1424             parameters.add(x);
1425             return x;
1426         }
1427 
1428         @Override
1429         public MMethod addThrows(String name) {
1430             throwz.add(name);
1431             return this;
1432         }
1433 
1434         @Override
1435         public List<FormalParameter> getParameters() {
1436             return ListTypeSelector.select(parameters, FormalParameter.class);
1437         }
1438 
1439         @Override
1440         public List<String> getThrows() {
1441             return ListTypeSelector.select(throwz, String.class);
1442         }
1443 
1444         @Override
1445         public Type getType() {
1446             return type;
1447         }
1448 
1449         @Override
1450         public boolean isAbstract() {
1451             return isAbstract;
1452         }
1453 
1454         @Override
1455         public MMethod isAbstract(boolean isAbstract) {
1456             this.isAbstract = isAbstract;
1457             return this;
1458         }
1459 
1460         @Override
1461         public MMethod setType(Type type) {
1462             this.type = type;
1463             return this;
1464         }
1465 
1466         @Override
1467         public void visit(ReplacingVisitor visitor) {
1468             super.visit(visitor);
1469             VisitorUtils.visit(parameters, this, visitor);
1470             type = VisitorUtils.visit(type, this, visitor);
1471         }
1472     }
1473 
1474     /**
1475      * PACKAGE DECLARATION
1476      */
1477     static class MNamespace extends MDeclaration implements Namespace {
1478 
1479         String name;
1480 
1481         MNamespace(MVM vm, String name) {
1482             super(vm);
1483             this.name = name;
1484         }
1485 
1486         @Override
1487         public String getName() {
1488             return name;
1489         }
1490 
1491         @Override
1492         public MNamespace setName(String name) {
1493             this.name = name;
1494             return this;
1495         }
1496 
1497         @Override
1498         public CodeWriter toCode(CodeWriter out) {
1499             out.ensureNewLine();
1500             super.toCode(out);
1501             out.write("package ").write(name).write(';').newLine();
1502             return out;
1503         }
1504 
1505     }
1506 
1507     /**
1508      * PACKAGE CLASS DECLARATION
1509      */
1510     static class MPackageClass extends MClassDeclaration implements PackageClass {
1511 
1512         MPackageClass(MVM vm, MCompilationUnit unit) {
1513             super(vm, unit);
1514         }
1515 
1516         @Override
1517         public MPackageClass addSerializable() {
1518             getUnit().addImport(Serializable.class.getName());
1519 
1520             addImplements(Serializable.class.getSimpleName());
1521 
1522             ClassField serialVersionUID = newField(vm.newType(Type.LONG), "serialVersionUID");
1523             serialVersionUID.setExpression(vm.newLong(1L))//
1524                     .isFinal(true)//
1525                     .isStatic(true)//
1526                     .setAccess(Access.PRIVATE);
1527             return this;
1528 
1529         }
1530     }
1531 
1532     /**
1533      * STATIC INITIALIZATION DECLARATION
1534      */
1535     static class MStaticInitializer extends BlockDeclaration implements StaticInitializer {
1536 
1537         MStaticInitializer(MVM vm) {
1538             super(vm);
1539         }
1540 
1541         @Override
1542         public CodeWriter toCode(CodeWriter out) {
1543             super.toCode(out);
1544 
1545             // write the class and name
1546             out.write("static");
1547             writeBlock(out, vm.getStyle("static-initializer"));
1548             return out;
1549         }
1550     }
1551 
1552     /**
1553      * MEMBER DECLARATION
1554      */
1555     abstract static class MTypeDeclaration extends MMember implements TypeDeclaration {
1556 
1557         final MCompilationUnit unit;
1558 
1559         List<Declaration> members;
1560 
1561         private Comparator<Member> comparator;
1562 
1563         MTypeDeclaration(MVM vm, MCompilationUnit unit) {
1564             super(vm);
1565             this.unit = unit;
1566             members = new ArrayList<>();
1567             this.comparator = new MemberComparator();
1568         }
1569 
1570         @Override
1571         public List<Member> getMembers() {
1572             return ListTypeSelector.select(members, Member.class);
1573         }
1574 
1575         @Override
1576         public CompilationUnit getUnit() {
1577             return unit;
1578         }
1579 
1580         @Override
1581         public void visit(ReplacingVisitor visitor) {
1582             super.visit(visitor);
1583             VisitorUtils.visit(members, this, visitor);
1584         }
1585 
1586         public Comparator<Member> getComparator() {
1587             return this.comparator;
1588         }
1589 
1590         public void setComparator(final Comparator comparator) {
1591             this.comparator = comparator;
1592             this.visit(new ReplacingVisitor() {
1593                 @Override
1594                 public Codeable visitReplace(Codeable current, Codeable parent) {
1595                     if (current!= null) {
1596                         if (current instanceof TypeDeclaration) {
1597                             ((TypeDeclaration) current).setComparator(comparator);
1598                         }
1599                         current.visit(this);
1600                     }
1601                     return current;
1602                 }
1603             });
1604         }
1605 
1606         @Override
1607         List<Member> codeableList() {
1608             return sort(getMembers());
1609         }
1610 
1611         /**
1612          * Note: this method does not take inner classes or fancy class names as
1613          * of yet.
1614          */
1615         String getClassfile() {
1616             // make the fully qualified class name
1617             StringBuilder className = new StringBuilder();
1618 
1619             // append to the filepath if exists (should, but
1620             // not required).
1621             if (unit.namespace != null) {
1622                 // fetch the package name
1623                 String pkg = unit.namespace.getName();
1624                 // make sure the package name exists
1625                 if (pkg != null) {
1626                     // append the package name
1627                     className.append(pkg).append('.');
1628                 }
1629             }
1630 
1631             // add the name
1632             className.append(getName());
1633 
1634             // done
1635             return className.toString();
1636         }
1637 
1638         List<Member> sort(List<Member> list) {
1639             List<Member> result = new ArrayList<>(list);
1640             Collections.sort(result, getComparator());
1641             return result;
1642         }
1643 
1644         @Override
1645         public boolean removeMember(Member member) {
1646             return members.remove(member);
1647         }
1648     }
1649 
1650     MDeclaration(MVM vm) {
1651         super(vm);
1652     }
1653 
1654     private static void writeTypeParametersAndThrow(String name, Type type, List<FormalParameter> parameters, List<String> throwz, CodeWriter out) {
1655         // write the class and name
1656         if (type != null) {
1657             out.write(type).space();
1658         }
1659         out.write(name).write('(');
1660 
1661         for (int i = 0; i < parameters.size(); i++) {
1662             if (i > 0) {
1663                 out.write(", ");
1664             }
1665             out.write(parameters.get(i));
1666         }
1667 
1668         out.write(')');
1669 
1670         if (!throwz.isEmpty()) {
1671             out.space().write("throws ");
1672             for (int i = 0; i < throwz.size(); i++) {
1673                 if (i > 0) {
1674                     out.write(", ");
1675                 }
1676                 out.write(throwz.get(i));
1677             }
1678         }
1679     }
1680 
1681     public DocumentationComment javadoc(String text) {
1682         comment = new MComment.MDocumentationComment(vm, text);
1683         return (DocumentationComment) comment;
1684     }
1685 }