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.HashSet;
  27 import java.util.Iterator;
  28 import java.util.List;
  29 import java.util.Locale;
  30 import java.util.Objects;
  31 import java.util.stream.Collectors;
  32 import jdk.test.lib.jittester.BinaryOperator;
  33 import jdk.test.lib.jittester.Block;
  34 import jdk.test.lib.jittester.Break;
  35 import jdk.test.lib.jittester.CastOperator;
  36 import jdk.test.lib.jittester.CatchBlock;
  37 import jdk.test.lib.jittester.Continue;
  38 import jdk.test.lib.jittester.Declaration;
  39 import jdk.test.lib.jittester.IRNode;
  40 import jdk.test.lib.jittester.If;
  41 import jdk.test.lib.jittester.Initialization;
  42 import jdk.test.lib.jittester.Literal;
  43 import jdk.test.lib.jittester.LocalVariable;
  44 import jdk.test.lib.jittester.LogicOperator;
  45 import jdk.test.lib.jittester.NonStaticMemberVariable;
  46 import jdk.test.lib.jittester.Nothing;
  47 import jdk.test.lib.jittester.Operator;
  48 import jdk.test.lib.jittester.PrintVariables;
  49 import jdk.test.lib.jittester.ProductionParams;
  50 import jdk.test.lib.jittester.Statement;
  51 import jdk.test.lib.jittester.StaticMemberVariable;
  52 import jdk.test.lib.jittester.Switch;
  53 import jdk.test.lib.jittester.Symbol;
  54 import jdk.test.lib.jittester.TernaryOperator;
  55 import jdk.test.lib.jittester.Throw;
  56 import jdk.test.lib.jittester.TryCatchBlock;
  57 import jdk.test.lib.jittester.Type;
  58 import jdk.test.lib.jittester.TypeList;
  59 import jdk.test.lib.jittester.UnaryOperator;
  60 import jdk.test.lib.jittester.VariableBase;
  61 import jdk.test.lib.jittester.VariableDeclaration;
  62 import jdk.test.lib.jittester.VariableDeclarationBlock;
  63 import jdk.test.lib.jittester.VariableInfo;
  64 import jdk.test.lib.jittester.arrays.ArrayCreation;
  65 import jdk.test.lib.jittester.arrays.ArrayElement;
  66 import jdk.test.lib.jittester.arrays.ArrayExtraction;
  67 import jdk.test.lib.jittester.classes.ClassDefinitionBlock;
  68 import jdk.test.lib.jittester.classes.Interface;
  69 import jdk.test.lib.jittester.classes.Klass;
  70 import jdk.test.lib.jittester.classes.MainKlass;
  71 import jdk.test.lib.jittester.functions.ArgumentDeclaration;
  72 import jdk.test.lib.jittester.functions.ConstructorDefinition;
  73 import jdk.test.lib.jittester.functions.ConstructorDefinitionBlock;
  74 import jdk.test.lib.jittester.functions.Function;
  75 import jdk.test.lib.jittester.functions.FunctionDeclaration;
  76 import jdk.test.lib.jittester.functions.FunctionDeclarationBlock;
  77 import jdk.test.lib.jittester.functions.FunctionDefinition;
  78 import jdk.test.lib.jittester.functions.FunctionDefinitionBlock;
  79 import jdk.test.lib.jittester.functions.FunctionInfo;
  80 import jdk.test.lib.jittester.functions.FunctionRedefinition;
  81 import jdk.test.lib.jittester.functions.FunctionRedefinitionBlock;
  82 import jdk.test.lib.jittester.functions.Return;
  83 import jdk.test.lib.jittester.functions.StaticConstructorDefinition;
  84 import jdk.test.lib.jittester.loops.CounterInitializer;
  85 import jdk.test.lib.jittester.loops.CounterManipulator;
  86 import jdk.test.lib.jittester.loops.DoWhile;
  87 import jdk.test.lib.jittester.loops.For;
  88 import jdk.test.lib.jittester.loops.Loop;
  89 import jdk.test.lib.jittester.loops.LoopingCondition;
  90 import jdk.test.lib.jittester.loops.While;
  91 import jdk.test.lib.jittester.types.TypeArray;
  92 import jdk.test.lib.jittester.types.TypeByte;
  93 import jdk.test.lib.jittester.types.TypeKlass;
  94 import jdk.test.lib.jittester.types.TypeChar;
  95 import jdk.test.lib.jittester.types.TypeDouble;
  96 import jdk.test.lib.jittester.types.TypeFloat;
  97 import jdk.test.lib.jittester.types.TypeLong;
  98 import jdk.test.lib.jittester.types.TypeShort;
  99 import jdk.test.lib.jittester.utils.PrintingUtils;
 100 
 101 public class JavaCodeVisitor implements Visitor<String> {
 102 
 103     public static String funcAttributes(FunctionInfo fi) {
 104         String attrs = attributes(fi);
 105         if (fi.isSynchronized()) {
 106             attrs += "synchronized ";
 107         }
 108         return attrs;
 109     }
 110 
 111     public static String attributes(Symbol s) {
 112         String attrs = "";
 113         if (s.isPrivate()) {
 114             attrs += "private ";
 115         }
 116         if (s.isProtected()) {
 117             attrs += "protected ";
 118         }
 119         if (s.isPublic()) {
 120             attrs += "public ";
 121         }
 122         if (s.isFinal()) {
 123             attrs += "final ";
 124         }
 125         if (s.isStatic()) {
 126             attrs += "static ";
 127         }
 128         return attrs;
 129     }
 130 
 131     public String expressionToJavaCode(Operator t, IRNode p, Operator.Order o) {
 132         String result;
 133         try {
 134             if ((o == Operator.Order.LEFT && ((Operator) p).getPriority() < t.getPriority())
 135                     || (o == Operator.Order.RIGHT && ((Operator) p).getPriority() <= t.getPriority())) {
 136                 result = "(" + p.accept(this)+ ")";
 137             } else {
 138                 result = p.accept(this);
 139             }
 140         } catch (Exception e) {
 141             result = p.accept(this);
 142         }
 143         return result;
 144     }
 145 
 146     @Override
 147     public String visit(ArgumentDeclaration node) {
 148         VariableInfo vi = node.variableInfo;
 149         return attributes(vi) + vi.type.accept(this) + " " + vi.name;
 150     }
 151 
 152     @Override
 153     public String visit(ArrayCreation node) {
 154         Type arrayType = node.getArrayType();
 155         String type = arrayType.accept(this);
 156         String name = node.getVariable().getName();
 157         StringBuilder code = new StringBuilder()
 158                 .append(node.getVariable().accept(this))
 159                 .append(";\n")
 160                 .append(PrintingUtils.align(node.getParent().getLevel()))
 161                 .append(name)
 162                 .append(" = new ")
 163                 .append(type);
 164         code.append(node.getChildren().stream()
 165                 .map(p -> p.accept(this))
 166                 .collect(Collectors.joining("][", "[", "]")));
 167         code.append(";\n");
 168         if (!TypeList.isBuiltIn(arrayType)) {
 169             code.append(PrintingUtils.align(node.getParent().getLevel()))
 170                 .append("java.util.Arrays.fill(")
 171                 .append(name)
 172                 .append(", new ")
 173                 .append(type)
 174                 .append("());\n");
 175         }
 176         return code.toString();
 177     }
 178 
 179     @Override
 180     public String visit(ArrayElement node) {
 181         IRNode array = node.getChild(0);
 182         StringBuilder code = new StringBuilder();
 183         if (array instanceof VariableBase || array instanceof Function) {
 184             code.append(array.accept(this));
 185         } else {
 186             code.append("(")
 187                 .append(array.accept(this))
 188                 .append(")");
 189         }
 190         code.append(node.getChildren().stream()
 191                 .skip(1)
 192                 .map(c -> c.accept(this))
 193                 .collect(Collectors.joining("][", "[", "]")));
 194         return code.toString();
 195     }
 196 
 197     @Override
 198     public String visit(ArrayExtraction node) {
 199         IRNode array = node.getChild(0);
 200         StringBuilder code = new StringBuilder();
 201         if (array instanceof VariableBase || array instanceof Function) {
 202             code.append(array.accept(this));
 203         } else {
 204             code.append("(")
 205                 .append(array.accept(this))
 206                 .append(")");
 207         }
 208         code.append(node.getChildren().stream()
 209                 .skip(1)
 210                 .map(c -> c.accept(this))
 211                 .collect(Collectors.joining("][", "[", "]")));
 212         return code.toString();
 213     }
 214 
 215     @Override
 216     public String visit(BinaryOperator node) {
 217         IRNode left = node.getChild(Operator.Order.LEFT.ordinal());
 218         IRNode right = node.getChild(Operator.Order.RIGHT.ordinal());
 219         if (left == null || right == null) {
 220             return "null";
 221         }
 222         return expressionToJavaCode(node, left, Operator.Order.LEFT)
 223                + " " + node.getOperationCode() + " "
 224                + expressionToJavaCode(node, right, Operator.Order.RIGHT);
 225     }
 226 
 227     @Override
 228     public String visit(Block node) {
 229         StringBuilder code = new StringBuilder();
 230         for (IRNode i : node.getChildren()) {
 231             String s = i.accept(this);
 232             if (!s.isEmpty()) {
 233                 int level = node.getLevel();
 234                 if (i instanceof Block) {
 235                     code.append(PrintingUtils.align(level + 1))
 236                         .append("{\n")
 237                         .append(s)
 238                         .append(PrintingUtils.align(level + 1))
 239                         .append("}");
 240                 } else {
 241                     code.append(PrintingUtils.align(level + 1))
 242                         .append(s);
 243                 }
 244                 code.append(addComplexityInfo(i));
 245                 code.append("\n");
 246             }
 247         }
 248         return code.toString();
 249     }
 250 
 251     private String addComplexityInfo(IRNode node) {
 252         if (ProductionParams.printComplexity.value()) {
 253             return " /* " + node.complexity() + " */";
 254         }
 255         return "";
 256     }
 257 
 258     @Override
 259     public String visit(Break node) {
 260         return "break;";
 261     }
 262 
 263     @Override
 264     public String visit(CastOperator node) {
 265         return "(" + node.getResultType().accept(this)+ ")"
 266                 + expressionToJavaCode(node, node.getChild(0), Operator.Order.LEFT);
 267     }
 268 
 269     @Override
 270     public String visit(ClassDefinitionBlock node) {
 271         StringBuilder code = new StringBuilder();
 272         for (IRNode i : node.getChildren()) {
 273             code.append("\n")
 274                 .append(PrintingUtils.align(node.getLevel()))
 275                 .append(i.accept(this))
 276                 .append("\n");
 277         }
 278 
 279         return code.toString();
 280     }
 281 
 282     @Override
 283     public String visit(ConstructorDefinition node) {
 284         String args = node.getChildren().stream()
 285                 .skip(1)
 286                 .map(c -> c.accept(this))
 287                 .collect(Collectors.joining(", "));
 288         IRNode body = node.getChild(0);
 289         StringBuilder code = new StringBuilder();
 290         code.append(funcAttributes(node.getFunctionInfo()))
 291             .append(node.getFunctionInfo().name)
 292             .append("(")
 293             .append(args)
 294             .append(")\n")
 295             .append(PrintingUtils.align(node.getLevel() + 1))
 296             .append("{\n")
 297             .append(body != null ? body.accept(this) : "")
 298             .append(PrintingUtils.align(node.getLevel() + 1))
 299             .append("}");
 300         return code.toString();
 301     }
 302 
 303     @Override
 304     public String visit(ConstructorDefinitionBlock node) {
 305         StringBuilder code = new StringBuilder();
 306         for (IRNode i : node.getChildren()) {
 307             code.append("\n")
 308                 .append(PrintingUtils.align(node.getLevel()))
 309                 .append(i.accept(this))
 310                 .append(addComplexityInfo(i))
 311                 .append("\n");
 312         }
 313         return code.toString();
 314     }
 315 
 316     @Override
 317     public String visit(Continue node) {
 318         return "continue;";
 319     }
 320 
 321     @Override
 322     public String visit(CounterInitializer node) {
 323         VariableInfo vi = node.get();
 324         return vi.type.accept(this) + " " + vi.name + " = " + node.getChild(0).accept(this)+ ";";
 325     }
 326 
 327     @Override
 328     public String visit(CounterManipulator node) {
 329         return node.getChild(0).accept(this);
 330     }
 331 
 332     @Override
 333     public String visit(Declaration node) {
 334         return node.getChild(0).accept(this)+ ";";
 335     }
 336 
 337     @Override
 338     public String visit(DoWhile node) {
 339         IRNode header = node.getChild(DoWhile.DoWhilePart.HEADER.ordinal());
 340         IRNode body1 = node.getChild(DoWhile.DoWhilePart.BODY1.ordinal());
 341         IRNode body2 = node.getChild(DoWhile.DoWhilePart.BODY2.ordinal());
 342         StringBuilder code = new StringBuilder();
 343         Loop loop = node.getLoop();
 344         int level = node.getLevel();
 345         code.append(loop.initialization.accept(this))
 346             .append("\n")
 347             .append(header.accept(this))
 348             .append(PrintingUtils.align(level))
 349             .append("do\n")
 350             .append(PrintingUtils.align(level))
 351             .append("{\n")
 352             .append(body1.accept(this))
 353             .append(PrintingUtils.align(level + 1))
 354             .append(loop.manipulator.accept(this))
 355             .append(";\n")
 356             .append(body2.accept(this))
 357             .append(PrintingUtils.align(level))
 358             .append("} while (")
 359             .append(loop.condition.accept(this))
 360             .append(");");
 361         return code.toString();
 362     }
 363 
 364     @Override
 365     public String visit(For node) {
 366         IRNode header = node.getChild(For.ForPart.HEADER.ordinal());
 367         IRNode statement1 = node.getChild(For.ForPart.STATEMENT1.ordinal());
 368         IRNode statement2 = node.getChild(For.ForPart.STATEMENT2.ordinal());
 369         IRNode body1 = node.getChild(For.ForPart.BODY1.ordinal());
 370         IRNode body2 = node.getChild(For.ForPart.BODY2.ordinal());
 371         IRNode body3 = node.getChild(For.ForPart.BODY3.ordinal());
 372         Loop loop = node.getLoop();
 373         StringBuilder code = new StringBuilder();
 374         int level = node.getLevel();
 375         code.append(loop.initialization.accept(this))
 376             .append("\n")
 377             .append(header.accept(this))
 378             .append(PrintingUtils.align(level))
 379             .append("for (")
 380             .append(statement1.accept(this))
 381             .append("; ")
 382             .append(loop.condition.accept(this))
 383             .append("; ")
 384             .append(statement2.accept(this))
 385             .append(")\n")
 386             .append(PrintingUtils.align(level))
 387             .append("{\n")
 388             .append(body1.accept(this))
 389             .append(PrintingUtils.align(level + 1))
 390             .append(loop.manipulator.accept(this))
 391             .append(";\n")
 392             .append(body2.accept(this))
 393             .append(body3.accept(this))
 394             .append(PrintingUtils.align(level))
 395             .append("}");
 396         return code.toString();
 397     }
 398 
 399     @Override
 400     public String visit(Function node) {
 401         FunctionInfo value = node.getValue();
 402         String nameAndArgs = value.name + "("
 403                 + node.getChildren().stream()
 404                     .skip(value.isStatic() || value.isConstructor() ? 0 : 1)
 405                     .map(c -> c.accept(this))
 406                     .collect(Collectors.joining(", "))
 407                 + ")";
 408         String prefix = "";
 409         if (value.isStatic()) {
 410             if(!node.getKlass().equals(value.klass)) {
 411                 prefix = value.klass.getName() + ".";
 412             }
 413         } else if (value.isConstructor()) {
 414             prefix = "new ";
 415         } else {
 416             IRNode object = node.getChild(0);
 417             String objectString = object.accept(this);
 418             if (!objectString.equals("this")) {
 419                  if (object instanceof VariableBase || object instanceof Function
 420                             || object instanceof Literal) {
 421                      prefix = objectString + ".";
 422                  } else {
 423                      prefix = "(" + objectString + ")" + ".";
 424                  }
 425             }
 426         }
 427         return prefix + nameAndArgs;
 428     }
 429 
 430     @Override
 431     public String visit(FunctionDeclaration node) {
 432         String args = node.getChildren().stream()
 433                 .map(c -> c.accept(this))
 434                 .collect(Collectors.joining(", "));
 435 
 436         FunctionInfo functionInfo = node.getFunctionInfo();
 437         return (functionInfo.klass.isInterface() ? "" : "abstract ")
 438                 + funcAttributes(functionInfo) + functionInfo.type.accept(this)+ " "
 439                 + functionInfo.name + "(" + args + ");";
 440     }
 441 
 442     @Override
 443     public String visit(FunctionDeclarationBlock node) {
 444         StringBuilder code = new StringBuilder();
 445         for (IRNode i : node.getChildren()) {
 446             code.append(PrintingUtils.align(node.getLevel()))
 447                 .append(i.accept(this))
 448                 .append(addComplexityInfo(i))
 449                 .append("\n");
 450         }
 451         return code.toString();
 452     }
 453 
 454     @Override
 455     public String visit(FunctionDefinition node) {
 456         String args = node.getChildren().stream()
 457                 .skip(2)
 458                 .map(c -> c.accept(this))
 459                 .collect(Collectors.joining(", "));
 460         IRNode body = node.getChild(0);
 461         IRNode ret = node.getChild(1);
 462         FunctionInfo functionInfo = node.getFunctionInfo();
 463         return funcAttributes(functionInfo) + functionInfo.type.accept(this) + " " + functionInfo.name + "(" + args + ")" + "\n"
 464                 + PrintingUtils.align(node.getLevel() + 1) + "{\n"
 465                 + body.accept(this)
 466                 + (ret != null ? PrintingUtils.align(node.getLevel() + 2) + ret.accept(this) + "\n" : "")
 467                 + PrintingUtils.align(node.getLevel() + 1) + "}";
 468     }
 469 
 470     @Override
 471     public String visit(FunctionDefinitionBlock node) {
 472         StringBuilder code = new StringBuilder();
 473         for (IRNode i : node.getChildren()) {
 474             code.append("\n")
 475                 .append(PrintingUtils.align(node.getLevel()))
 476                 .append(i.accept(this))
 477                 .append(addComplexityInfo(i))
 478                 .append("\n");
 479         }
 480         return code.toString();
 481     }
 482 
 483     @Override
 484     public String visit(FunctionRedefinition node) {
 485         String args = node.getChildren().stream()
 486                 .map(c -> c.accept(this))
 487                 .collect(Collectors.joining(", "));
 488 
 489         IRNode body = node.getChild(0);
 490         IRNode ret = node.getChild(1);
 491         int level = node.getLevel();
 492         FunctionInfo functionInfo = node.getFunctionInfo();
 493         return funcAttributes(functionInfo) + functionInfo.type + " " + functionInfo.name + "(" + args + ")" + "\n"
 494                 + PrintingUtils.align(level + 1) + "{\n"
 495                 + body
 496                 + (ret != null ? PrintingUtils.align(level + 2) + ret + "\n" : "")
 497                 + PrintingUtils.align(level + 1) + "}";
 498     }
 499 
 500     @Override
 501     public String visit(FunctionRedefinitionBlock node) {
 502         StringBuilder code = new StringBuilder();
 503         for (IRNode i : node.getChildren()) {
 504             code.append("\n")
 505                 .append(PrintingUtils.align(node.getLevel()))
 506                 .append(i.accept(this))
 507                 .append(addComplexityInfo(i))
 508                 .append("\n");
 509         }
 510         return code.toString();
 511     }
 512 
 513     @Override
 514     public String visit(If node) {
 515         int level = node.getLevel();
 516         String thenBlockString = PrintingUtils.align(level) + "{\n"
 517                                  + node.getChild(If.IfPart.THEN.ordinal()).accept(this)
 518                                  + PrintingUtils.align(level) + "}";
 519 
 520         String elseBlockString = null;
 521         if (node.getChild(If.IfPart.ELSE.ordinal()) != null) {
 522             elseBlockString = PrintingUtils.align(level) + "{\n"
 523                               + node.getChild(If.IfPart.ELSE.ordinal()).accept(this)
 524                               + PrintingUtils.align(level) + "}";
 525         }
 526 
 527         return "if (" + node.getChild(If.IfPart.CONDITION.ordinal()).accept(this)+ ")\n"
 528             + thenBlockString + (elseBlockString != null ? "\n"
 529             + PrintingUtils.align(level) + "else\n" + elseBlockString : "");
 530     }
 531 
 532     @Override
 533     public String visit(Initialization node) {
 534         VariableInfo vi = node.getVariableInfo();
 535         return attributes(vi) + vi.type.accept(this)+ " " + vi.name + " = "
 536                 + node.getChild(0).accept(this);
 537     }
 538 
 539     @Override
 540     public String visit(Interface node) {
 541         return "interface " + node.getName() + (node.getParentKlass() != null ? " extends "
 542                 + node.getParentKlass().getName() : "") + " {\n"
 543                 + (node.getChildren().size() > 0 ? node.getChild(0).accept(this) : "")
 544                 + "}\n";
 545     }
 546 
 547     @Override
 548     public String visit(Klass node) {
 549         TypeKlass thisKlass = node.getThisKlass();
 550         String r = (ProductionParams.enableStrictFP.value() ? "strictfp " : "")
 551                 + (thisKlass.isFinal() ? "final " : "")
 552                 + (thisKlass.isAbstract() ? "abstract " : "")
 553                 + "class " + node.getName()
 554                 + (node.getParentKlass()!= null ? " extends " + node.getParentKlass().getName() : "");
 555         List<TypeKlass> interfaces = node.getInterfaces();
 556         r += interfaces.stream()
 557                 .map(c -> c.getName())
 558                 .collect(Collectors.joining(", ", (interfaces.isEmpty() ? "" : " implements "), ""));
 559         IRNode dataMembers = node.getChild(Klass.KlassPart.DATA_MEMBERS.ordinal());
 560         IRNode constructors = node.getChild(Klass.KlassPart.CONSTRUCTORS.ordinal());
 561         IRNode redefinedFunctions = node.getChild(Klass.KlassPart.REDEFINED_FUNCTIONS.ordinal());
 562         IRNode overridenFunctions = node.getChild(Klass.KlassPart.OVERRIDEN_FUNCTIONS.ordinal());
 563         IRNode memberFunctions = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS.ordinal());
 564         IRNode memberFunctionDecls = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS_DECLARATIONS.ordinal());
 565         IRNode printVariables = node.getChild(Klass.KlassPart.PRINT_VARIABLES.ordinal());
 566         r += " {\n"
 567              + (dataMembers != null ? (dataMembers.accept(this)+ "\n") : "")
 568              + (constructors != null ? (constructors.accept(this)+ "\n") : "")
 569              + (redefinedFunctions != null ? (redefinedFunctions.accept(this)+ "\n") : "")
 570              + (overridenFunctions != null ? (overridenFunctions.accept(this)+ "\n") : "")
 571              + (memberFunctionDecls != null ? (memberFunctionDecls.accept(this)+ "\n") : "")
 572              + (memberFunctions != null ? (memberFunctions.accept(this)+ "\n") : "")
 573              + "    public String toString()\n"
 574              + "    {\n"
 575              + printVariables.accept(this)
 576              + "    }\n"
 577              + "}\n";
 578         return r;
 579     }
 580 
 581     @Override
 582     public String visit(Literal node) {
 583         Type resultType = node.getResultType();
 584         Object value = node.getValue();
 585         if (resultType.equals(new TypeLong())) {
 586             return value.toString() + "L";
 587         }
 588         if (resultType.equals(new TypeFloat())) {
 589             return String.format((Locale) null,
 590                 "%." + ProductionParams.floatingPointPrecision.value() + "EF",
 591                 Double.parseDouble(value.toString()));
 592         }
 593         if (resultType.equals(new TypeDouble())) {
 594             return String.format((Locale) null,
 595                 "%." + 2 * ProductionParams.floatingPointPrecision.value() + "E",
 596                 Double.parseDouble(value.toString()));
 597         }
 598         if (resultType.equals(new TypeChar())) {
 599             if (((Character) value).charValue() == '\\') {
 600                 return "\'" + "\\\\" + "\'";
 601             } else {
 602                 return "\'" + value.toString() + "\'";
 603             }
 604         }
 605         if (resultType.equals(new TypeShort())) {
 606             return "(short) " + value.toString();
 607         }
 608         if (resultType.equals(new TypeByte())) {
 609             return "(byte) " + value.toString();
 610         }
 611         return value.toString();
 612     }
 613 
 614     @Override
 615     public String visit(LocalVariable node) {
 616         return node.get().name;
 617     }
 618 
 619     @Override
 620     public String visit(LogicOperator node) {
 621         throw new UnsupportedOperationException("Not supported yet.");
 622     }
 623 
 624     @Override
 625     public String visit(LoopingCondition node) {
 626         return node.getCondition().accept(this);
 627     }
 628 
 629     @Override
 630     public String visit(MainKlass node) {
 631         String name = node.getName();
 632         IRNode dataMembers = node.getChild(MainKlass.MainKlassPart.DATA_MEMBERS.ordinal());
 633         IRNode memberFunctions = node.getChild(MainKlass.MainKlassPart.MEMBER_FUNCTIONS.ordinal());
 634         IRNode testFunction = node.getChild(MainKlass.MainKlassPart.TEST_FUNCTION.ordinal());
 635         IRNode printVariables = node.getChild(MainKlass.MainKlassPart.PRINT_VARIABLES.ordinal());
 636         String executeFunction = "    public static String execute()\n"
 637                 + "    {\n"
 638                 + "        try {\n"
 639                 + "            " + name + " t = new " + name + "();\n"
 640                 + "            try { t.test(); }\n"
 641                 + "            catch(Throwable e) { }\n"
 642                 + "            try { return t.toString(); }\n"
 643                 + "            catch (Throwable e) { return \"Error during result conversion to String\"; }\n"
 644                 + "        } catch (Throwable e) { return \"Error during test execution\"; }\n"
 645                 + "    }\n";
 646         String mainFunction = "    public static void main(String[] args)\n"
 647                 + "    {\n"
 648                 + "        try {\n"
 649                 + "            " + name + " t = new " + name + "();\n"
 650                 + "            try {\n"
 651                 + "                for (int i = 0; i < 150000; ++i) {\n"
 652                 + "                    t.test();\n"
 653                 + "                }\n"
 654                 + "            }\n"
 655                 + "            catch(Throwable e) { e.printStackTrace(); }\n"
 656                 + "            try { System.out.println(t); }\n"
 657                 + "            catch(Throwable e) { e.printStackTrace();}\n"
 658                 + "        } catch (Throwable e) { e.printStackTrace(); }\n"
 659                 + "    }\n";
 660         String printerClass = "    static class Printer\n"
 661                 + "    {\n"
 662                 + "        public static String print(boolean arg) { return String.valueOf(arg); }\n"
 663                 + "        public static String print(byte arg)    { return String.valueOf(arg); }\n"
 664                 + "        public static String print(short arg)   { return String.valueOf(arg); }\n"
 665                 + "        public static String print(char arg)    { return String.valueOf((int)arg); }\n"
 666                 + "        public static String print(int arg)     { return String.valueOf(arg); }\n"
 667                 + "        public static String print(long arg)    { return String.valueOf(arg); }\n"
 668                 + "        public static String print(float arg)   { return String.valueOf(arg); }\n"
 669                 + "        public static String print(double arg)  { return String.valueOf(arg); }\n"
 670                 + "\n"
 671                 + "\n"
 672                 + "        public static String print(Object arg)\n"
 673                 + "        {\n"
 674                 + "            return print_r(new java.util.Stack(), arg);\n"
 675                 + "        }\n"
 676                 + "\n"
 677                 + "        private static String print_r(java.util.Stack visitedObjects, Object arg)\n"
 678                 + "        {\n"
 679                 + "            String result = \"\";\n"
 680                 + "            if (arg == null)\n"
 681                 + "                result += \"null\";\n"
 682                 + "            else\n"
 683                 + "            if (arg.getClass().isArray())\n"
 684                 + "            {\n"
 685                 + "                for (int i = 0; i < visitedObjects.size(); i++)\n"
 686                 + "                    if (visitedObjects.elementAt(i) == arg) return \"<recursive>\";\n"
 687                 + "\n"
 688                 + "                visitedObjects.push(arg);\n"
 689                 + "\n"
 690                 + "                final String delimiter = \", \";\n"
 691                 + "                result += \"[\";\n"
 692                 + "\n"
 693                 + "                if (arg instanceof Object[])\n"
 694                 + "                {\n"
 695                 + "                    Object[] array = (Object[]) arg;\n"
 696                 + "                    for (int i = 0; i < array.length; i++)\n"
 697                 + "                    {\n"
 698                 + "                        result += print_r(visitedObjects, array[i]);\n"
 699                 + "                        if (i < array.length - 1) result += delimiter;\n"
 700                 + "                    }\n"
 701                 + "                }\n"
 702                 + "                else\n"
 703                 + "                if (arg instanceof boolean[])\n"
 704                 + "                {\n"
 705                 + "                    boolean[] array = (boolean[]) arg;\n"
 706                 + "                    for (int i = 0; i < array.length; i++)\n"
 707                 + "                    {\n"
 708                 + "                        result += print(array[i]);\n"
 709                 + "                        if (i < array.length - 1) result += delimiter;\n"
 710                 + "                    }\n"
 711                 + "                }\n"
 712                 + "                else\n"
 713                 + "                if (arg instanceof byte[])\n"
 714                 + "                {\n"
 715                 + "                    byte[] array = (byte[]) arg;\n"
 716                 + "                    for (int i = 0; i < array.length; i++)\n"
 717                 + "                    {\n"
 718                 + "                        result += print(array[i]);\n"
 719                 + "                        if (i < array.length - 1) result += delimiter;\n"
 720                 + "                    }\n"
 721                 + "                }\n"
 722                 + "                else\n"
 723                 + "                if (arg instanceof short[])\n"
 724                 + "                {\n"
 725                 + "                    short[] array = (short[]) arg;\n"
 726                 + "                    for (int i = 0; i < array.length; i++)\n"
 727                 + "                    {\n"
 728                 + "                        result += print(array[i]);\n"
 729                 + "                        if (i < array.length - 1) result += delimiter;\n"
 730                 + "                    }\n"
 731                 + "                }\n"
 732                 + "                else\n"
 733                 + "                if (arg instanceof char[])\n"
 734                 + "                {\n"
 735                 + "                    char[] array = (char[]) arg;\n"
 736                 + "                    for (int i = 0; i < array.length; i++)\n"
 737                 + "                    {\n"
 738                 + "                        result += print(array[i]);\n"
 739                 + "                        if (i < array.length - 1) result += delimiter;\n"
 740                 + "                    }\n"
 741                 + "                }\n"
 742                 + "                else\n"
 743                 + "                if (arg instanceof int[])\n"
 744                 + "                {\n"
 745                 + "                     int[] array = (int[]) arg;\n"
 746                 + "                     for (int i = 0; i < array.length; i++)\n"
 747                 + "                     {\n"
 748                 + "                        result += print(array[i]);\n"
 749                 + "                        if (i < array.length - 1) result += delimiter;\n"
 750                 + "                     }\n"
 751                 + "                }\n"
 752                 + "                else\n"
 753                 + "                if (arg instanceof long[])\n"
 754                 + "                {\n"
 755                 + "                    long[] array = (long[]) arg;\n"
 756                 + "                    for (int i = 0; i < array.length; i++)\n"
 757                 + "                    {\n"
 758                 + "                        result += print(array[i]);\n"
 759                 + "                        if (i < array.length - 1) result += delimiter;\n"
 760                 + "                    }\n"
 761                 + "                }\n"
 762                 + "                else\n"
 763                 + "                if (arg instanceof float[])\n"
 764                 + "                {\n"
 765                 + "                    float[] array = (float[]) arg;\n"
 766                 + "                    for (int i = 0; i < array.length; i++)\n"
 767                 + "                    {\n"
 768                 + "                        result += print(array[i]);\n"
 769                 + "                        if (i < array.length - 1) result += delimiter;\n"
 770                 + "                    }\n"
 771                 + "                }\n"
 772                 + "                else\n"
 773                 + "                if (arg instanceof double[])\n"
 774                 + "                {\n"
 775                 + "                    double[] array = (double[]) arg;\n"
 776                 + "                    for (int i = 0; i < array.length; i++)\n"
 777                 + "                    {\n"
 778                 + "                        result += print(array[i]);\n"
 779                 + "                        if (i < array.length - 1) result += delimiter;\n"
 780                 + "                    }\n"
 781                 + "                }\n"
 782                 + "\n"
 783                 + "                result += \"]\";\n"
 784                 + "                visitedObjects.pop();\n"
 785                 + "\n"
 786                 + "            } else\n"
 787                 + "            {\n"
 788                 + "                result += arg.toString();\n"
 789                 + "            }\n"
 790                 + "\n"
 791                 + "            return result;\n"
 792                 + "        }\n"
 793                 + "    }\n";
 794 
 795         return (ProductionParams.enableStrictFP.value() ? "strictfp " : "")
 796                 + "public class " + name + " {\n"
 797                 + dataMembers.accept(this)+ "\n"
 798                 + (memberFunctions != null ? memberFunctions.accept(this): "") + "\n"
 799                 + executeFunction
 800                 + "\n"
 801                 + mainFunction
 802                 + "\n"
 803                 + "    private void test()\n"
 804                 + "    {\n"
 805                 + testFunction.accept(this)
 806                 + "    }" + addComplexityInfo(testFunction) + "\n"
 807                 + "    public String toString()\n"
 808                 + "    {\n"
 809                 + printVariables.accept(this)
 810                 + "    }\n"
 811                 + printerClass
 812                 + "}\n\n";
 813     }
 814 
 815     @Override
 816     public String visit(NonStaticMemberVariable node) {
 817         IRNode object = node.getChild(0);
 818         String objectString = object.accept(this);
 819         VariableInfo value = node.getValue();
 820         if (objectString.equals("this")) {
 821             return value.name;
 822         } else {
 823             if (object instanceof VariableBase || object instanceof Function || object instanceof Literal) {
 824                 return objectString + "." + value.name;
 825             } else {
 826                 return "(" + objectString + ")" + "." + value.name;
 827             }
 828         }
 829     }
 830 
 831     @Override
 832     public String visit(Nothing node) {
 833         return "";
 834     }
 835 
 836     @Override
 837     public String visit(PrintVariables node) {
 838         int level = node.getLevel();
 839         List<Symbol> vars = node.getVars();
 840         StringBuilder result = new StringBuilder()
 841                 .append(PrintingUtils.align(level))
 842                 .append("String result =  \"[\\n\";\n");
 843         if (!vars.isEmpty()) {
 844             for (int i = 0; i < vars.size(); i++) {
 845                 Symbol v = vars.get(i);
 846                 result.append(PrintingUtils.align(level))
 847                         .append("result += \"").append(v.klass.getName())
 848                         .append(".")
 849                         .append(v.name)
 850                         .append(" = \"; ")
 851                         .append("result += ")
 852                         .append(node.getPrinterName())
 853                         .append(".print(")
 854                         .append(v.name)
 855                         .append(");\n")
 856                         .append(PrintingUtils.align(level));
 857                 if (i < vars.size() - 1) {
 858                     result.append("result += \"\\n\";");
 859                 } else {
 860                     result.append("result += \"\";");
 861                 }
 862                 result.append("\n");
 863             }
 864         }
 865         result.append(PrintingUtils.align(level))
 866                 .append("result += \"\\n]\";\n")
 867                 .append(PrintingUtils.align(level))
 868                 .append("return result;\n");
 869         return result.toString();
 870     }
 871 
 872     @Override
 873     public String visit(Return node) {
 874         return "return " + node.getExpression().accept(this) + ";";
 875     }
 876 
 877     @Override
 878     public String visit(Throw node) {
 879         return "throw " + node.getThowable().accept(this) + ";";
 880     }
 881 
 882     @Override
 883     public String visit(Statement node) {
 884         return node.getChild(0).accept(this)+ (node.isSemicolonNeeded() ? ";" : "");
 885     }
 886 
 887     @Override
 888     public String visit(StaticConstructorDefinition node) {
 889         IRNode body = node.getChild(0);
 890         return "static {\n"
 891                 + (body != null ? body.accept(this): "")
 892                 + PrintingUtils.align(node.getLevel()) + "}";
 893     }
 894 
 895     @Override
 896     public String visit(StaticMemberVariable node) {
 897         IRNode klass = node.getKlass();
 898         VariableInfo value = node.get();
 899         if (klass.equals(value.klass)) {
 900             return value.name;
 901         } else {
 902             return value.klass.getName() + "." + value.name;
 903         }
 904     }
 905 
 906     @Override
 907     public String visit(Switch node) {
 908         int level = node.getLevel();
 909         int caseBlockIdx = node.getCaseBlockIndex();
 910         String cases = "";
 911         for (int i = 0; i < caseBlockIdx - 1; ++i) {
 912             cases += PrintingUtils.align(level + 1);
 913             if (node.getChild(i + 1) != null) {
 914                 cases += "case " + node.getChild(i + 1).accept(this)+ ":\n";
 915             } else {
 916                 cases += "default:\n";
 917             }
 918 
 919             cases += node.getChild(i + caseBlockIdx).accept(this)+ "\n";
 920         }
 921         return "switch (" + node.getChild(0).accept(this)+ ")\n"
 922                + PrintingUtils.align(level) + "{\n"
 923                + cases
 924                + PrintingUtils.align(level) + "}";
 925     }
 926 
 927     @Override
 928     public String visit(TernaryOperator node) {
 929         IRNode conditionalExp = node.getChild(TernaryOperator.TernaryPart.CONDITION.ordinal());
 930         IRNode leftExp = node.getChild(TernaryOperator.TernaryPart.TRUE.ordinal());
 931         IRNode rightExp = node.getChild(TernaryOperator.TernaryPart.FALSE.ordinal());
 932         if (Objects.isNull(conditionalExp) || Objects.isNull(leftExp) || Objects.isNull(rightExp)) {
 933             return "null";
 934         }
 935         return expressionToJavaCode(node, conditionalExp, Operator.Order.RIGHT) + " ? "
 936                 + expressionToJavaCode(node, leftExp, Operator.Order.RIGHT) + " : "
 937                 + expressionToJavaCode(node, rightExp, Operator.Order.RIGHT);
 938     }
 939 
 940     @Override
 941     public String visit(Type node) {
 942         return node.getName();
 943     }
 944 
 945     @Override
 946     public String visit(TypeArray node) {
 947         String r = node.getType().accept(this);
 948         for (int i = 0; i < node.getDimensions(); i++) {
 949             r += "[]";
 950         }
 951         return r;
 952     }
 953 
 954     @Override
 955     public String visit(UnaryOperator node) {
 956         IRNode exp = node.getChild(0);
 957         if (node.isPrefix()) {
 958             return node.getOperatorText() + (exp instanceof Operator ? " " : "")
 959                     + expressionToJavaCode(node, exp, Operator.Order.LEFT);
 960         } else {
 961             return expressionToJavaCode(node, exp, Operator.Order.RIGHT)
 962                     + (exp instanceof Operator ? " " : "") + node.getOperatorText();
 963         }
 964     }
 965 
 966     @Override
 967     public String visit(VariableDeclaration node) {
 968         VariableInfo vi = node.getVariableInfo();
 969         return attributes(vi) + vi.type.accept(this)+ " " + vi.name;
 970     }
 971 
 972     @Override
 973     public String visit(VariableDeclarationBlock node) {
 974         StringBuilder code = new StringBuilder();
 975         for (IRNode i : node.getChildren()) {
 976             code.append(PrintingUtils.align(node.getLevel()))
 977                 .append(i.accept(this))
 978                 .append(addComplexityInfo(i))
 979                 .append("\n");
 980         }
 981         return code.toString();
 982     }
 983 
 984     @Override
 985     public String visit(While node) {
 986         IRNode header = node.getChild(While.WhilePart.HEADER.ordinal());
 987         IRNode body1 = node.getChild(While.WhilePart.BODY1.ordinal());
 988         IRNode body2 = node.getChild(While.WhilePart.BODY2.ordinal());
 989         IRNode body3 = node.getChild(While.WhilePart.BODY3.ordinal());
 990         int level = node.getLevel();
 991         Loop loop = node.getLoop();
 992         return loop.initialization.accept(this)+ "\n"
 993                 + header.accept(this)
 994                 + PrintingUtils.align(level) + "while (" + loop.condition.accept(this)+ ")\n"
 995                 + PrintingUtils.align(level) + "{\n"
 996                 + body1.accept(this)
 997                 + PrintingUtils.align(level + 1) + loop.manipulator.accept(this)+ ";\n"
 998                 + body2.accept(this)
 999                 + body3.accept(this)
1000                 + PrintingUtils.align(level) + "}";
1001     }
1002 
1003     @Override
1004     public String visit(CatchBlock node) {
1005         StringBuilder result = new StringBuilder();
1006         int level = node.getLevel();
1007         result.append(PrintingUtils.align(level)).append("catch(");
1008         result.append(node.throwables.get(0).accept(this));
1009         for (int i = 1; i < node.throwables.size(); i++) {
1010             result.append(" | ").append(node.throwables.get(i).accept(this));
1011         }
1012         result.append(" ex) {\n");
1013         result.append(node.getChild(0).accept(this));
1014         result.append(PrintingUtils.align(level)).append("}\n");
1015         return result.toString();
1016     }
1017 
1018     @Override
1019     public String visit(TryCatchBlock node) {
1020         StringBuilder result = new StringBuilder();
1021         List<? extends IRNode> childs = node.getChildren();
1022         IRNode body = childs.get(0);
1023         IRNode finallyBody = childs.get(1);
1024         int level = node.getLevel();
1025         result.append("try {\n")
1026                 .append(body.accept(this)).append("\n")
1027                 .append(PrintingUtils.align(level)).append("}\n");
1028         for (int i = 2; i < childs.size(); i++) {
1029             result.append(childs.get(i).accept(this));
1030         }
1031         if (finallyBody != null) {
1032             result.append(PrintingUtils.align(level)).append("finally {\n")
1033                     .append(finallyBody.accept(this)).append("\n")
1034                     .append(PrintingUtils.align(level)).append("}\n");
1035         }
1036         return result.toString();
1037     }
1038 }