1 /*
  2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 package jdk.test.lib.jittester.visitors;
 25 
 26 import java.util.List;
 27 import java.util.Locale;
 28 import java.util.Objects;
 29 import java.util.stream.Collectors;
 30 import jdk.test.lib.jittester.BinaryOperator;
 31 import jdk.test.lib.jittester.Block;
 32 import jdk.test.lib.jittester.Break;
 33 import jdk.test.lib.jittester.CastOperator;
 34 import jdk.test.lib.jittester.CatchBlock;
 35 import jdk.test.lib.jittester.Continue;
 36 import jdk.test.lib.jittester.Declaration;
 37 import jdk.test.lib.jittester.IRNode;
 38 import jdk.test.lib.jittester.If;
 39 import jdk.test.lib.jittester.Initialization;
 40 import jdk.test.lib.jittester.Literal;
 41 import jdk.test.lib.jittester.LocalVariable;
 42 import jdk.test.lib.jittester.NonStaticMemberVariable;
 43 import jdk.test.lib.jittester.Nothing;
 44 import jdk.test.lib.jittester.Operator;
 45 import jdk.test.lib.jittester.OperatorKind;
 46 import jdk.test.lib.jittester.PrintVariables;
 47 import jdk.test.lib.jittester.ProductionParams;
 48 import jdk.test.lib.jittester.Statement;
 49 import jdk.test.lib.jittester.StaticMemberVariable;
 50 import jdk.test.lib.jittester.Switch;
 51 import jdk.test.lib.jittester.Symbol;
 52 import jdk.test.lib.jittester.TernaryOperator;
 53 import jdk.test.lib.jittester.Throw;
 54 import jdk.test.lib.jittester.TryCatchBlock;
 55 import jdk.test.lib.jittester.Type;
 56 import jdk.test.lib.jittester.TypeList;
 57 import jdk.test.lib.jittester.UnaryOperator;
 58 import jdk.test.lib.jittester.VariableBase;
 59 import jdk.test.lib.jittester.VariableDeclaration;
 60 import jdk.test.lib.jittester.VariableDeclarationBlock;
 61 import jdk.test.lib.jittester.VariableInfo;
 62 import jdk.test.lib.jittester.arrays.ArrayCreation;
 63 import jdk.test.lib.jittester.arrays.ArrayElement;
 64 import jdk.test.lib.jittester.arrays.ArrayExtraction;
 65 import jdk.test.lib.jittester.classes.ClassDefinitionBlock;
 66 import jdk.test.lib.jittester.classes.Interface;
 67 import jdk.test.lib.jittester.classes.Klass;
 68 import jdk.test.lib.jittester.classes.MainKlass;
 69 import jdk.test.lib.jittester.functions.ArgumentDeclaration;
 70 import jdk.test.lib.jittester.functions.ConstructorDefinition;
 71 import jdk.test.lib.jittester.functions.ConstructorDefinitionBlock;
 72 import jdk.test.lib.jittester.functions.Function;
 73 import jdk.test.lib.jittester.functions.FunctionDeclaration;
 74 import jdk.test.lib.jittester.functions.FunctionDeclarationBlock;
 75 import jdk.test.lib.jittester.functions.FunctionDefinition;
 76 import jdk.test.lib.jittester.functions.FunctionDefinitionBlock;
 77 import jdk.test.lib.jittester.functions.FunctionInfo;
 78 import jdk.test.lib.jittester.functions.FunctionRedefinition;
 79 import jdk.test.lib.jittester.functions.FunctionRedefinitionBlock;
 80 import jdk.test.lib.jittester.functions.Return;
 81 import jdk.test.lib.jittester.functions.StaticConstructorDefinition;
 82 import jdk.test.lib.jittester.loops.CounterInitializer;
 83 import jdk.test.lib.jittester.loops.CounterManipulator;
 84 import jdk.test.lib.jittester.loops.DoWhile;
 85 import jdk.test.lib.jittester.loops.For;
 86 import jdk.test.lib.jittester.loops.Loop;
 87 import jdk.test.lib.jittester.loops.LoopingCondition;
 88 import jdk.test.lib.jittester.loops.While;
 89 import jdk.test.lib.jittester.types.TypeArray;
 90 import jdk.test.lib.jittester.types.TypeKlass;
 91 import jdk.test.lib.jittester.utils.FixedTrees;
 92 import jdk.test.lib.jittester.utils.PrintingUtils;
 93 
 94 public class JavaCodeVisitor implements Visitor<String> {
 95 
 96     public static String funcAttributes(FunctionInfo fi) {
 97         String attrs = attributes(fi);
 98         if (fi.isSynchronized()) {
 99             attrs += "synchronized ";
100         }
101         return attrs;
102     }
103 
104     public static String attributes(Symbol s) {
105         String attrs = "";
106         if (s.isPrivate()) {
107             attrs += "private ";
108         }
109         if (s.isProtected()) {
110             attrs += "protected ";
111         }
112         if (s.isPublic()) {
113             attrs += "public ";
114         }
115         if (s.isFinal()) {
116             attrs += "final ";
117         }
118         if (s.isStatic()) {
119             attrs += "static ";
120         }
121         return attrs;
122     }
123 
124     private String operatorToJaveCode(OperatorKind operationKind) {
125        switch (operationKind) {
126            case COMPOUND_ADD:
127                return  "+=";
128            case COMPOUND_SUB:
129                return "-=";
130            case COMPOUND_MUL:
131                return "*=";
132            case COMPOUND_DIV:
133                return "/=";
134            case COMPOUND_MOD:
135                return "%=";
136            case COMPOUND_AND:
137                return "&=";
138            case COMPOUND_OR:
139                return "|=";
140            case COMPOUND_XOR:
141                return "^=";
142            case COMPOUND_SHR:
143                return ">>=";
144            case COMPOUND_SHL:
145                return "<<=";
146            case COMPOUND_SAR:
147                return ">>>=";
148            case ASSIGN:
149                return "=";
150            case OR:
151                return "||";
152            case BIT_OR:
153                return "|";
154            case BIT_XOR:
155                return "^";
156            case AND:
157                return "&&";
158            case BIT_AND:
159                return "&";
160            case EQ:
161                return "==";
162            case NE:
163                return "!=";
164            case GT:
165                return ">";
166            case LT:
167                return "<";
168            case GE:
169                return ">=";
170            case LE:
171                return "<=";
172            case SHR:
173                return ">>";
174            case SHL:
175                return "<<";
176            case SAR:
177                return ">>>";
178            case ADD:
179            case STRADD:
180                return "+";
181            case SUB:
182                return "-";
183            case MUL:
184                return "*";
185            case DIV:
186                return "/";
187            case MOD:
188                return "%";
189            case NOT:
190                return "!";
191            case BIT_NOT:
192                return "~";
193            case UNARY_PLUS:
194                return "+";
195            case UNARY_MINUS:
196                return "-";
197            case PRE_DEC:
198            case POST_DEC:
199                return "--";
200            case PRE_INC:
201            case POST_INC:
202                return "++";
203            default:
204                throw new IllegalArgumentException("Unkown operator kind " + operationKind);
205        }
206     }
207 
208     private String expressionToJavaCode(Operator t, IRNode p, Operator.Order o) {
209         String result;
210         try {
211             if ((o == Operator.Order.LEFT && ((Operator) p).getPriority() < t.getPriority())
212                     || (o == Operator.Order.RIGHT && ((Operator) p).getPriority() <= t.getPriority())) {
213                 result = "(" + p.accept(this)+ ")";
214             } else {
215                 result = p.accept(this);
216             }
217         } catch (Exception e) {
218             result = p.accept(this);
219         }
220         return result;
221     }
222 
223     @Override
224     public String visit(ArgumentDeclaration node) {
225         VariableInfo vi = node.variableInfo;
226         return attributes(vi) + vi.type.accept(this) + " " + vi.name;
227     }
228 
229     @Override
230     public String visit(ArrayCreation node) {
231         Type arrayElemType = node.getArrayType().type;
232         String type = arrayElemType.accept(this);
233         String name = node.getVariable().getName();
234         StringBuilder code = new StringBuilder()
235                 .append(node.getVariable().accept(this))
236                 .append(";\n")
237                 .append(PrintingUtils.align(node.getParent().getLevel()))
238                 .append(name)
239                 .append(" = new ")
240                 .append(type);
241         code.append(node.getChildren().stream()
242                 .map(p -> p.accept(this))
243                 .collect(Collectors.joining("][", "[", "]")));
244         code.append(";\n");
245         if (!TypeList.isBuiltIn(arrayElemType)) {
246             code.append(PrintingUtils.align(node.getParent().getLevel()))
247                 .append("java.util.Arrays.fill(")
248                 .append(name)
249                 .append(", new ")
250                 .append(type)
251                 .append("());\n");
252         }
253         return code.toString();
254     }
255 
256     @Override
257     public String visit(ArrayElement node) {
258         IRNode array = node.getChild(0);
259         StringBuilder code = new StringBuilder();
260         if (array instanceof VariableBase || array instanceof Function) {
261             code.append(array.accept(this));
262         } else {
263             code.append("(")
264                 .append(array.accept(this))
265                 .append(")");
266         }
267         code.append(node.getChildren().stream()
268                 .skip(1)
269                 .map(c -> c.accept(this))
270                 .collect(Collectors.joining("][", "[", "]")));
271         return code.toString();
272     }
273 
274     @Override
275     public String visit(ArrayExtraction node) {
276         IRNode array = node.getChild(0);
277         StringBuilder code = new StringBuilder();
278         if (array instanceof VariableBase || array instanceof Function) {
279             code.append(array.accept(this));
280         } else {
281             code.append("(")
282                 .append(array.accept(this))
283                 .append(")");
284         }
285         code.append(node.getChildren().stream()
286                 .skip(1)
287                 .map(c -> c.accept(this))
288                 .collect(Collectors.joining("][", "[", "]")));
289         return code.toString();
290     }
291 
292     @Override
293     public String visit(BinaryOperator node) {
294         IRNode left = node.getChild(Operator.Order.LEFT.ordinal());
295         IRNode right = node.getChild(Operator.Order.RIGHT.ordinal());
296         if (left == null || right == null) {
297             return "null";
298         }
299         return expressionToJavaCode(node, left, Operator.Order.LEFT)
300                + " " + operatorToJaveCode(node.getOperationKind()) + " "
301                + expressionToJavaCode(node, right, Operator.Order.RIGHT);
302     }
303 
304     @Override
305     public String visit(Block node) {
306         StringBuilder code = new StringBuilder();
307         for (IRNode i : node.getChildren()) {
308             String s = i.accept(this);
309             if (!s.isEmpty()) {
310                 int level = node.getLevel();
311                 if (i instanceof Block) {
312                     code.append(PrintingUtils.align(level + 1))
313                         .append("{\n")
314                         .append(s)
315                         .append(PrintingUtils.align(level + 1))
316                         .append("}");
317                 } else {
318                     code.append(PrintingUtils.align(level + 1))
319                         .append(s);
320                 }
321                 code.append(addComplexityInfo(i));
322                 code.append("\n");
323             }
324         }
325         return code.toString();
326     }
327 
328     private String addComplexityInfo(IRNode node) {
329         if (ProductionParams.printComplexity.value()) {
330             return " /* " + node.complexity() + " */";
331         }
332         return "";
333     }
334 
335     @Override
336     public String visit(Break node) {
337         return "break;";
338     }
339 
340     @Override
341     public String visit(CastOperator node) {
342         return "(" + node.getResultType().accept(this)+ ")"
343                 + expressionToJavaCode(node, node.getChild(0), Operator.Order.LEFT);
344     }
345 
346     @Override
347     public String visit(ClassDefinitionBlock node) {
348         StringBuilder code = new StringBuilder();
349         for (IRNode i : node.getChildren()) {
350             code.append("\n")
351                 .append(PrintingUtils.align(node.getLevel()))
352                 .append(i.accept(this))
353                 .append("\n");
354         }
355 
356         return code.toString();
357     }
358 
359     @Override
360     public String visit(ConstructorDefinition node) {
361         String args = node.getChildren().stream()
362                 .skip(1)
363                 .map(c -> c.accept(this))
364                 .collect(Collectors.joining(", "));
365         IRNode body = node.getChild(0);
366         StringBuilder code = new StringBuilder();
367         code.append(funcAttributes(node.getFunctionInfo()))
368             .append(node.getFunctionInfo().name)
369             .append("(")
370             .append(args)
371             .append(")\n")
372             .append(PrintingUtils.align(node.getLevel() + 1))
373             .append("{\n")
374             .append(body != null ? body.accept(this) : "")
375             .append(PrintingUtils.align(node.getLevel() + 1))
376             .append("}");
377         return code.toString();
378     }
379 
380     @Override
381     public String visit(ConstructorDefinitionBlock node) {
382         StringBuilder code = new StringBuilder();
383         for (IRNode i : node.getChildren()) {
384             code.append("\n")
385                 .append(PrintingUtils.align(node.getLevel()))
386                 .append(i.accept(this))
387                 .append(addComplexityInfo(i))
388                 .append("\n");
389         }
390         return code.toString();
391     }
392 
393     @Override
394     public String visit(Continue node) {
395         return "continue;";
396     }
397 
398     @Override
399     public String visit(CounterInitializer node) {
400         VariableInfo vi = node.getVariableInfo();
401         return vi.type.accept(this) + " " + vi.name + " = " + node.getChild(0).accept(this)+ ";";
402     }
403 
404     @Override
405     public String visit(CounterManipulator node) {
406         return node.getChild(0).accept(this);
407     }
408 
409     @Override
410     public String visit(Declaration node) {
411         return node.getChild(0).accept(this)+ ";";
412     }
413 
414     @Override
415     public String visit(DoWhile node) {
416         IRNode header = node.getChild(DoWhile.DoWhilePart.HEADER.ordinal());
417         IRNode body1 = node.getChild(DoWhile.DoWhilePart.BODY1.ordinal());
418         IRNode body2 = node.getChild(DoWhile.DoWhilePart.BODY2.ordinal());
419         StringBuilder code = new StringBuilder();
420         Loop loop = node.getLoop();
421         int level = node.getLevel();
422         code.append(loop.initialization.accept(this))
423             .append("\n")
424             .append(header.accept(this))
425             .append(PrintingUtils.align(level))
426             .append("do\n")
427             .append(PrintingUtils.align(level))
428             .append("{\n")
429             .append(body1.accept(this))
430             .append(PrintingUtils.align(level + 1))
431             .append(loop.manipulator.accept(this))
432             .append(";\n")
433             .append(body2.accept(this))
434             .append(PrintingUtils.align(level))
435             .append("} while (")
436             .append(loop.condition.accept(this))
437             .append(");");
438         return code.toString();
439     }
440 
441     @Override
442     public String visit(For node) {
443         IRNode header = node.getChild(For.ForPart.HEADER.ordinal());
444         IRNode statement1 = node.getChild(For.ForPart.STATEMENT1.ordinal());
445         IRNode statement2 = node.getChild(For.ForPart.STATEMENT2.ordinal());
446         IRNode body1 = node.getChild(For.ForPart.BODY1.ordinal());
447         IRNode body2 = node.getChild(For.ForPart.BODY2.ordinal());
448         IRNode body3 = node.getChild(For.ForPart.BODY3.ordinal());
449         Loop loop = node.getLoop();
450         StringBuilder code = new StringBuilder();
451         int level = node.getLevel();
452         code.append(loop.initialization.accept(this))
453             .append("\n")
454             .append(header.accept(this))
455             .append(PrintingUtils.align(level))
456             .append("for (")
457             .append(statement1.accept(this))
458             .append("; ")
459             .append(loop.condition.accept(this))
460             .append("; ")
461             .append(statement2.accept(this))
462             .append(")\n")
463             .append(PrintingUtils.align(level))
464             .append("{\n")
465             .append(body1.accept(this))
466             .append(PrintingUtils.align(level + 1))
467             .append(loop.manipulator.accept(this))
468             .append(";\n")
469             .append(body2.accept(this))
470             .append(body3.accept(this))
471             .append(PrintingUtils.align(level))
472             .append("}");
473         return code.toString();
474     }
475 
476     @Override
477     public String visit(Function node) {
478         FunctionInfo value = node.getValue();
479         String nameAndArgs = value.name + "("
480                 + node.getChildren().stream()
481                     .skip(value.isStatic() || value.isConstructor() ? 0 : 1)
482                     .map(c -> c.accept(this))
483                     .collect(Collectors.joining(", "))
484                 + ")";
485         String prefix = "";
486         if (value.isStatic()) {
487             if(!node.getOwner().equals(value.owner)) {
488                 prefix = value.owner.getName() + ".";
489             }
490         } else if (value.isConstructor()) {
491             prefix = "new ";
492         } else {
493             IRNode object = node.getChild(0);
494             String objectString = object.accept(this);
495             if (!objectString.equals("this")) {
496                  if (object instanceof VariableBase || object instanceof Function
497                             || object instanceof Literal) {
498                      prefix = objectString + ".";
499                  } else {
500                      prefix = "(" + objectString + ")" + ".";
501                  }
502             }
503         }
504         return prefix + nameAndArgs;
505     }
506 
507     @Override
508     public String visit(FunctionDeclaration node) {
509         String args = node.getChildren().stream()
510                 .map(c -> c.accept(this))
511                 .collect(Collectors.joining(", "));
512 
513         FunctionInfo functionInfo = node.getFunctionInfo();
514         return (functionInfo.owner.isInterface() ? "" : "abstract ")
515                 + funcAttributes(functionInfo) + functionInfo.type.accept(this)+ " "
516                 + functionInfo.name + "(" + args + ");";
517     }
518 
519     @Override
520     public String visit(FunctionDeclarationBlock node) {
521         StringBuilder code = new StringBuilder();
522         for (IRNode i : node.getChildren()) {
523             code.append(PrintingUtils.align(node.getLevel()))
524                 .append(i.accept(this))
525                 .append(addComplexityInfo(i))
526                 .append("\n");
527         }
528         return code.toString();
529     }
530 
531     @Override
532     public String visit(FunctionDefinition node) {
533         String args = node.getChildren().stream()
534                 .skip(2)
535                 .map(c -> c.accept(this))
536                 .collect(Collectors.joining(", "));
537         IRNode body = node.getChild(0);
538         IRNode ret = node.getChild(1);
539         FunctionInfo functionInfo = node.getFunctionInfo();
540         return funcAttributes(functionInfo) + functionInfo.type.accept(this) + " " + functionInfo.name + "(" + args + ")" + "\n"
541                 + PrintingUtils.align(node.getLevel() + 1) + "{\n"
542                 + body.accept(this)
543                 + (ret != null ? PrintingUtils.align(node.getLevel() + 2) + ret.accept(this) + "\n" : "")
544                 + PrintingUtils.align(node.getLevel() + 1) + "}\n";
545     }
546 
547     @Override
548     public String visit(FunctionDefinitionBlock node) {
549         StringBuilder code = new StringBuilder();
550         for (IRNode i : node.getChildren()) {
551             code.append("\n")
552                 .append(PrintingUtils.align(node.getLevel()))
553                 .append(i.accept(this))
554                 .append(addComplexityInfo(i))
555                 .append("\n");
556         }
557         return code.toString();
558     }
559 
560     @Override
561     public String visit(FunctionRedefinition node) {
562         String args = node.getChildren().stream()
563                 .skip(2)
564                 .map(c -> c.accept(this))
565                 .collect(Collectors.joining(", "));
566 
567         IRNode body = node.getChild(0);
568         IRNode ret = node.getChild(1);
569         int level = node.getLevel();
570         FunctionInfo functionInfo = node.getFunctionInfo();
571         return funcAttributes(functionInfo) + functionInfo.type.accept(this) + " " + functionInfo.name + "(" + args + ")" + "\n"
572                 + PrintingUtils.align(level + 1) + "{\n"
573                 + body.accept(this)
574                 + (ret != null ? PrintingUtils.align(level + 2) + ret.accept(this) + "\n" : "")
575                 + PrintingUtils.align(level + 1) + "}";
576     }
577 
578     @Override
579     public String visit(FunctionRedefinitionBlock node) {
580         StringBuilder code = new StringBuilder();
581         for (IRNode i : node.getChildren()) {
582             code.append("\n")
583                 .append(PrintingUtils.align(node.getLevel()))
584                 .append(i.accept(this))
585                 .append(addComplexityInfo(i))
586                 .append("\n");
587         }
588         return code.toString();
589     }
590 
591     @Override
592     public String visit(If node) {
593         int level = node.getLevel();
594         String thenBlockString = PrintingUtils.align(level) + "{\n"
595                                  + node.getChild(If.IfPart.THEN.ordinal()).accept(this)
596                                  + PrintingUtils.align(level) + "}";
597 
598         String elseBlockString = null;
599         if (node.getChild(If.IfPart.ELSE.ordinal()) != null) {
600             elseBlockString = PrintingUtils.align(level) + "{\n"
601                               + node.getChild(If.IfPart.ELSE.ordinal()).accept(this)
602                               + PrintingUtils.align(level) + "}";
603         }
604 
605         return "if (" + node.getChild(If.IfPart.CONDITION.ordinal()).accept(this)+ ")\n"
606             + thenBlockString + (elseBlockString != null ? "\n"
607             + PrintingUtils.align(level) + "else\n" + elseBlockString : "");
608     }
609 
610     @Override
611     public String visit(Initialization node) {
612         VariableInfo vi = node.getVariableInfo();
613         return attributes(vi) + vi.type.accept(this)+ " " + vi.name + " = "
614                 + node.getChild(0).accept(this);
615     }
616 
617     @Override
618     public String visit(Interface node) {
619         return "interface " + node.getName() + (node.getParentKlass() != null ? " extends "
620                 + node.getParentKlass().getName() : "") + " {\n"
621                 + (node.getChildren().size() > 0 ? node.getChild(0).accept(this) : "")
622                 + "}\n";
623     }
624 
625     @Override
626     public String visit(Klass node) {
627         TypeKlass thisKlass = node.getThisKlass();
628         String r = (ProductionParams.enableStrictFP.value() ? "strictfp " : "")
629                 + (thisKlass.isFinal() ? "final " : "")
630                 + (thisKlass.isAbstract() ? "abstract " : "")
631                 + "class " + node.getName()
632                 + (node.getParentKlass() != null && !node.getParentKlass().equals(TypeList.OBJECT)
633                 ? " extends " + node.getParentKlass().getName() : "");
634         List<TypeKlass> interfaces = node.getInterfaces();
635         r += interfaces.stream()
636                 .map(Type::getName)
637                 .collect(Collectors.joining(", ", (interfaces.isEmpty() ? "" : " implements "), ""));
638         IRNode dataMembers = node.getChild(Klass.KlassPart.DATA_MEMBERS.ordinal());
639         IRNode constructors = node.getChild(Klass.KlassPart.CONSTRUCTORS.ordinal());
640         IRNode redefinedFunctions = node.getChild(Klass.KlassPart.REDEFINED_FUNCTIONS.ordinal());
641         IRNode overridenFunctions = node.getChild(Klass.KlassPart.OVERRIDEN_FUNCTIONS.ordinal());
642         IRNode memberFunctions = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS.ordinal());
643         IRNode memberFunctionDecls = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS_DECLARATIONS.ordinal());
644         IRNode printVariables = node.getChild(Klass.KlassPart.PRINT_VARIABLES.ordinal());
645         r += " {\n"
646              + (dataMembers != null ? (dataMembers.accept(this)+ "\n") : "")
647              + (constructors != null ? (constructors.accept(this)+ "\n") : "")
648              + (redefinedFunctions != null ? (redefinedFunctions.accept(this)+ "\n") : "")
649              + (overridenFunctions != null ? (overridenFunctions.accept(this)+ "\n") : "")
650              + (memberFunctionDecls != null ? (memberFunctionDecls.accept(this)+ "\n") : "")
651              + (memberFunctions != null ? (memberFunctions.accept(this)+ "\n") : "")
652              + printVariables.accept(this)
653              + "}\n";
654         return r;
655     }
656 
657     @Override
658     public String visit(Literal node) {
659         Type resultType = node.getResultType();
660         Object value = node.getValue();
661         if (resultType.equals(TypeList.LONG)) {
662             return value.toString() + "L";
663         }
664         if (resultType.equals(TypeList.FLOAT)) {
665             return String.format((Locale) null,
666                 "%EF",
667                 Double.parseDouble(value.toString()));
668         }
669         if (resultType.equals(TypeList.DOUBLE)) {
670             return String.format((Locale) null,
671                 "%E",
672                 Double.parseDouble(value.toString()));
673         }
674         if (resultType.equals(TypeList.CHAR)) {
675             if ((Character) value == '\\') {
676                 return "\'" + "\\\\" + "\'";
677             } else {
678                 return "\'" + value.toString() + "\'";
679             }
680         }
681         if (resultType.equals(TypeList.SHORT)) {
682             return "(short) " + value.toString();
683         }
684         if (resultType.equals(TypeList.BYTE)) {
685             return "(byte) " + value.toString();
686         }
687         if (resultType.equals(TypeList.STRING)) {
688             // TOOD handle other non-printable
689             return "\"" + value.toString().replace("\n", "\\n") + "\"";
690         }
691         return value.toString();
692     }
693 
694     @Override
695     public String visit(LocalVariable node) {
696         return node.getVariableInfo().name;
697     }
698 
699     @Override
700     public String visit(LoopingCondition node) {
701         return node.getCondition().accept(this);
702     }
703 
704     @Override
705     public String visit(MainKlass node) {
706         String name = node.getName();
707         IRNode dataMembers = node.getChild(MainKlass.MainKlassPart.DATA_MEMBERS.ordinal());
708         IRNode memberFunctions = node.getChild(MainKlass.MainKlassPart.MEMBER_FUNCTIONS.ordinal());
709         IRNode testFunction = node.getChild(MainKlass.MainKlassPart.TEST_FUNCTION.ordinal());
710         IRNode printVariables = node.getChild(MainKlass.MainKlassPart.PRINT_VARIABLES.ordinal());
711 
712         return (ProductionParams.enableStrictFP.value() ? "strictfp " : "")
713                 + "public class " + name + " {\n"
714                 + dataMembers.accept(this)+ "\n"
715                 + (memberFunctions != null ? memberFunctions.accept(this): "") + "\n"
716                 + "    private void test()\n"
717                 + "    {\n"
718                 + testFunction.accept(this)
719                 + "    }" + addComplexityInfo(testFunction) + "\n"
720                 + printVariables.accept(this)
721                 + "}\n\n";
722     }
723 
724     @Override
725     public String visit(NonStaticMemberVariable node) {
726         IRNode object = node.getChild(0);
727         String objectString = object.accept(this);
728         VariableInfo value = node.getVariableInfo();
729         if (objectString.equals("this")) {
730             return value.name;
731         } else {
732             if (object instanceof VariableBase || object instanceof Function || object instanceof Literal) {
733                 return objectString + "." + value.name;
734             } else {
735                 return "(" + objectString + ")" + "." + value.name;
736             }
737         }
738     }
739 
740     @Override
741     public String visit(Nothing node) {
742         return "";
743     }
744 
745     @Override
746     public String visit(PrintVariables node) {
747         return FixedTrees.printVariablesAsFunction(node).accept(this);
748     }
749 
750     @Override
751     public String visit(Return node) {
752         return "return " + node.getExpression().accept(this) + ";";
753     }
754 
755     @Override
756     public String visit(Throw node) {
757         return "throw " + node.getThowable().accept(this) + ";";
758     }
759 
760     @Override
761     public String visit(Statement node) {
762         return node.getChild(0).accept(this)+ (node.isSemicolonNeeded() ? ";" : "");
763     }
764 
765     @Override
766     public String visit(StaticConstructorDefinition node) {
767         IRNode body = node.getChild(0);
768         return "static {\n"
769                 + (body != null ? body.accept(this): "")
770                 + PrintingUtils.align(node.getLevel()) + "}";
771     }
772 
773     @Override
774     public String visit(StaticMemberVariable node) {
775         IRNode owner = node.getOwner();
776         VariableInfo info = node.getVariableInfo();
777         if (owner.equals(info.owner)) {
778             return info.name;
779         } else {
780             return info.owner.getName() + "." + info.name;
781         }
782     }
783 
784     @Override
785     public String visit(Switch node) {
786         int level = node.getLevel();
787         int caseBlockIdx = node.getCaseBlockIndex();
788         String cases = "";
789         for (int i = 0; i < caseBlockIdx - 1; ++i) {
790             cases += PrintingUtils.align(level + 1);
791             if (node.getChild(i + 1) instanceof Nothing) {
792                 cases += "default:\n";
793             } else {
794                 cases += "case " + node.getChild(i + 1).accept(this)+ ":\n";
795             }
796 
797             cases += node.getChild(i + caseBlockIdx).accept(this)+ "\n";
798         }
799         return "switch (" + node.getChild(0).accept(this)+ ")\n"
800                + PrintingUtils.align(level) + "{\n"
801                + cases
802                + PrintingUtils.align(level) + "}";
803     }
804 
805     @Override
806     public String visit(TernaryOperator node) {
807         IRNode conditionalExp = node.getChild(TernaryOperator.TernaryPart.CONDITION.ordinal());
808         IRNode leftExp = node.getChild(TernaryOperator.TernaryPart.TRUE.ordinal());
809         IRNode rightExp = node.getChild(TernaryOperator.TernaryPart.FALSE.ordinal());
810         if (Objects.isNull(conditionalExp) || Objects.isNull(leftExp) || Objects.isNull(rightExp)) {
811             return "null";
812         }
813         return expressionToJavaCode(node, conditionalExp, Operator.Order.RIGHT) + " ? "
814                 + expressionToJavaCode(node, leftExp, Operator.Order.RIGHT) + " : "
815                 + expressionToJavaCode(node, rightExp, Operator.Order.RIGHT);
816     }
817 
818     @Override
819     public String visit(Type node) {
820         return node.getName();
821     }
822 
823     @Override
824     public String visit(TypeArray node) {
825         String r = node.getType().accept(this);
826         for (int i = 0; i < node.getDimensions(); i++) {
827             r += "[]";
828         }
829         return r;
830     }
831 
832     @Override
833     public String visit(UnaryOperator node) {
834         IRNode exp = node.getChild(0);
835         if (node.isPrefix()) {
836             return operatorToJaveCode(node.getOperationKind())
837                     + (exp instanceof Operator ? " " : "")
838                     + expressionToJavaCode(node, exp, Operator.Order.LEFT);
839         } else {
840             return expressionToJavaCode(node, exp, Operator.Order.RIGHT)
841                     + (exp instanceof Operator ? " " : "")
842                     + operatorToJaveCode(node.getOperationKind());
843         }
844     }
845 
846     @Override
847     public String visit(VariableDeclaration node) {
848         VariableInfo vi = node.getVariableInfo();
849         return attributes(vi) + vi.type.accept(this)+ " " + vi.name;
850     }
851 
852     @Override
853     public String visit(VariableDeclarationBlock node) {
854         StringBuilder code = new StringBuilder();
855         for (IRNode i : node.getChildren()) {
856             code.append(PrintingUtils.align(node.getLevel()))
857                 .append(i.accept(this))
858                 .append(addComplexityInfo(i))
859                 .append("\n");
860         }
861         return code.toString();
862     }
863 
864     @Override
865     public String visit(While node) {
866         IRNode header = node.getChild(While.WhilePart.HEADER.ordinal());
867         IRNode body1 = node.getChild(While.WhilePart.BODY1.ordinal());
868         IRNode body2 = node.getChild(While.WhilePart.BODY2.ordinal());
869         IRNode body3 = node.getChild(While.WhilePart.BODY3.ordinal());
870         int level = node.getLevel();
871         Loop loop = node.getLoop();
872         return loop.initialization.accept(this)+ "\n"
873                 + header.accept(this)
874                 + PrintingUtils.align(level) + "while (" + loop.condition.accept(this)+ ")\n"
875                 + PrintingUtils.align(level) + "{\n"
876                 + body1.accept(this)
877                 + PrintingUtils.align(level + 1) + loop.manipulator.accept(this)+ ";\n"
878                 + body2.accept(this)
879                 + body3.accept(this)
880                 + PrintingUtils.align(level) + "}";
881     }
882 
883     @Override
884     public String visit(CatchBlock node) {
885         StringBuilder result = new StringBuilder();
886         int level = node.getLevel();
887         result.append(PrintingUtils.align(level)).append("catch(");
888         result.append(node.throwables.get(0).accept(this));
889         for (int i = 1; i < node.throwables.size(); i++) {
890             result.append(" | ").append(node.throwables.get(i).accept(this));
891         }
892         result.append(" ex) {\n");
893         result.append(node.getChild(0).accept(this));
894         result.append(PrintingUtils.align(level)).append("}\n");
895         return result.toString();
896     }
897 
898     @Override
899     public String visit(TryCatchBlock node) {
900         StringBuilder result = new StringBuilder();
901         List<? extends IRNode> childs = node.getChildren();
902         IRNode body = childs.get(0);
903         IRNode finallyBody = childs.get(1);
904         int level = node.getLevel();
905         result.append("try {\n")
906                 .append(body.accept(this)).append("\n")
907                 .append(PrintingUtils.align(level))
908                 .append("}\n");
909         for (int i = 2; i < childs.size(); i++) {
910             result.append(childs.get(i).accept(this));
911         }
912         if (finallyBody != null) {
913             String finallyContent = finallyBody.accept(this);
914             if (!finallyContent.isEmpty()) {
915                 result.append(PrintingUtils.align(level)).append("finally {\n")
916                         .append(finallyContent).append("\n")
917                         .append(PrintingUtils.align(level)).append("}\n");
918             }
919         }
920         return result.toString();
921     }
922 }