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.impl.util.ListTypeSelector;
42  import net.sourceforge.jenesis4java.impl.util.VisitorUtils;
43  
44  import java.util.ArrayList;
45  import java.util.Comparator;
46  import java.util.List;
47  
48  import static net.sourceforge.jenesis4java.Style.METHOD_INVOCATION_ON_NEW_LINE;
49  
50  /**
51   * Standard {@code Expression} implementations.
52   */
53  public abstract class MExpression extends MVM.MCodeable implements Expression {
54  
55      private boolean forcedNewlineAfterExpression = false;
56  
57      /**
58       * ACCESSOR EXPRESSION
59       */
60      static class MAccessor extends MExpression implements Accessor {
61  
62          String name;
63  
64          String qual;
65  
66          Expression qualExpression;
67  
68          Expression nameExpression;
69  
70          public MAccessor(MVM vm, String qual, String name) {
71              super(vm);
72              this.qual = qual;
73              qualExpression = null;
74              this.name = name;
75              nameExpression = null;
76          }
77  
78          MAccessor(MVM vm) {
79              super(vm);
80          }
81  
82          MAccessor(MVM vm, Expression qual, String name) {
83              super(vm);
84              this.qual = null;
85              qualExpression = qual;
86              this.name = name;
87          }
88  
89          MAccessor(MVM vm, Expression qual, Expression name) {
90              super(vm);
91              this.qual = null;
92              qualExpression = qual;
93              nameExpression = name;
94          }
95  
96          @Override
97          public String getName() {
98              return name;
99          }
100 
101         @Override
102         public Expression getQualExpression() {
103             return qualExpression;
104         }
105 
106         @Override
107         public String getQualifier() {
108             return qual;
109         }
110 
111         @Override
112         public Type getType() {
113             return null;
114         }
115 
116         @Override
117         public MAccessor setName(String name) {
118             this.name = name;
119             return this;
120         }
121 
122         @Override
123         public MAccessor setQualifier(String qual) {
124             this.qual = qual;
125             return this;
126         }
127 
128         @Override
129         public CodeWriter toCode2(CodeWriter out) {
130             super.toCode2(out);
131             if (qual != null) {
132                 out.write(qual).write('.');
133             } else if (qualExpression != null) {
134                 out.write(qualExpression).write('.');
135             }
136             if (name != null) {
137                 out.write(name);
138             } else if (nameExpression != null) {
139                 out.write(nameExpression).write('.');
140             }
141             return out;
142         }
143 
144         @Override
145         public void visit(ReplacingVisitor visitor) {
146             super.visit(visitor);
147             qualExpression = VisitorUtils.visit(qualExpression, this, visitor);
148             nameExpression = VisitorUtils.visit(nameExpression, this, visitor);
149         }
150     }
151 
152     /**
153      * ARRAY ACCESS EXPRESSION
154      */
155     static class MArrayAccess extends MAccessor implements ArrayAccess {
156 
157         List<Expression> dimensions = new ArrayList<>();
158 
159         MArrayAccess(MVM vm, Expression qual, String name) {
160             super(vm, qual, name);
161         }
162 
163         MArrayAccess(MVM vm, String qual, String name) {
164             super(vm, qual, name);
165         }
166 
167         @Override
168         public ArrayAccess addDim(Expression expr) {
169             dimensions.add(expr);
170             return this;
171         }
172 
173         @Override
174         public List<Expression> getDims() {
175             return ListTypeSelector.select(dimensions);
176         }
177 
178         @Override
179         public CodeWriter toCode2(CodeWriter out) {
180             super.toCode2(out);
181 
182             for (Expression dimension : dimensions) {
183                 out.write('[').write(dimension).write(']');
184             }
185 
186             return out;
187         }
188 
189         @Override
190         public void visit(ReplacingVisitor visitor) {
191             super.visit(visitor);
192             VisitorUtils.visit(dimensions, this, visitor);
193         }
194     }
195 
196     /**
197      * ARRAY INITIALIZATION EXPRESSION
198      */
199     static class MArrayInitializer extends MExpression implements ArrayInitializer {
200 
201         Object o;
202 
203         MArrayInitializer(MVM vm, Object o) {
204             super(vm);
205             this.o = o;
206         }
207 
208         @Override
209         public Object getArgs() {
210             return o;
211         }
212 
213         @Override
214         public Type getType() {
215             return null;
216         }
217 
218         @Override
219         public MArrayInitializer setArgs(Object o) {
220             this.o = o;
221             return this;
222         }
223 
224         @Override
225         public CodeWriter toCode2(CodeWriter out) {
226             super.toCode2(out);
227 
228             // normal case
229             if (o == null) {
230                 out.write("{}");
231             } else if (o instanceof Object[]) {
232                 Object[] ao = (Object[]) o;
233                 if (ao.length == 0) {
234                     out.write("{}");
235                 } else {
236                     writeElements(ao, out);
237                 }
238 
239                 // the exceptional case where the primary object
240                 // is NOT an array, and we simply write the sole
241                 // element
242             } else if (o instanceof Expression) {
243                 out.write("{ ").write(o).write(" }");
244             }
245 
246             return out;
247         }
248 
249         @Override
250         public void visit(ReplacingVisitor visitor) {
251             super.visit(visitor);
252             o = VisitorUtils.visit(o, this, visitor);
253         }
254 
255         void writeElement(Object o, CodeWriter out, boolean isNotFirst) {
256             if (o instanceof Object[]) {
257                 if (isNotFirst) {
258                     out.write(", ");
259                 }
260                 writeElements((Object[]) o, out);
261             } else if (o instanceof Expression) {
262                 if (isNotFirst) {
263                     out.write(", ");
264                 }
265                 out.write(o);
266             }
267         }
268 
269         void writeElements(Object[] ao, CodeWriter out) {
270             out.write('{');
271 
272             // write each element, sending true if this
273             // is not the first element we are writing
274             for (int i = 0; i < ao.length; i++) {
275                 writeElement(ao[i], out, i > 0);
276             }
277 
278             out.write('}');
279         }
280     }
281 
282     /**
283      * ASSIGNMENT EXPRESSION
284      */
285     static class MAssign extends MBinary implements Assign {
286 
287         MAssign(MVM vm, int type, Variable l, Expression r) {
288             super(vm, type, l, r);
289         }
290 
291         @Override
292         public Variable getVariable() {
293             return (Variable) super.getLValue();
294         }
295 
296         @Override
297         public MAssign setVariable(Variable v) {
298             super.setLValue(v);
299             return this;
300         }
301 
302         @Override
303         public CodeWriter toCode2(CodeWriter out) {
304             switch (type) {
305                 case Assign.S:
306                     out.write(l).write(" = ").write(r);
307                     break;
308                 case Binary.BINARY_AND:
309                     out.write(l).write(" &= ").write(r);
310                     break;
311                 case Binary.BINARY_OR:
312                     out.write(l).write(" |= ").write(r);
313                     break;
314                 case Binary.XOR:
315                     out.write(l).write(" ^= ").write(r);
316                     break;
317                 case Binary.LEFT:
318                     out.write(l).write(" <<= ").write(r);
319                     break;
320                 case Binary.RIGHT:
321                     out.write(l).write(" >>= ").write(r);
322                     break;
323                 case Binary.UNSIGNED:
324                     out.write(l).write(" >>>= ").write(r);
325                     break;
326                 case Binary.SUB:
327                     out.write(l).write(" -= ").write(r);
328                     break;
329                 case Binary.MUL:
330                     out.write(l).write(" *= ").write(r);
331                     break;
332                 case Binary.DIV:
333                     out.write(l).write(" /= ").write(r);
334                     break;
335                 case Binary.MOD:
336                     out.write(l).write(" %= ").write(r);
337                     break;
338                 case Binary.ADD:
339                 case Binary.CAT:
340                     out.write(l).write(" += ").write(r);
341                     break;
342                 default:
343                     throw new RuntimeException("Please use a constant from the Assign interface when making new Assignment expressions.");
344             }
345             return out;
346         }
347 
348         @Override
349         public int type() {
350             return type;
351         }
352     }
353 
354     /**
355      * BINARY EXPRESSION
356      */
357     static class MBinary extends MExpression implements Binary {
358 
359         final int type;
360 
361         Expression l;
362 
363         Expression r;
364 
365         MBinary(MVM vm, int type, Expression l, Expression r) {
366             super(vm);
367             this.type = type;
368             this.l = l;
369             this.r = r;
370         }
371 
372         @Override
373         public Expression getLValue() {
374             return l;
375         }
376 
377         @Override
378         public Expression getRValue() {
379             return r;
380         }
381 
382         @Override
383         public Type getType() {
384             return l.getType();
385         }
386 
387         @Override
388         public MBinary setLValue(Expression l) {
389             this.l = l;
390             return this;
391         }
392 
393         @Override
394         public MBinary setRValue(Expression r) {
395             this.r = r;
396             return this;
397         }
398 
399         @Override
400         public CodeWriter toCode2(CodeWriter out) {
401             super.toCode2(out);
402 
403             switch (type) {
404                 case Binary.AND:
405                     out.write(l).write(" && ").write(r);
406                     break;
407                 case Binary.OR:
408                     out.write(l).write(" || ").write(r);
409                     break;
410                 case Binary.BINARY_AND:
411                     out.write(l).write(" & ").write(r);
412                     break;
413                 case Binary.BINARY_OR:
414                     out.write(l).write(" | ").write(r);
415                     break;
416                 case Binary.XOR:
417                     out.write(l).write(" ^ ").write(r);
418                     break;
419                 case Binary.LEFT:
420                     out.write(l).write(" << ").write(r);
421                     break;
422                 case Binary.RIGHT:
423                     out.write(l).write(" >> ").write(r);
424                     break;
425                 case Binary.UNSIGNED:
426                     out.write(l).write(" >>> ").write(r);
427                     break;
428                 case Binary.SUB:
429                     out.write(l).write(" - ").write(r);
430                     break;
431                 case Binary.MUL:
432                     out.write(l).write(" * ").write(r);
433                     break;
434                 case Binary.DIV:
435                     out.write(l).write(" / ").write(r);
436                     break;
437                 case Binary.MOD:
438                     out.write(l).write(" % ").write(r);
439                     break;
440                 case Binary.EQUAL_TO:
441                     out.write(l).write(" == ").write(r);
442                     break;
443                 case Binary.NOT_EQUAL:
444                     out.write(l).write(" != ").write(r);
445                     break;
446                 case Binary.GREATER:
447                     out.write(l).write(" > ").write(r);
448                     break;
449                 case Binary.GREATER_EQUAL:
450                     out.write(l).write(" >= ").write(r);
451                     break;
452                 case Binary.LESS:
453                     out.write(l).write(" < ").write(r);
454                     break;
455                 case Binary.LESS_EQUAL:
456                     out.write(l).write(" <= ").write(r);
457                     break;
458                 case Binary.INSTANCE_OF:
459                     out.write(l).write(" instanceof ").write(r);
460                     break;
461                 case Binary.ASSIGN:
462                     out.write(l).write(" = ").write(r);
463                     break;
464                 case Binary.ADD:
465                 case Binary.CAT:
466                     out.write(l).write(" + ").write(r);
467                     break;
468                 default:
469                     throw new RuntimeException("Please use a constant from the Binary interface when making new binary expressions.");
470             }
471             return out;
472         }
473 
474         @Override
475         public int type() {
476             return type;
477         }
478 
479         @Override
480         public void visit(ReplacingVisitor visitor) {
481             super.visit(visitor);
482             l = VisitorUtils.visit(l, this, visitor);
483             r = VisitorUtils.visit(r, this, visitor);
484         }
485     }
486 
487     /**
488      * BLANK EXPRESSION
489      */
490     static class MBlank extends MExpression implements Blank {
491 
492         MBlank(MVM vm) {
493             super(vm);
494         }
495 
496         @Override
497         public Type getType() {
498             return null;
499         }
500 
501         @Override
502         public CodeWriter toCode2(CodeWriter out) {
503             return out;
504         }
505     }
506 
507     /**
508      * CAST EXPRESSION
509      */
510     static class MCast extends MExpression implements Cast {
511 
512         Type type;
513 
514         Expression val;
515 
516         MCast(MVM vm, Type type, Expression val) {
517             super(vm);
518             this.type = type;
519             this.val = val;
520         }
521 
522         @Override
523         public Expression getExpression() {
524             return val;
525         }
526 
527         @Override
528         public Type getType() {
529             return type;
530         }
531 
532         @Override
533         public MCast setExpression(Expression val) {
534             this.val = val;
535             return this;
536         }
537 
538         @Override
539         public CodeWriter toCode2(CodeWriter out) {
540             super.toCode2(out);
541             if (type == null) {
542                 out.write('(').write(val).write(')');
543             } else {
544                 out.write('(').write('(').write(type).write(')').write(val).write(')');
545             }
546             return out;
547         }
548 
549         @Override
550         public void visit(ReplacingVisitor visitor) {
551             super.visit(visitor);
552             type = VisitorUtils.visit(type, this, visitor);
553             val = VisitorUtils.visit(val, this, visitor);
554         }
555     }
556 
557     /**
558      * FIELD ACCESS EXPRESSION
559      */
560     static class MFieldAccess extends MAccessor implements FieldAccess {
561 
562         MFieldAccess(MVM vm, Expression qual, String name) {
563             super(vm, qual, name);
564         }
565 
566         MFieldAccess(MVM vm, String qual, String name) {
567             super(vm, qual, name);
568         }
569     }
570 
571     /**
572      * FREEFORM EXPRESSION
573      */
574     static class MFreeform extends MExpression implements Freeform {
575 
576         // the actual writer
577         java.io.StringWriter buf;
578 
579         java.io.PrintWriter out;
580 
581         int colNo;
582 
583         int lineNo;
584 
585         int indentNo;
586 
587         boolean isLineNew;
588 
589         MFreeform(MVM vm) {
590             super(vm);
591             init();
592         }
593 
594         MFreeform(MVM vm, String code) {
595             this(vm);
596             write(code);
597         }
598 
599         @Override
600         public Freeform dedentLine() {
601             indentNo--;
602             newLine();
603             return this;
604         }
605 
606         @Override
607         public String getCode() {
608             return buf.toString();
609         }
610 
611         public int getColumnNumber() {
612             return colNo;
613         }
614 
615         @Override
616         public int getIndentNumber() {
617             return indentNo;
618         }
619 
620         public int getLineNumber() {
621             return lineNo;
622         }
623 
624         @Override
625         public Type getType() {
626             return null;
627         }
628 
629         @Override
630         public Freeform indentLine() {
631             indentNo++;
632             newLine();
633             return this;
634         }
635 
636         @Override
637         public boolean isLineNew() {
638             return isLineNew;
639         }
640 
641         @Override
642         public Freeform newLine() {
643             out.println();
644             writeIndent();
645             colNo = 0;
646             lineNo++;
647             isLineNew = true;
648             return this;
649         }
650 
651         @Override
652         public Freeform resetLine() {
653             indentNo = 0;
654             newLine();
655             return this;
656         }
657 
658         @Override
659         public MFreeform setCode(String code) {
660             init();
661             buf.write(code);
662             return this;
663         }
664 
665         @Override
666         public Freeform space() {
667             out.print(' ');
668             colNo++;
669             isLineNew = false;
670             return this;
671         }
672 
673         @Override
674         public CodeWriter toCode2(CodeWriter out) {
675             super.toCode2(out);
676             out.write(buf.toString());
677             return out;
678         }
679 
680         @Override
681         public Freeform write(boolean b) {
682             // print it
683             out.print(b);
684             // add if 4:'true' or 5:'false'
685             colNo += b ? 4 : 5;
686             isLineNew = false;
687             return this;
688         }
689 
690         @Override
691         public Freeform write(char c) {
692             // print the char
693             out.print(c);
694             // add one
695             colNo++;
696             isLineNew = false;
697             return this;
698         }
699 
700         @Override
701         public Freeform write(char[] chars) {
702 
703             if (chars != null) {
704                 out.print(chars);
705                 // add
706                 colNo += chars.length;
707                 isLineNew = false;
708             }
709             return this;
710         }
711 
712         @Override
713         public Freeform write(double d) {
714             out.print(d);
715             colNo += Double.toString(d).length();
716             isLineNew = false;
717             return this;
718         }
719 
720         @Override
721         public Freeform write(float f) {
722             out.print(f);
723             colNo += Float.toString(f).length();
724             isLineNew = false;
725             return this;
726         }
727 
728         @Override
729         public Freeform write(int i) {
730             out.print(i);
731             colNo += Integer.toString(i).length();
732             isLineNew = false;
733             return this;
734         }
735 
736         @Override
737         public Freeform write(Object o) {
738             if (o != null) {
739                 out.print(o);
740                 colNo += o.toString().length();
741                 isLineNew = false;
742             }
743             return this;
744         }
745 
746         @Override
747         public Freeform write(Object[] ao) {
748             if (ao != null) {
749                 for (Object element : ao) {
750                     write(element);
751                 }
752             }
753             return this;
754         }
755 
756         @Override
757         public Freeform write(String s) {
758             if (s != null) {
759                 out.print(s);
760                 colNo += s.length();
761                 isLineNew = false;
762             }
763 
764             return this;
765         }
766 
767         private void writeIndent() {
768             int n = indentNo;
769             while (n-- > 0) {
770                 out.print('\t');
771             }
772         }
773 
774         void init() {
775             buf = new java.io.StringWriter();
776             out = new java.io.PrintWriter(buf);
777         }
778     }
779 
780     /**
781      * METHOD INVOCATION EXPRESSION
782      */
783     static class MInvoke extends MNary implements Invoke {
784 
785         MInvoke(MVM vm, Expression qual, String name) {
786             super(vm);
787             this.qual = null;
788             qualExpression = qual;
789             this.name = name;
790         }
791 
792         MInvoke(MVM vm, String qual, String name) {
793             super(vm);
794             this.qual = qual;
795             qualExpression = null;
796             this.name = name;
797         }
798 
799         @Override
800         public Invoke addArg(boolean value) {
801             return addArg(value ? vm.newTrue() : vm.newFalse());
802         }
803 
804         @Override
805         public Invoke addArg(double value) {
806             return addArg(vm.newDouble(value));
807         }
808 
809         @Override
810         public Invoke addArg(Expression arg) {
811             ve.add(arg);
812             return this;
813         }
814 
815         @Override
816         public Invoke addArg(float value) {
817             return addArg(vm.newFloat(value));
818         }
819 
820         @Override
821         public Invoke addArg(int value) {
822             return addArg(vm.newInt(value));
823         }
824 
825         @Override
826         public Invoke addArg(long value) {
827             return addArg(vm.newLong(value));
828         }
829 
830         @Override
831         public Invoke addArg(String value) {
832             return addArg(vm.newString(value));
833         }
834 
835         @Override
836         public Invoke addVariableArg(String variableName) {
837             return addArg(vm.newVar(variableName));
838         }
839 
840         @Override
841         public void removeArg(int index) {
842             if (index < 0 || index >= ve.size()) {
843                 throw new IllegalArgumentException("Cannot remove argument with index " + index);
844             }
845 
846             ve.remove(index);
847         }
848 
849         @Override
850         public CodeWriter toCode2(CodeWriter out) {
851             if (isActive(METHOD_INVOCATION_ON_NEW_LINE) && qualExpression instanceof MExpression) {
852                 // force newline on previous expression
853                 // this is effectively a null check
854                 ((MExpression) qualExpression).forceNewLineAfterExpression();
855             }
856 
857             super.toCode2(out);
858             out.write('(');
859             for (int i = 0; i < ve.size(); i++) {
860                 if (i > 0) {
861                     out.write(", ");
862                 }
863                 out.write(ve.get(i));
864             }
865             out.write(')');
866 
867             return out;
868         }
869 
870         @Override
871         public boolean isActive(Style style) {
872             if (style == METHOD_INVOCATION_ON_NEW_LINE) {
873                 // the style is always stored on the innermost Invoke
874                 return super.isActive(style) //
875                         || qualExpression != null && qualExpression.isActive(style);
876             } else {
877                 return super.isActive(style);
878             }
879         }
880 
881         @Override
882         public Invoke applyStyle(Style style) {
883             if (qualExpression instanceof MInvoke) {
884                 // apply style eagerly at the bottom-most invoke node
885                 qualExpression.applyStyle(style);
886 
887             } else {
888                 super.applyStyle(style);
889             }
890             return this;
891         }
892     }
893 
894     /**
895      * NARY EXPRESSION
896      */
897     abstract static class MNary extends MAccessor {
898 
899         List<Expression> ve = new ArrayList<>();
900 
901         MNary(MVM vm) {
902             super(vm);
903         }
904 
905         public List<Expression> getArgs() {
906             return ListTypeSelector.select(ve, Expression.class);
907         }
908 
909         @Override
910         public void visit(ReplacingVisitor visitor) {
911             super.visit(visitor);
912             VisitorUtils.visit(ve, this, visitor);
913         }
914     }
915 
916     /**
917      * ANONYMOUS CLASS CREATION EXPRESSION
918      */
919     static class MNewAnonymousClass extends MDeclaration.MClassDeclaration implements NewAnonymousClass {
920 
921         Type type;
922 
923         List<Expression> ve = new ArrayList<>();
924 
925         String qual;
926 
927         MNewAnonymousClass(MVM vm, Type type, Comparator comparator) {
928             super(vm, null);
929             this.type = type;
930             setComparator(comparator);
931         }
932 
933         @Override
934         public NewClass addArg(Expression arg) {
935             ve.add(arg);
936             return this;
937         }
938 
939         @Override
940         public List<Expression> getArgs() {
941             return ListTypeSelector.select(ve, Expression.class);
942         }
943 
944         @Override
945         public String getQualifier() {
946             return qual;
947         }
948 
949         @Override
950         public Type getType() {
951             return type;
952         }
953 
954         @Override
955         public MNewAnonymousClass setQualifier(String qual) {
956             this.qual = qual;
957             return this;
958         }
959 
960         @Override
961         public MNewAnonymousClass setType(Type type) {
962             this.type = type;
963             return this;
964         }
965 
966         @Override
967         public CodeWriter toCode(CodeWriter out) {
968             out.write("new ").write(type).write('(');
969 
970             for (int i = 0; i < ve.size(); i++) {
971                 if (i > 0) {
972                     out.write(", ");
973                 }
974                 out.write(ve.get(i));
975             }
976             out.write(')');
977 
978             writeBlock(out, vm.getStyle("anonymous-class"));
979 
980             return out;
981         }
982 
983         @Override
984         public void visit(ReplacingVisitor visitor) {
985             super.visit(visitor);
986             type = VisitorUtils.visit(type, this, visitor);
987             VisitorUtils.visit(ve, this, visitor);
988         }
989     }
990 
991     /**
992      * ARRAY INSTANCE CREATION EXPRESSION
993      */
994     static class MNewArray extends MNary implements NewArray {
995 
996         Type type;
997 
998         List<Expression> dimensions;
999 
1000         ArrayInitializer ai;
1001 
1002         MNewArray(MVM vm, Type type) {
1003             super(vm);
1004             this.type = type;
1005             dimensions = new ArrayList<>();
1006         }
1007 
1008         @Override
1009         public NewArray addDim() {
1010             dimensions.add(new MBlank(vm));
1011             return this;
1012         }
1013 
1014         @Override
1015         public NewArray addDim(Expression e) {
1016             dimensions.add(e);
1017             return this;
1018         }
1019 
1020         @Override
1021         public List<Expression> getDims() {
1022             return ListTypeSelector.select(dimensions, Expression.class);
1023         }
1024 
1025         @Override
1026         public ArrayInitializer getInitializer() {
1027             return ai;
1028         }
1029 
1030         @Override
1031         public Type getType() {
1032             return type;
1033         }
1034 
1035         @Override
1036         public MNewArray setInitializer(ArrayInitializer ai) {
1037             this.ai = ai;
1038             return this;
1039         }
1040 
1041         @Override
1042         public MNewArray setType(Type type) {
1043             this.type = type;
1044             return this;
1045         }
1046 
1047         @Override
1048         public CodeWriter toCode2(CodeWriter out) {
1049             out.write("new ").write(type);
1050             for (Expression dim : dimensions) {
1051                 out.write('[').write(dim).write(']');
1052             }
1053             out.write(ai);
1054             return out;
1055         }
1056 
1057         @Override
1058         public void visit(ReplacingVisitor visitor) {
1059             super.visit(visitor);
1060             type = VisitorUtils.visit(type, this, visitor);
1061             VisitorUtils.visit(dimensions, this, visitor);
1062             ai = VisitorUtils.visit(ai, this, visitor);
1063         }
1064     }
1065 
1066     /**
1067      * CLASS INSTANCE CREATION EXPRESSION
1068      */
1069     static class MNewClass extends MNary implements NewClass {
1070 
1071         Type type;
1072 
1073         MNewClass(MVM vm, Type type) {
1074             super(vm);
1075             this.type = type;
1076         }
1077 
1078         @Override
1079         public NewClass addArg(Expression arg) {
1080             ve.add(arg);
1081             return this;
1082         }
1083 
1084         @Override
1085         public Type getType() {
1086             return type;
1087         }
1088 
1089         @Override
1090         public MNewClass setQualifier(String qual) {
1091             super.setQualifier(qual);
1092             return this;
1093         }
1094 
1095         @Override
1096         public MNewClass setType(Type type) {
1097             this.type = type;
1098             return this;
1099         }
1100 
1101         @Override
1102         public CodeWriter toCode2(CodeWriter out) {
1103             super.toCode2(out);
1104 
1105             out.write("new ").write(type).write('(');
1106             for (int i = 0; i < ve.size(); i++) {
1107                 if (i > 0) {
1108                     out.write(", ");
1109                 }
1110                 out.write(ve.get(i));
1111             }
1112             out.write(')');
1113 
1114             return out;
1115         }
1116 
1117         @Override
1118         public void visit(ReplacingVisitor visitor) {
1119             super.visit(visitor);
1120             type = VisitorUtils.visit(type, this, visitor);
1121         }
1122     }
1123 
1124     /**
1125      * TERNARY EXPRESSION
1126      */
1127     static class MTernary extends MExpression implements Ternary {
1128 
1129         final int type;
1130 
1131         Expression one;
1132 
1133         Expression two;
1134 
1135         Expression three;
1136 
1137         MTernary(MVM vm, int type, Expression one, Expression two, Expression three) {
1138             super(vm);
1139             this.type = type;
1140             this.one = one;
1141             this.two = two;
1142             this.three = three;
1143         }
1144 
1145         @Override
1146         public Type getType() {
1147             return two.getType();
1148         }
1149 
1150         @Override
1151         public Expression getValue1() {
1152             return one;
1153         }
1154 
1155         @Override
1156         public Expression getValue2() {
1157             return two;
1158         }
1159 
1160         @Override
1161         public Expression getValue3() {
1162             return three;
1163         }
1164 
1165         @Override
1166         public MTernary setValue1(Expression one) {
1167             this.one = one;
1168             return this;
1169         }
1170 
1171         @Override
1172         public MTernary setValue2(Expression two) {
1173             this.two = two;
1174             return this;
1175         }
1176 
1177         @Override
1178         public MTernary setValue3(Expression three) {
1179             this.three = three;
1180             return this;
1181         }
1182 
1183         @Override
1184         public CodeWriter toCode2(CodeWriter out) {
1185             super.toCode2(out);
1186             out.write(one).write(" ? ").write(two).write(" : ").write(three);
1187             return out;
1188         }
1189 
1190         @Override
1191         public int type() {
1192             return type;
1193         }
1194 
1195         @Override
1196         public void visit(ReplacingVisitor visitor) {
1197             super.visit(visitor);
1198             one = VisitorUtils.visit(one, this, visitor);
1199             two = VisitorUtils.visit(two, this, visitor);
1200             three = VisitorUtils.visit(three, this, visitor);
1201         }
1202     }
1203 
1204     /**
1205      * VARIABLE EXPRESSION
1206      */
1207     static class MTypeVariable extends MExpression implements Variable {
1208 
1209         Type type;
1210 
1211         MTypeVariable(MVM vm) {
1212             super(vm);
1213         }
1214 
1215         MTypeVariable(MVM vm, Type type) {
1216             super(vm);
1217             this.type = type;
1218         }
1219 
1220         @Override
1221         public String getName() {
1222             return type.toString();
1223         }
1224 
1225         @Override
1226         public Type getType() {
1227             return type;
1228         }
1229 
1230         @Override
1231         public Variable setName(String typeName) {
1232             type = vm.newType(typeName);
1233             return this;
1234         }
1235 
1236         public MTypeVariable setName(Type type) {
1237             this.type = type;
1238             return this;
1239         }
1240 
1241         @Override
1242         public CodeWriter toCode2(CodeWriter out) {
1243             super.toCode2(out);
1244             out.write(type);
1245             return out;
1246         }
1247 
1248         @Override
1249         public void visit(ReplacingVisitor visitor) {
1250             super.visit(visitor);
1251             type = VisitorUtils.visit(type, this, visitor);
1252         }
1253     }
1254 
1255     /**
1256      * UNARY EXPRESSION
1257      */
1258     static class MUnary extends MExpression implements Unary {
1259 
1260         final int type;
1261 
1262         Expression val;
1263 
1264         MUnary(MVM vm, int type, Expression val) {
1265             super(vm);
1266             this.type = type;
1267             this.val = val;
1268         }
1269 
1270         @Override
1271         public Type getType() {
1272             return val.getType();
1273         }
1274 
1275         @Override
1276         public Expression getValue() {
1277             return val;
1278         }
1279 
1280         @Override
1281         public MUnary setValue(Expression val) {
1282             this.val = val;
1283             return this;
1284         }
1285 
1286         @Override
1287         public CodeWriter toCode2(CodeWriter out) {
1288             super.toCode2(out);
1289 
1290             switch (type) {
1291                 case Unary.GROUP:
1292                     out.write('(').write(val).write(')');
1293                     break;
1294                 case Unary.NOT:
1295                     out.write('!').write(val);
1296                     break;
1297                 case Unary.BITWISE_NOT:
1298                     out.write('~').write(val);
1299                     break;
1300                 case Unary.POS:
1301                     out.write('+').write(val);
1302                     break;
1303                 case Unary.NEG:
1304                     out.write('-').write(val);
1305                     break;
1306                 case Unary.PREFIX_INCREMENT:
1307                     out.write("++").write(val);
1308                     break;
1309                 case Unary.POST_INCREMENT:
1310                     out.write(val).write("++");
1311                     break;
1312                 case Unary.PREFIX_DECREMENT:
1313                     out.write("--").write(val);
1314                     break;
1315                 case Unary.POST_DECREMENT:
1316                     out.write(val).write("--");
1317                     break;
1318                 default:
1319                     throw new RuntimeException("Please use a constant from the Unary interface when making new unary expressions.");
1320             }
1321 
1322             return out;
1323         }
1324 
1325         @Override
1326         public int type() {
1327             return type;
1328         }
1329 
1330         @Override
1331         public void visit(ReplacingVisitor visitor) {
1332             super.visit(visitor);
1333             val = VisitorUtils.visit(val, this, visitor);
1334         }
1335     }
1336 
1337     /**
1338      * VARIABLE EXPRESSION
1339      */
1340     static class MVariable extends MExpression implements Variable {
1341 
1342         String name;
1343 
1344         MVariable(MVM vm, String name) {
1345             super(vm);
1346             this.name = name;
1347         }
1348 
1349         @Override
1350         public String getName() {
1351             return name;
1352         }
1353 
1354         @Override
1355         public Type getType() {
1356             return null;
1357         }
1358 
1359         @Override
1360         public MVariable setName(String name) {
1361             this.name = name;
1362             return this;
1363         }
1364 
1365         @Override
1366         public CodeWriter toCode2(CodeWriter out) {
1367             super.toCode2(out);
1368             out.write(name);
1369             return out;
1370         }
1371     }
1372 
1373     static class MThis extends MVariable implements This {
1374 
1375         MThis(MVM vm) {
1376             super(vm, "this");
1377         }
1378 
1379         public MThis(MVM mvm, ClassType typeOfOuterClass) {
1380             super(mvm, typeOfOuterClass.getName() + ".this");
1381         }
1382 
1383         @Override
1384         public MVariable setName(String ignored) {
1385             throw new UnsupportedOperationException("Not allowed for this.");
1386         }
1387     }
1388 
1389     static class MSuper extends MVariable implements Super {
1390 
1391         MSuper(MVM vm) {
1392             super(vm, "super");
1393         }
1394 
1395         @Override
1396         public MVariable setName(String ignored) {
1397             throw new UnsupportedOperationException("Not allowed for super.");
1398         }
1399     }
1400 
1401     MExpression(MVM vm) {
1402         super(vm);
1403     }
1404 
1405     public CodeWriter toCode2(CodeWriter out) {
1406         return out;
1407     }
1408 
1409     @Override
1410     public final CodeWriter toCode(CodeWriter out) {
1411         toCode2(out);
1412         if (forcedNewlineAfterExpression) {
1413             out.write(" //").newLine();
1414         }
1415         return out;
1416     }
1417 
1418     private void forceNewLineAfterExpression() {
1419         this.forcedNewlineAfterExpression = true;
1420     }
1421 }