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  import java.util.ArrayList;
40  import java.util.Comparator;
41  import java.util.LinkedList;
42  import java.util.List;
43  
44  import net.sourceforge.jenesis4java.*;
45  import net.sourceforge.jenesis4java.impl.util.*;
46  
47  /**
48   * Standard {@code Statement} implementations.
49   */
50  abstract class MStatement extends MVM.MCodeable implements Statement {
51  
52      /**
53       * BLOCK STATEMENT
54       */
55      static class BlockStatement extends MStatement implements Block {
56  
57          List<Statement> vs;
58  
59          BlockStatement(MVM vm) {
60              super(vm);
61              vs = new ArrayList<>();
62          }
63  
64          @Override
65          public List<Statement> getStatements() {
66              return ListTypeSelector.select(vs);
67          }
68  
69          @Override
70          public Statement insertStatement(int index, Expression expression) {
71              ExpressionStatement expressionStatement = new MStatement.MExpressionStatement((MVM) vm(), expression);
72              vs.add(index, expressionStatement);
73              return expressionStatement;
74          }
75  
76          @Override
77          public void insertStatement(int index, Statement statement) {
78              vs.add(index, statement);
79          }
80  
81          @Override
82          public boolean isBlockWithAbruptCompletion() {
83              return BlockUtil.isBlockWithAbruptCompletion(getStatements());
84          }
85  
86          @Override
87          public Break newBreak() {
88              Break x = new MBreak(vm);
89              vs.add(x);
90              return x;
91          }
92  
93          @Override
94          public Continue newContinue() {
95              Continue x = new MContinue(vm);
96              vs.add(x);
97              return x;
98          }
99  
100         @Override
101         public Let newDeclarationLet(Type type) {
102             Let x = new MStatement.MLet(vm, type);
103             int index = 0;
104             while (index < vs.size() && vs.get(index) instanceof Let) {
105                 index++;
106             }
107             vs.add(index, x);
108             return x;
109         }
110 
111         @Override
112         public DoWhile newDoWhile(Expression predicate) {
113             DoWhile x = new MDoWhile(vm, predicate);
114             vs.add(x);
115             return x;
116         }
117 
118         @Override
119         public Empty newEmpty() {
120             Empty x = new MEmpty(vm);
121             vs.add(x);
122             return x;
123         }
124 
125         @Override
126         public For newFor() {
127             For x = new MFor(vm);
128             vs.add(x);
129             return x;
130         }
131 
132         @Override
133         public If newIf(Expression predicate) {
134             If x = new MIf(vm, predicate);
135             vs.add(x);
136             return x;
137         }
138 
139         @Override
140         public Let newLet(Type type) {
141             Let x = new MLet(vm, type);
142             vs.add(x);
143             return x;
144         }
145 
146         @Override
147         public LocalBlock newLocalBlock() {
148             LocalBlock x = new MLocalBlock(vm);
149             vs.add(x);
150             return x;
151         }
152 
153         @Override
154         public LocalClass newLocalClass(String name) {
155             return newLocalClass(name, new MemberComparator());
156         }
157 
158         @Override
159         public LocalClass newLocalClass(String name, Comparator comparator) {
160             LocalClass x = new MDeclaration.MLocalClass(vm, name, comparator);
161             vs.add(x);
162             return x;
163         }
164 
165         @Override
166         public Return newReturn() {
167             Return x = new MReturn(vm);
168             vs.add(x);
169             return x;
170         }
171 
172         @Override
173         public ExpressionStatement newStmt(Expression expr) {
174             ExpressionStatement x = new MExpressionStatement(vm, expr);
175             vs.add(x);
176             return x;
177         }
178 
179         @Override
180         public Switch newSwitch(Expression integer) {
181             Switch x = new MSwitch(vm, integer);
182             vs.add(x);
183             return x;
184         }
185 
186         @Override
187         public Synchronized newSynchronized(Expression mutex) {
188             Synchronized x = new MSynchronized(vm, mutex);
189             vs.add(x);
190             return x;
191         }
192 
193         @Override
194         public Throw newThrow(Expression throwable) {
195             Throw x = new MThrow(vm, throwable);
196             vs.add(x);
197             return x;
198         }
199 
200         @Override
201         public Try newTry() {
202             Try x = new MTry(vm);
203             vs.add(x);
204             return x;
205         }
206 
207         @Override
208         public While newWhile(Expression predicate) {
209             While x = new MWhile(vm, predicate);
210             vs.add(x);
211             return x;
212         }
213 
214         @Override
215         public void removeStmt(Statement statement) {
216             if (vs != null) {
217                 vs.remove(statement);
218             }
219         }
220 
221         @Override
222         public void visit(ReplacingVisitor visitor) {
223             super.visit(visitor);
224             VisitorUtils.visit(vs, this, visitor);
225         }
226 
227         void writeBlock(CodeWriter out, BlockStyle style) {
228             // write it
229             style.toCode(out, getStatements(), comment);
230         }
231     }
232 
233     /**
234      * GOTO STATMENTS
235      */
236     abstract static class GotoStatement extends MStatement {
237 
238         final String kwd;
239 
240         String target;
241 
242         GotoStatement(MVM vm, String kwd) {
243             super(vm);
244             this.kwd = kwd;
245         }
246 
247         public String getGoto() {
248             return target;
249         }
250 
251         public GotoStatement setGoto(String target) {
252             this.target = target;
253             return this;
254         }
255 
256         @Override
257         public CodeWriter toCode(CodeWriter out) {
258             super.toCode(out);
259 
260             out.write(kwd);
261 
262             if (target != null) {
263                 out.space().write(target);
264             }
265 
266             out.write(';');
267             appendTrailingComment(out);
268             return out;
269         }
270     }
271 
272     /**
273      * BREAK STATEMENT
274      */
275     static class MBreak extends GotoStatement implements Break {
276 
277         MBreak(MVM vm) {
278             super(vm, "break");
279         }
280 
281         @Override
282         public MBreak setGoto(String target) {
283             super.setGoto(target);
284             return this;
285         }
286     }
287 
288     /**
289      * CASE STATEMENT
290      */
291     static class MCase extends MConditionalStatement implements Case {
292 
293         MCase(MVM vm, Expression expr) {
294             super(vm);
295             setPredicate(expr);
296         }
297 
298         @Override
299         public Expression getConstant() {
300             return getPredicate();
301         }
302 
303         @Override
304         public MCase setConstant(Expression expr) {
305             setPredicate(expr);
306             return this;
307         }
308 
309         @Override
310         public CodeWriter toCode(CodeWriter out) {
311             super.toCode(out);
312             out.write("case ").write(e).write(':');
313             appendTrailingComment(out);
314 
315             out.indentLine();
316             out.write(getStatements());
317             out.dedentLine();
318             return out;
319         }
320     }
321 
322     /**
323      * CONDITIONAL STATEMENT
324      */
325     abstract static class MConditionalStatement extends BlockStatement implements ConditionalStatement {
326 
327         Expression e;
328 
329         public MConditionalStatement(MVM vm) {
330             super(vm);
331         }
332 
333         public MConditionalStatement(MVM vm, Expression e) {
334             super(vm);
335             this.e = e;
336         }
337 
338         @Override
339         public Expression getPredicate() {
340             return e;
341         }
342 
343         @Override
344         public MConditionalStatement setPredicate(Expression e) {
345             this.e = e;
346             return this;
347         }
348 
349         @Override
350         public void visit(ReplacingVisitor visitor) {
351             super.visit(visitor);
352             e = VisitorUtils.visit(e, this, visitor);
353         }
354     }
355 
356     /**
357      * CONTINUE STATEMENT
358      */
359     static class MContinue extends GotoStatement implements Continue {
360 
361         MContinue(MVM vm) {
362             super(vm, "continue");
363         }
364 
365         @Override
366         public MContinue setGoto(String target) {
367             super.setGoto(target);
368             return this;
369         }
370     }
371 
372     /**
373      * DEFAULT STATEMENT
374      */
375     static class MDefault extends BlockStatement implements Default {
376 
377         MDefault(MVM vm) {
378             super(vm);
379         }
380 
381         @Override
382         public CodeWriter toCode(CodeWriter out) {
383             super.toCode(out);
384             out.write("default:");
385             writeBlock(out, vm.getStyle("default"));
386             return out;
387         }
388     }
389 
390     /**
391      * DO WHILE STATEMENT
392      */
393     static class MDoWhile extends MConditionalStatement implements DoWhile {
394 
395         public MDoWhile(MVM vm, Expression e) {
396             super(vm, e);
397         }
398 
399         @Override
400         public CodeWriter toCode(CodeWriter out) {
401             super.toCode(out);
402             out.write("do");
403             writeBlock(out, vm.getStyle("do"));
404             out.write("while (").write(e).write(");");
405             return out;
406         }
407     }
408 
409     /**
410      * ELSE STATEMENT
411      */
412     static class MElse extends BlockStatement implements Else {
413 
414         MElse(MVM vm) {
415             super(vm);
416         }
417 
418         @Override
419         public CodeWriter toCode(CodeWriter out) {
420             appendCommentsAndLabel(out);
421             if (!out.isLineNew()) {
422                 out.space();
423             }
424             out.write("else");
425             writeBlock(out, vm.getStyle("else"));
426             return out;
427         }
428     }
429 
430     /**
431      * ELSE IF STATEMENT
432      */
433     static class MElseIf extends MConditionalStatement implements ElseIf {
434 
435         MElseIf(MVM vm, Expression e) {
436             super(vm, e);
437         }
438 
439         @Override
440         public CodeWriter toCode(CodeWriter out) {
441             appendCommentsAndLabel(out);
442             if (!out.isLineNew()) {
443                 out.space();
444             }
445             out.write("else if (").write(e).write(')');
446             writeBlock(out, vm.getStyle("else-if"));
447             return out;
448         }
449     }
450 
451     /**
452      * EMPTY STATEMENT
453      */
454     static class MEmpty extends MStatement implements Empty {
455 
456         MEmpty(MVM vm) {
457             super(vm);
458         }
459 
460         @Override
461         public CodeWriter toCode(CodeWriter out) {
462             super.toCode(out);
463             out.write(';');
464             appendTrailingComment(out);
465             return out;
466         }
467     }
468 
469     /**
470      * EXPRESSIONABLE STATEMENT
471      */
472     abstract static class MExpressionableStatement extends MStatement {
473 
474         Expression e;
475 
476         MExpressionableStatement(MVM vm) {
477             super(vm);
478         }
479 
480         public Expression getExpression() {
481             return e;
482         }
483 
484         public MExpressionableStatement setExpression(Expression e) {
485             this.e = e;
486             return this;
487         }
488 
489         @Override
490         public void visit(ReplacingVisitor visitor) {
491             super.visit(visitor);
492             e = VisitorUtils.visit(e, this, visitor);
493         }
494     }
495 
496     /**
497      * EXPRESSION STATEMENT
498      */
499     static class MExpressionStatement extends MExpressionableStatement implements ExpressionStatement {
500 
501         MExpressionStatement(MVM vm, Expression e) {
502             super(vm);
503             setExpression(e);
504         }
505 
506         @Override
507         public MExpressionStatement setExpression(Expression e) {
508             super.setExpression(e);
509             return this;
510         }
511 
512         @Override
513         public CodeWriter toCode(CodeWriter out) {
514             super.toCode(out);
515             out.write(getExpression()).write(';');
516             appendTrailingComment(out);
517             return out;
518         }
519     }
520 
521     /**
522      * CATCH STATEMENT
523      */
524     static class MFinally extends BlockStatement implements Finally {
525 
526         MFinally(MVM vm) {
527             super(vm);
528         }
529 
530         @Override
531         public CodeWriter toCode(CodeWriter out) {
532             appendCommentsAndLabel(out);
533             if (!out.isLineNew()) {
534                 out.space();
535             }
536             out.write("finally");
537             writeBlock(out, vm.getStyle("finally"));
538             return out;
539         }
540     }
541 
542     /**
543      * FOR STATEMENT
544      */
545     static class MFor extends MConditionalStatement implements For {
546 
547         List<Codeable> initExpressions = new ArrayList<>();
548 
549         List<Codeable> vu = new ArrayList<>();
550 
551         MFor(MVM vm) {
552             super(vm);
553         }
554 
555         @Override
556         public MFor addInit(Expression e) {
557             initExpressions.add(e);
558             return this;
559         }
560 
561         @Override
562         public MFor addUpdate(Expression e) {
563             vu.add(e);
564             return this;
565         }
566 
567         @Override
568         public List<Codeable> getInits() {
569             return ListTypeSelector.select(initExpressions);
570         }
571 
572         @Override
573         public List<Codeable> getUpdates() {
574             return ListTypeSelector.select(vu);
575         }
576 
577         @Override
578         public Let setInit(Type type) {
579             Let let = new MForInitLet(vm, type);
580             initExpressions.add(let);
581             return let;
582         }
583 
584         @Override
585         public CodeWriter toCode(CodeWriter out) {
586             super.toCode(out);
587             out.write("for (");
588             write(initExpressions, out);
589             out.write(';');
590             if (e != null) {
591                 out.space().write(e);
592             }
593             out.write(';');
594             if (!vu.isEmpty()) {
595                 out.space();
596                 write(vu, out);
597             }
598             out.write(')');
599             writeBlock(out, vm.getStyle("for"));
600             return out;
601         }
602 
603         @Override
604         public void visit(ReplacingVisitor visitor) {
605             super.visit(visitor);
606             VisitorUtils.visit(initExpressions, this, visitor);
607             VisitorUtils.visit(vu, this, visitor);
608         }
609 
610         private void write(List<Codeable> v, CodeWriter out) {
611             for (int i = 0; i < v.size(); i++) {
612                 if (i > 0) {
613                     out.write(", ");
614                 }
615                 out.write(v.get(i));
616             }
617         }
618     }
619 
620     /**
621      * LET STATEMENT
622      */
623     static class MForInitLet extends MLet {
624 
625         MForInitLet(MVM vm, Type type) {
626             super(vm, type);
627         }
628 
629         @Override
630         public CodeWriter toCode(CodeWriter out) {
631             // queue up the comment
632             out.queue(comment);
633 
634             if (isFinal) {
635                 out.write("final").space();
636             }
637 
638             out.write(type).space();
639 
640             for (int i = 0; i < v.size(); i++) {
641                 if (i > 0) {
642                     out.write(',').space();
643                 }
644                 out.write(v.get(i));
645             }
646 
647             return out;
648         }
649     }
650 
651     /**
652      * IF STATEMENT
653      */
654     static class MIf extends MConditionalStatement implements If {
655 
656         List<ElseIf> elseIfs = new ArrayList<>();
657 
658         Else _else;
659 
660         MIf(MVM vm, Expression e) {
661             super(vm, e);
662         }
663 
664         @Override
665         public Else getElse() {
666             if (_else == null) {
667                 _else = new MElse(vm);
668             }
669             return _else;
670         }
671 
672         @Override
673         public List<ElseIf> getElseIfs() {
674             return ListTypeSelector.select(elseIfs);
675         }
676 
677         @Override
678         public ElseIf newElseIf(Expression e) {
679             ElseIf ei = new MElseIf(vm, e);
680             elseIfs.add(ei);
681             return ei;
682         }
683 
684         @Override
685         public CodeWriter toCode(CodeWriter out) {
686             super.toCode(out);
687             out.write("if (").write(e).write(')');
688             writeBlock(out, vm.getStyle("if"));
689             for (ElseIf elseIf : elseIfs) {
690                 out.write(elseIf);
691             }
692             if (_else != null && !_else.getStatements().isEmpty()) {
693                 out.write(_else);
694             }
695             return out;
696         }
697 
698         @Override
699         public void visit(ReplacingVisitor visitor) {
700             super.visit(visitor);
701             VisitorUtils.visit(elseIfs, this, visitor);
702             _else = VisitorUtils.visit(_else, this, visitor);
703         }
704     }
705 
706     /**
707      * LET STATEMENT
708      */
709     static class MLet extends MExpressionableStatement implements Let {
710 
711         Type type;
712 
713         boolean isFinal;
714 
715         List<Assign> v = new ArrayList<>();
716 
717         MLet(MVM vm, Type type) {
718             super(vm);
719             this.type = type;
720         }
721 
722         @Override
723         public MLet addAssign(Assign assign) {
724             v.add(assign);
725             return this;
726         }
727 
728         @Override
729         public MLet addAssign(String name, Expression expr) {
730             v.add(new MExpression.MAssign(vm, Assign.S, new MExpression.MVariable(vm, name), expr));
731             return this;
732         }
733 
734         @Override
735         public List<Assign> getAssigns() {
736             return ListTypeSelector.select(v);
737         }
738 
739         @Override
740         public Type getType() {
741             return type;
742         }
743 
744         @Override
745         public boolean isFinal() {
746             return isFinal;
747         }
748 
749         @Override
750         public MLet isFinal(boolean value) {
751             isFinal = value;
752             return this;
753         }
754 
755         @Override
756         public MLet setType(Type type) {
757             this.type = type;
758             return this;
759         }
760 
761         @Override
762         public CodeWriter toCode(CodeWriter out) {
763             super.toCode(out);
764 
765             if (isFinal) {
766                 out.write("final").space();
767             }
768 
769             out.write(type).space();
770 
771             for (int i = 0; i < v.size(); i++) {
772                 if (i > 0) {
773                     out.write(',').space();
774                 }
775                 out.write(v.get(i));
776             }
777 
778             out.write(';');
779 
780             appendTrailingComment(out);
781 
782             return out;
783         }
784 
785         @Override
786         public void visit(ReplacingVisitor visitor) {
787             super.visit(visitor);
788             type = VisitorUtils.visit(type, this, visitor);
789             VisitorUtils.visit(v, this, visitor);
790         }
791     }
792 
793     /**
794      * LOCAL BLOCK STATEMENT k
795      */
796     static class MLocalBlock extends BlockStatement implements LocalBlock {
797 
798         public MLocalBlock(MVM vm) {
799             super(vm);
800         }
801 
802         @Override
803         public CodeWriter toCode(CodeWriter out) {
804             super.toCode(out);
805             writeBlock(out, vm.getStyle("local-class"));
806             return out;
807         }
808     }
809 
810     /**
811      * RETURN STATEMENT
812      */
813     static class MReturn extends MExpressionableStatement implements Return {
814 
815         MReturn(MVM vm) {
816             super(vm);
817         }
818 
819         @Override
820         public MReturn setExpression(Expression e) {
821             super.setExpression(e);
822             return this;
823         }
824 
825         @Override
826         public CodeWriter toCode(CodeWriter out) {
827             super.toCode(out);
828 
829             out.write("return");
830 
831             if (e != null) {
832                 out.space().write(e);
833             }
834 
835             out.write(';');
836 
837             appendTrailingComment(out);
838 
839             return out;
840         }
841     }
842 
843     /**
844      * SWITCH STATEMENT
845      */
846     static class MSwitch extends MConditionalStatement implements Switch {
847 
848         boolean triggered;
849 
850         Default d;
851 
852         MSwitch(MVM vm, Expression e) {
853             super(vm, e);
854         }
855 
856         @Override
857         public List<Case> getCases() {
858             return ListTypeSelector.select(vs, Case.class);
859         }
860 
861         @Override
862         public Default getDefault() {
863             if (d == null) {
864                 d = new MDefault(vm);
865             }
866             return d;
867         }
868 
869         @Override
870         public Case newCase(Expression constant) {
871             Case c = new MCase(vm, constant);
872             vs.add(c);
873             return c;
874         }
875 
876         @Override
877         public CodeWriter toCode(CodeWriter out) {
878             if (!triggered) {
879                 // add in the default if its not null
880                 if (d != null) {
881                     vs.add(d);
882                 }
883                 triggered = true;
884             }
885 
886             super.toCode(out);
887             out.write("switch (").write(e).write(')');
888             writeBlock(out, vm.getStyle("switch"));
889             return out;
890         }
891 
892         @Override
893         public void visit(ReplacingVisitor visitor) {
894             super.visit(visitor);
895             d = VisitorUtils.visit(d, this, visitor);
896         }
897     }
898 
899     /**
900      * SYNCHRONIZED STATEMENT
901      */
902     static class MSynchronized extends BlockStatement implements Synchronized {
903 
904         Expression mutex;
905 
906         MSynchronized(MVM vm, Expression mutex) {
907             super(vm);
908             this.mutex = mutex;
909         }
910 
911         @Override
912         public Expression getMutex() {
913             return mutex;
914         }
915 
916         @Override
917         public MSynchronized setMutex(Expression mutex) {
918             this.mutex = mutex;
919             return this;
920         }
921 
922         @Override
923         public CodeWriter toCode(CodeWriter out) {
924             super.toCode(out);
925             out.write("synchronized ").write('(').write(mutex).write(')');
926             writeBlock(out, vm.getStyle("synchronized"));
927             return out;
928         }
929 
930         @Override
931         public void visit(ReplacingVisitor visitor) {
932             super.visit(visitor);
933             mutex = VisitorUtils.visit(mutex, this, visitor);
934         }
935     }
936 
937     static class MConstructorForwarding extends MStatement implements ConstructorForwarding {
938 
939         private final Constructor.ForwardingTarget target;
940 
941         private final List<Expression> arguments = new ArrayList<>();
942 
943         private String qualifier;
944 
945         MConstructorForwarding(MVM vm, Constructor.ForwardingTarget target) {
946             super(vm);
947             this.target = target;
948         }
949 
950         @Override
951         public CodeWriter toCode(CodeWriter out) {
952             super.toCode(out);
953 
954             if (qualifier != null) {
955                 out.write(qualifier).write('.');
956             }
957 
958             if (target == Constructor.ForwardingTarget.THIS) {
959                 out.write("this(");
960             } else if (target == Constructor.ForwardingTarget.SUPER){
961                 out.write("super(");
962             }
963 
964             String separator = "";
965             for (Expression argument : arguments) {
966                 out.write(separator);
967                 out.write(argument);
968                 separator = ", ";
969             }
970 
971             out.write(");");
972             appendTrailingComment(out);
973             return out;
974         }
975 
976         @Override
977         public ConstructorForwarding addArg(boolean value) {
978             return addArg(value ? vm.newTrue() : vm.newFalse());
979         }
980 
981         @Override
982         public ConstructorForwarding addArg(double value) {
983             return addArg(vm.newDouble(value));
984         }
985 
986         @Override
987         public ConstructorForwarding addArg(Expression arg) {
988             arguments.add(arg);
989             return this;
990         }
991 
992         @Override
993         public ConstructorForwarding addArg(float value) {
994             return addArg(vm.newFloat(value));
995         }
996 
997         @Override
998         public ConstructorForwarding addArg(int value) {
999             return addArg(vm.newInt(value));
1000         }
1001 
1002         @Override
1003         public ConstructorForwarding addArg(long value) {
1004             return addArg(vm.newLong(value));
1005         }
1006 
1007         @Override
1008         public ConstructorForwarding addArg(String value) {
1009             return addArg(vm.newString(value));
1010         }
1011 
1012         @Override
1013         public ConstructorForwarding addVariableArg(String variableName) {
1014             return addArg(vm.newVar(variableName));
1015         }
1016 
1017         @Override
1018         public List<Expression> getArgs() {
1019             return ListTypeSelector.select(arguments, Expression.class);
1020         }
1021 
1022         @Override
1023         public void removeArg(int index) {
1024             if (index < 0 || index >= arguments.size()) {
1025                 throw new IllegalArgumentException("Cannot remove argument with index " + index);
1026             }
1027 
1028             arguments.remove(index);
1029         }
1030 
1031         @Override
1032         public void visit(ReplacingVisitor visitor) {
1033             super.visit(visitor);
1034             VisitorUtils.visit(arguments, this, visitor);
1035         }
1036 
1037         @Override
1038         public Constructor.ForwardingTarget getTarget() {
1039             return target;
1040         }
1041 
1042         @Override
1043         public void setQualifier(String qualifier) {
1044             this.qualifier = qualifier;
1045         }
1046 
1047         @Override
1048         public Expression getQualifier() {
1049             if (qualifier != null) {
1050                 return vm.newClassLiteral(qualifier);
1051             } else {
1052                 return null;
1053             }
1054         }
1055     }
1056 
1057     /**
1058      * THROW STATEMENT
1059      */
1060     static class MThrow extends MStatement implements Throw {
1061 
1062         Expression e;
1063 
1064         MThrow(MVM vm, Expression e) {
1065             super(vm);
1066             this.e = e;
1067         }
1068 
1069         @Override
1070         public Expression getThrowable() {
1071             return e;
1072         }
1073 
1074         @Override
1075         public MThrow setThrowable(Expression e) {
1076             this.e = e;
1077             return this;
1078         }
1079 
1080         @Override
1081         public CodeWriter toCode(CodeWriter out) {
1082             super.toCode(out);
1083 
1084             out.write("throw ").write(e).write(';');
1085             appendTrailingComment(out);
1086 
1087             return out;
1088         }
1089 
1090         @Override
1091         public void visit(ReplacingVisitor visitor) {
1092             super.visit(visitor);
1093             e = VisitorUtils.visit(e, this, visitor);
1094         }
1095     }
1096 
1097     /**
1098      * WHILE STATEMENT
1099      */
1100     static class MWhile extends MConditionalStatement implements While {
1101 
1102         public MWhile(MVM vm, Expression e) {
1103             super(vm, e);
1104         }
1105 
1106         @Override
1107         public CodeWriter toCode(CodeWriter out) {
1108             super.toCode(out);
1109             out.write("while (").write(e).write(')');
1110             writeBlock(out, vm.getStyle("while"));
1111             return out;
1112         }
1113     }
1114 
1115     private String label;
1116 
1117     MStatement(MVM vm) {
1118         super(vm);
1119     }
1120 
1121     @Override
1122     public Comment comment(String text) {
1123         comment = new MComment.MSingleLineComment(vm, text);
1124         return comment;
1125     }
1126 
1127     @Override
1128     public String getLabel() {
1129         return label;
1130     }
1131 
1132     @Override
1133     public boolean isAbruptCompletionStatement() {
1134         return this instanceof Return || //
1135                 this instanceof Break || //
1136                 this instanceof Throw || //
1137                 this instanceof Continue;
1138     }
1139 
1140     @Override
1141     public MStatement setLabel(String label) {
1142         this.label = label;
1143         return this;
1144     }
1145 
1146     private List<Comment> collectComments() {
1147         final List<Comment> collectedComments = new LinkedList<>();
1148 
1149         visit(new ConditionalVisitor() {
1150 
1151             @Override
1152             public boolean visit(Codeable current, Codeable parent) {
1153                 if (current instanceof Expression) {
1154                     Expression expression = (Expression) current;
1155                     if (expression.getComment() != null) {
1156                         collectedComments.add(expression.getComment());
1157                     }
1158                     return true;
1159 
1160                 } else if (current instanceof MForInitLet) {
1161                     // special case where we need to traverse a stmt
1162                     MExpressionableStatement expression = (MExpressionableStatement) current;
1163                     if (expression.getComment() != null) {
1164                         collectedComments.add(expression.getComment());
1165                     }
1166                     return true;
1167 
1168                 } else {
1169                     return false;
1170                 }
1171             }
1172         });
1173 
1174         return collectedComments;
1175     }
1176 
1177     @Override
1178     public CodeWriter toCode(CodeWriter out) {
1179         // always start a statement on a new line
1180         out.ensureNewLine();
1181 
1182         appendCommentsAndLabel(out);
1183         return out;
1184     }
1185 
1186     void appendCommentsAndLabel(CodeWriter out) {
1187         // write the comment of the statement
1188         if (comment != null && comment.getType() != Comment.TRAILING) {
1189             out.write(comment);
1190             out.ensureNewLine();
1191         }
1192 
1193         // write the comment of inner expressions
1194         List<Comment> commentsFromInnerExpressions = collectComments();
1195         for (Comment expressionComment : commentsFromInnerExpressions) {
1196             if (expressionComment.getType() != Comment.TRAILING) {
1197                 out.write(expressionComment);
1198 
1199                 out.ensureNewLine();
1200             }
1201         }
1202 
1203         // and the label, if there is one.
1204         if (label != null) {
1205             out.ensureNewLine();
1206             out.write(label).write(':').space();
1207         }
1208     }
1209 
1210     CodeWriter appendTrailingComment(CodeWriter out) {
1211         if (comment != null && comment.getType() == Comment.TRAILING) {
1212             out.write(comment);
1213         }
1214 
1215         List<Comment> commentsFromInnerExpressions = collectComments();
1216         for (Comment expressionComment : commentsFromInnerExpressions) {
1217             if (expressionComment.getType() == Comment.TRAILING) {
1218                 out.write(expressionComment);
1219             }
1220         }
1221 
1222         return out;
1223     }
1224 }