/* * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.test.lib.jittester.visitors; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.stream.Collectors; import jdk.test.lib.jittester.BinaryOperator; import jdk.test.lib.jittester.Block; import jdk.test.lib.jittester.Break; import jdk.test.lib.jittester.CastOperator; import jdk.test.lib.jittester.CatchBlock; import jdk.test.lib.jittester.Continue; import jdk.test.lib.jittester.Declaration; import jdk.test.lib.jittester.IRNode; import jdk.test.lib.jittester.If; import jdk.test.lib.jittester.Initialization; import jdk.test.lib.jittester.Literal; import jdk.test.lib.jittester.LocalVariable; import jdk.test.lib.jittester.NonStaticMemberVariable; import jdk.test.lib.jittester.Nothing; import jdk.test.lib.jittester.Operator; import jdk.test.lib.jittester.OperatorKind; import jdk.test.lib.jittester.PrintVariables; import jdk.test.lib.jittester.ProductionParams; import jdk.test.lib.jittester.Statement; import jdk.test.lib.jittester.StaticMemberVariable; import jdk.test.lib.jittester.Switch; import jdk.test.lib.jittester.Symbol; import jdk.test.lib.jittester.TernaryOperator; import jdk.test.lib.jittester.Throw; import jdk.test.lib.jittester.TryCatchBlock; import jdk.test.lib.jittester.Type; import jdk.test.lib.jittester.TypeList; import jdk.test.lib.jittester.UnaryOperator; import jdk.test.lib.jittester.VariableBase; import jdk.test.lib.jittester.VariableDeclaration; import jdk.test.lib.jittester.VariableDeclarationBlock; import jdk.test.lib.jittester.VariableInfo; import jdk.test.lib.jittester.arrays.ArrayCreation; import jdk.test.lib.jittester.arrays.ArrayElement; import jdk.test.lib.jittester.arrays.ArrayExtraction; import jdk.test.lib.jittester.classes.ClassDefinitionBlock; import jdk.test.lib.jittester.classes.Interface; import jdk.test.lib.jittester.classes.Klass; import jdk.test.lib.jittester.classes.MainKlass; import jdk.test.lib.jittester.functions.ArgumentDeclaration; import jdk.test.lib.jittester.functions.ConstructorDefinition; import jdk.test.lib.jittester.functions.ConstructorDefinitionBlock; import jdk.test.lib.jittester.functions.Function; import jdk.test.lib.jittester.functions.FunctionDeclaration; import jdk.test.lib.jittester.functions.FunctionDeclarationBlock; import jdk.test.lib.jittester.functions.FunctionDefinition; import jdk.test.lib.jittester.functions.FunctionDefinitionBlock; import jdk.test.lib.jittester.functions.FunctionInfo; import jdk.test.lib.jittester.functions.FunctionRedefinition; import jdk.test.lib.jittester.functions.FunctionRedefinitionBlock; import jdk.test.lib.jittester.functions.Return; import jdk.test.lib.jittester.functions.StaticConstructorDefinition; import jdk.test.lib.jittester.loops.CounterInitializer; import jdk.test.lib.jittester.loops.CounterManipulator; import jdk.test.lib.jittester.loops.DoWhile; import jdk.test.lib.jittester.loops.For; import jdk.test.lib.jittester.loops.Loop; import jdk.test.lib.jittester.loops.LoopingCondition; import jdk.test.lib.jittester.loops.While; import jdk.test.lib.jittester.types.TypeArray; import jdk.test.lib.jittester.types.TypeKlass; import jdk.test.lib.jittester.utils.FixedTrees; import jdk.test.lib.jittester.utils.PrintingUtils; public class JavaCodeVisitor implements Visitor<String> { public static String funcAttributes(FunctionInfo fi) { String attrs = attributes(fi); if (fi.isSynchronized()) { attrs += "synchronized "; } return attrs; } public static String attributes(Symbol s) { String attrs = ""; if (s.isPrivate()) { attrs += "private "; } if (s.isProtected()) { attrs += "protected "; } if (s.isPublic()) { attrs += "public "; } if (s.isFinal()) { attrs += "final "; } if (s.isStatic()) { attrs += "static "; } return attrs; } private String operatorToJaveCode(OperatorKind operationKind) { switch (operationKind) { case COMPOUND_ADD: return "+="; case COMPOUND_SUB: return "-="; case COMPOUND_MUL: return "*="; case COMPOUND_DIV: return "/="; case COMPOUND_MOD: return "%="; case COMPOUND_AND: return "&="; case COMPOUND_OR: return "|="; case COMPOUND_XOR: return "^="; case COMPOUND_SHR: return ">>="; case COMPOUND_SHL: return "<<="; case COMPOUND_SAR: return ">>>="; case ASSIGN: return "="; case OR: return "||"; case BIT_OR: return "|"; case BIT_XOR: return "^"; case AND: return "&&"; case BIT_AND: return "&"; case EQ: return "=="; case NE: return "!="; case GT: return ">"; case LT: return "<"; case GE: return ">="; case LE: return "<="; case SHR: return ">>"; case SHL: return "<<"; case SAR: return ">>>"; case ADD: case STRADD: return "+"; case SUB: return "-"; case MUL: return "*"; case DIV: return "/"; case MOD: return "%"; case NOT: return "!"; case BIT_NOT: return "~"; case UNARY_PLUS: return "+"; case UNARY_MINUS: return "-"; case PRE_DEC: case POST_DEC: return "--"; case PRE_INC: case POST_INC: return "++"; default: throw new IllegalArgumentException("Unkown operator kind " + operationKind); } } private String expressionToJavaCode(Operator t, IRNode p, Operator.Order o) { String result; try { if ((o == Operator.Order.LEFT && ((Operator) p).getPriority() < t.getPriority()) || (o == Operator.Order.RIGHT && ((Operator) p).getPriority() <= t.getPriority())) { result = "(" + p.accept(this)+ ")"; } else { result = p.accept(this); } } catch (Exception e) { result = p.accept(this); } return result; } @Override public String visit(ArgumentDeclaration node) { VariableInfo vi = node.variableInfo; return attributes(vi) + vi.type.accept(this) + " " + vi.name; } @Override public String visit(ArrayCreation node) { Type arrayElemType = node.getArrayType().type; String type = arrayElemType.accept(this); String name = node.getVariable().getName(); StringBuilder code = new StringBuilder() .append(node.getVariable().accept(this)) .append(";\n") .append(PrintingUtils.align(node.getParent().getLevel())) .append(name) .append(" = new ") .append(type); code.append(node.getChildren().stream() .map(p -> p.accept(this)) .collect(Collectors.joining("][", "[", "]"))); code.append(";\n"); if (!TypeList.isBuiltIn(arrayElemType)) { code.append(PrintingUtils.align(node.getParent().getLevel())) .append("java.util.Arrays.fill(") .append(name) .append(", new ") .append(type) .append("());\n"); } return code.toString(); } @Override public String visit(ArrayElement node) { IRNode array = node.getChild(0); StringBuilder code = new StringBuilder(); if (array instanceof VariableBase || array instanceof Function) { code.append(array.accept(this)); } else { code.append("(") .append(array.accept(this)) .append(")"); } code.append(node.getChildren().stream() .skip(1) .map(c -> c.accept(this)) .collect(Collectors.joining("][", "[", "]"))); return code.toString(); } @Override public String visit(ArrayExtraction node) { IRNode array = node.getChild(0); StringBuilder code = new StringBuilder(); if (array instanceof VariableBase || array instanceof Function) { code.append(array.accept(this)); } else { code.append("(") .append(array.accept(this)) .append(")"); } code.append(node.getChildren().stream() .skip(1) .map(c -> c.accept(this)) .collect(Collectors.joining("][", "[", "]"))); return code.toString(); } @Override public String visit(BinaryOperator node) { IRNode left = node.getChild(Operator.Order.LEFT.ordinal()); IRNode right = node.getChild(Operator.Order.RIGHT.ordinal()); if (left == null || right == null) { return "null"; } return expressionToJavaCode(node, left, Operator.Order.LEFT) + " " + operatorToJaveCode(node.getOperationKind()) + " " + expressionToJavaCode(node, right, Operator.Order.RIGHT); } @Override public String visit(Block node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { String s = i.accept(this); if (!s.isEmpty()) { int level = node.getLevel(); if (i instanceof Block) { code.append(PrintingUtils.align(level + 1)) .append("{\n") .append(s) .append(PrintingUtils.align(level + 1)) .append("}"); } else { code.append(PrintingUtils.align(level + 1)) .append(s); } code.append(addComplexityInfo(i)); code.append("\n"); } } return code.toString(); } private String addComplexityInfo(IRNode node) { if (ProductionParams.printComplexity.value()) { return " /* " + node.complexity() + " */"; } return ""; } @Override public String visit(Break node) { return "break;"; } @Override public String visit(CastOperator node) { return "(" + node.getResultType().accept(this)+ ")" + expressionToJavaCode(node, node.getChild(0), Operator.Order.LEFT); } @Override public String visit(ClassDefinitionBlock node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { code.append("\n") .append(PrintingUtils.align(node.getLevel())) .append(i.accept(this)) .append("\n"); } return code.toString(); } @Override public String visit(ConstructorDefinition node) { String args = node.getChildren().stream() .skip(1) .map(c -> c.accept(this)) .collect(Collectors.joining(", ")); IRNode body = node.getChild(0); StringBuilder code = new StringBuilder(); code.append(funcAttributes(node.getFunctionInfo())) .append(node.getFunctionInfo().name) .append("(") .append(args) .append(")\n") .append(PrintingUtils.align(node.getLevel() + 1)) .append("{\n") .append(body != null ? body.accept(this) : "") .append(PrintingUtils.align(node.getLevel() + 1)) .append("}"); return code.toString(); } @Override public String visit(ConstructorDefinitionBlock node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { code.append("\n") .append(PrintingUtils.align(node.getLevel())) .append(i.accept(this)) .append(addComplexityInfo(i)) .append("\n"); } return code.toString(); } @Override public String visit(Continue node) { return "continue;"; } @Override public String visit(CounterInitializer node) { VariableInfo vi = node.getVariableInfo(); return vi.type.accept(this) + " " + vi.name + " = " + node.getChild(0).accept(this)+ ";"; } @Override public String visit(CounterManipulator node) { return node.getChild(0).accept(this); } @Override public String visit(Declaration node) { return node.getChild(0).accept(this)+ ";"; } @Override public String visit(DoWhile node) { IRNode header = node.getChild(DoWhile.DoWhilePart.HEADER.ordinal()); IRNode body1 = node.getChild(DoWhile.DoWhilePart.BODY1.ordinal()); IRNode body2 = node.getChild(DoWhile.DoWhilePart.BODY2.ordinal()); StringBuilder code = new StringBuilder(); Loop loop = node.getLoop(); int level = node.getLevel(); code.append(loop.initialization.accept(this)) .append("\n") .append(header.accept(this)) .append(PrintingUtils.align(level)) .append("do\n") .append(PrintingUtils.align(level)) .append("{\n") .append(body1.accept(this)) .append(PrintingUtils.align(level + 1)) .append(loop.manipulator.accept(this)) .append(";\n") .append(body2.accept(this)) .append(PrintingUtils.align(level)) .append("} while (") .append(loop.condition.accept(this)) .append(");"); return code.toString(); } @Override public String visit(For node) { IRNode header = node.getChild(For.ForPart.HEADER.ordinal()); IRNode statement1 = node.getChild(For.ForPart.STATEMENT1.ordinal()); IRNode statement2 = node.getChild(For.ForPart.STATEMENT2.ordinal()); IRNode body1 = node.getChild(For.ForPart.BODY1.ordinal()); IRNode body2 = node.getChild(For.ForPart.BODY2.ordinal()); IRNode body3 = node.getChild(For.ForPart.BODY3.ordinal()); Loop loop = node.getLoop(); StringBuilder code = new StringBuilder(); int level = node.getLevel(); code.append(loop.initialization.accept(this)) .append("\n") .append(header.accept(this)) .append(PrintingUtils.align(level)) .append("for (") .append(statement1.accept(this)) .append("; ") .append(loop.condition.accept(this)) .append("; ") .append(statement2.accept(this)) .append(")\n") .append(PrintingUtils.align(level)) .append("{\n") .append(body1.accept(this)) .append(PrintingUtils.align(level + 1)) .append(loop.manipulator.accept(this)) .append(";\n") .append(body2.accept(this)) .append(body3.accept(this)) .append(PrintingUtils.align(level)) .append("}"); return code.toString(); } @Override public String visit(Function node) { FunctionInfo value = node.getValue(); String nameAndArgs = value.name + "(" + node.getChildren().stream() .skip(value.isStatic() || value.isConstructor() ? 0 : 1) .map(c -> c.accept(this)) .collect(Collectors.joining(", ")) + ")"; String prefix = ""; if (value.isStatic()) { if(!node.getOwner().equals(value.owner)) { prefix = value.owner.getName() + "."; } } else if (value.isConstructor()) { prefix = "new "; } else { IRNode object = node.getChild(0); String objectString = object.accept(this); if (!objectString.equals("this")) { if (object instanceof VariableBase || object instanceof Function || object instanceof Literal) { prefix = objectString + "."; } else { prefix = "(" + objectString + ")" + "."; } } } return prefix + nameAndArgs; } @Override public String visit(FunctionDeclaration node) { String args = node.getChildren().stream() .map(c -> c.accept(this)) .collect(Collectors.joining(", ")); FunctionInfo functionInfo = node.getFunctionInfo(); return (functionInfo.owner.isInterface() ? "" : "abstract ") + funcAttributes(functionInfo) + functionInfo.type.accept(this)+ " " + functionInfo.name + "(" + args + ");"; } @Override public String visit(FunctionDeclarationBlock node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { code.append(PrintingUtils.align(node.getLevel())) .append(i.accept(this)) .append(addComplexityInfo(i)) .append("\n"); } return code.toString(); } @Override public String visit(FunctionDefinition node) { String args = node.getChildren().stream() .skip(2) .map(c -> c.accept(this)) .collect(Collectors.joining(", ")); IRNode body = node.getChild(0); IRNode ret = node.getChild(1); FunctionInfo functionInfo = node.getFunctionInfo(); return funcAttributes(functionInfo) + functionInfo.type.accept(this) + " " + functionInfo.name + "(" + args + ")" + "\n" + PrintingUtils.align(node.getLevel() + 1) + "{\n" + body.accept(this) + (ret != null ? PrintingUtils.align(node.getLevel() + 2) + ret.accept(this) + "\n" : "") + PrintingUtils.align(node.getLevel() + 1) + "}\n"; } @Override public String visit(FunctionDefinitionBlock node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { code.append("\n") .append(PrintingUtils.align(node.getLevel())) .append(i.accept(this)) .append(addComplexityInfo(i)) .append("\n"); } return code.toString(); } @Override public String visit(FunctionRedefinition node) { String args = node.getChildren().stream() .skip(2) .map(c -> c.accept(this)) .collect(Collectors.joining(", ")); IRNode body = node.getChild(0); IRNode ret = node.getChild(1); int level = node.getLevel(); FunctionInfo functionInfo = node.getFunctionInfo(); return funcAttributes(functionInfo) + functionInfo.type.accept(this) + " " + functionInfo.name + "(" + args + ")" + "\n" + PrintingUtils.align(level + 1) + "{\n" + body.accept(this) + (ret != null ? PrintingUtils.align(level + 2) + ret.accept(this) + "\n" : "") + PrintingUtils.align(level + 1) + "}"; } @Override public String visit(FunctionRedefinitionBlock node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { code.append("\n") .append(PrintingUtils.align(node.getLevel())) .append(i.accept(this)) .append(addComplexityInfo(i)) .append("\n"); } return code.toString(); } @Override public String visit(If node) { int level = node.getLevel(); String thenBlockString = PrintingUtils.align(level) + "{\n" + node.getChild(If.IfPart.THEN.ordinal()).accept(this) + PrintingUtils.align(level) + "}"; String elseBlockString = null; if (node.getChild(If.IfPart.ELSE.ordinal()) != null) { elseBlockString = PrintingUtils.align(level) + "{\n" + node.getChild(If.IfPart.ELSE.ordinal()).accept(this) + PrintingUtils.align(level) + "}"; } return "if (" + node.getChild(If.IfPart.CONDITION.ordinal()).accept(this)+ ")\n" + thenBlockString + (elseBlockString != null ? "\n" + PrintingUtils.align(level) + "else\n" + elseBlockString : ""); } @Override public String visit(Initialization node) { VariableInfo vi = node.getVariableInfo(); return attributes(vi) + vi.type.accept(this)+ " " + vi.name + " = " + node.getChild(0).accept(this); } @Override public String visit(Interface node) { return "interface " + node.getName() + (node.getParentKlass() != null ? " extends " + node.getParentKlass().getName() : "") + " {\n" + (node.getChildren().size() > 0 ? node.getChild(0).accept(this) : "") + "}\n"; } @Override public String visit(Klass node) { TypeKlass thisKlass = node.getThisKlass(); String r = (ProductionParams.enableStrictFP.value() ? "strictfp " : "") + (thisKlass.isFinal() ? "final " : "") + (thisKlass.isAbstract() ? "abstract " : "") + "class " + node.getName() + (node.getParentKlass() != null && !node.getParentKlass().equals(TypeList.OBJECT) ? " extends " + node.getParentKlass().getName() : ""); List<TypeKlass> interfaces = node.getInterfaces(); r += interfaces.stream() .map(Type::getName) .collect(Collectors.joining(", ", (interfaces.isEmpty() ? "" : " implements "), "")); IRNode dataMembers = node.getChild(Klass.KlassPart.DATA_MEMBERS.ordinal()); IRNode constructors = node.getChild(Klass.KlassPart.CONSTRUCTORS.ordinal()); IRNode redefinedFunctions = node.getChild(Klass.KlassPart.REDEFINED_FUNCTIONS.ordinal()); IRNode overridenFunctions = node.getChild(Klass.KlassPart.OVERRIDEN_FUNCTIONS.ordinal()); IRNode memberFunctions = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS.ordinal()); IRNode memberFunctionDecls = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS_DECLARATIONS.ordinal()); IRNode printVariables = node.getChild(Klass.KlassPart.PRINT_VARIABLES.ordinal()); r += " {\n" + (dataMembers != null ? (dataMembers.accept(this)+ "\n") : "") + (constructors != null ? (constructors.accept(this)+ "\n") : "") + (redefinedFunctions != null ? (redefinedFunctions.accept(this)+ "\n") : "") + (overridenFunctions != null ? (overridenFunctions.accept(this)+ "\n") : "") + (memberFunctionDecls != null ? (memberFunctionDecls.accept(this)+ "\n") : "") + (memberFunctions != null ? (memberFunctions.accept(this)+ "\n") : "") + printVariables.accept(this) + "}\n"; return r; } @Override public String visit(Literal node) { Type resultType = node.getResultType(); Object value = node.getValue(); if (resultType.equals(TypeList.LONG)) { return value.toString() + "L"; } if (resultType.equals(TypeList.FLOAT)) { return String.format((Locale) null, "%EF", Double.parseDouble(value.toString())); } if (resultType.equals(TypeList.DOUBLE)) { return String.format((Locale) null, "%E", Double.parseDouble(value.toString())); } if (resultType.equals(TypeList.CHAR)) { if ((Character) value == '\\') { return "\'" + "\\\\" + "\'"; } else { return "\'" + value.toString() + "\'"; } } if (resultType.equals(TypeList.SHORT)) { return "(short) " + value.toString(); } if (resultType.equals(TypeList.BYTE)) { return "(byte) " + value.toString(); } if (resultType.equals(TypeList.STRING)) { // TOOD handle other non-printable return "\"" + value.toString().replace("\n", "\\n") + "\""; } return value.toString(); } @Override public String visit(LocalVariable node) { return node.getVariableInfo().name; } @Override public String visit(LoopingCondition node) { return node.getCondition().accept(this); } @Override public String visit(MainKlass node) { String name = node.getName(); IRNode dataMembers = node.getChild(MainKlass.MainKlassPart.DATA_MEMBERS.ordinal()); IRNode memberFunctions = node.getChild(MainKlass.MainKlassPart.MEMBER_FUNCTIONS.ordinal()); IRNode testFunction = node.getChild(MainKlass.MainKlassPart.TEST_FUNCTION.ordinal()); IRNode printVariables = node.getChild(MainKlass.MainKlassPart.PRINT_VARIABLES.ordinal()); return (ProductionParams.enableStrictFP.value() ? "strictfp " : "") + "public class " + name + " {\n" + dataMembers.accept(this)+ "\n" + (memberFunctions != null ? memberFunctions.accept(this): "") + "\n" + " private void test()\n" + " {\n" + testFunction.accept(this) + " }" + addComplexityInfo(testFunction) + "\n" + printVariables.accept(this) + "}\n\n"; } @Override public String visit(NonStaticMemberVariable node) { IRNode object = node.getChild(0); String objectString = object.accept(this); VariableInfo value = node.getVariableInfo(); if (objectString.equals("this")) { return value.name; } else { if (object instanceof VariableBase || object instanceof Function || object instanceof Literal) { return objectString + "." + value.name; } else { return "(" + objectString + ")" + "." + value.name; } } } @Override public String visit(Nothing node) { return ""; } @Override public String visit(PrintVariables node) { return FixedTrees.printVariablesAsFunction(node).accept(this); } @Override public String visit(Return node) { return "return " + node.getExpression().accept(this) + ";"; } @Override public String visit(Throw node) { return "throw " + node.getThowable().accept(this) + ";"; } @Override public String visit(Statement node) { return node.getChild(0).accept(this)+ (node.isSemicolonNeeded() ? ";" : ""); } @Override public String visit(StaticConstructorDefinition node) { IRNode body = node.getChild(0); return "static {\n" + (body != null ? body.accept(this): "") + PrintingUtils.align(node.getLevel()) + "}"; } @Override public String visit(StaticMemberVariable node) { IRNode owner = node.getOwner(); VariableInfo info = node.getVariableInfo(); if (owner.equals(info.owner)) { return info.name; } else { return info.owner.getName() + "." + info.name; } } @Override public String visit(Switch node) { int level = node.getLevel(); int caseBlockIdx = node.getCaseBlockIndex(); String cases = ""; for (int i = 0; i < caseBlockIdx - 1; ++i) { cases += PrintingUtils.align(level + 1); if (node.getChild(i + 1) instanceof Nothing) { cases += "default:\n"; } else { cases += "case " + node.getChild(i + 1).accept(this)+ ":\n"; } cases += node.getChild(i + caseBlockIdx).accept(this)+ "\n"; } return "switch (" + node.getChild(0).accept(this)+ ")\n" + PrintingUtils.align(level) + "{\n" + cases + PrintingUtils.align(level) + "}"; } @Override public String visit(TernaryOperator node) { IRNode conditionalExp = node.getChild(TernaryOperator.TernaryPart.CONDITION.ordinal()); IRNode leftExp = node.getChild(TernaryOperator.TernaryPart.TRUE.ordinal()); IRNode rightExp = node.getChild(TernaryOperator.TernaryPart.FALSE.ordinal()); if (Objects.isNull(conditionalExp) || Objects.isNull(leftExp) || Objects.isNull(rightExp)) { return "null"; } return expressionToJavaCode(node, conditionalExp, Operator.Order.RIGHT) + " ? " + expressionToJavaCode(node, leftExp, Operator.Order.RIGHT) + " : " + expressionToJavaCode(node, rightExp, Operator.Order.RIGHT); } @Override public String visit(Type node) { return node.getName(); } @Override public String visit(TypeArray node) { String r = node.getType().accept(this); for (int i = 0; i < node.getDimensions(); i++) { r += "[]"; } return r; } @Override public String visit(UnaryOperator node) { IRNode exp = node.getChild(0); if (node.isPrefix()) { return operatorToJaveCode(node.getOperationKind()) + (exp instanceof Operator ? " " : "") + expressionToJavaCode(node, exp, Operator.Order.LEFT); } else { return expressionToJavaCode(node, exp, Operator.Order.RIGHT) + (exp instanceof Operator ? " " : "") + operatorToJaveCode(node.getOperationKind()); } } @Override public String visit(VariableDeclaration node) { VariableInfo vi = node.getVariableInfo(); return attributes(vi) + vi.type.accept(this)+ " " + vi.name; } @Override public String visit(VariableDeclarationBlock node) { StringBuilder code = new StringBuilder(); for (IRNode i : node.getChildren()) { code.append(PrintingUtils.align(node.getLevel())) .append(i.accept(this)) .append(addComplexityInfo(i)) .append("\n"); } return code.toString(); } @Override public String visit(While node) { IRNode header = node.getChild(While.WhilePart.HEADER.ordinal()); IRNode body1 = node.getChild(While.WhilePart.BODY1.ordinal()); IRNode body2 = node.getChild(While.WhilePart.BODY2.ordinal()); IRNode body3 = node.getChild(While.WhilePart.BODY3.ordinal()); int level = node.getLevel(); Loop loop = node.getLoop(); return loop.initialization.accept(this)+ "\n" + header.accept(this) + PrintingUtils.align(level) + "while (" + loop.condition.accept(this)+ ")\n" + PrintingUtils.align(level) + "{\n" + body1.accept(this) + PrintingUtils.align(level + 1) + loop.manipulator.accept(this)+ ";\n" + body2.accept(this) + body3.accept(this) + PrintingUtils.align(level) + "}"; } @Override public String visit(CatchBlock node) { StringBuilder result = new StringBuilder(); int level = node.getLevel(); result.append(PrintingUtils.align(level)).append("catch("); result.append(node.throwables.get(0).accept(this)); for (int i = 1; i < node.throwables.size(); i++) { result.append(" | ").append(node.throwables.get(i).accept(this)); } result.append(" ex) {\n"); result.append(node.getChild(0).accept(this)); result.append(PrintingUtils.align(level)).append("}\n"); return result.toString(); } @Override public String visit(TryCatchBlock node) { StringBuilder result = new StringBuilder(); List<? extends IRNode> childs = node.getChildren(); IRNode body = childs.get(0); IRNode finallyBody = childs.get(1); int level = node.getLevel(); result.append("try {\n") .append(body.accept(this)).append("\n") .append(PrintingUtils.align(level)) .append("}\n"); for (int i = 2; i < childs.size(); i++) { result.append(childs.get(i).accept(this)); } if (finallyBody != null) { String finallyContent = finallyBody.accept(this); if (!finallyContent.isEmpty()) { result.append(PrintingUtils.align(level)).append("finally {\n") .append(finallyContent).append("\n") .append(PrintingUtils.align(level)).append("}\n"); } } return result.toString(); } }