Java tutorial
package de.aschoerk.javaconv; import static com.github.javaparser.PositionUtils.sortByBeginPosition; import static com.github.javaparser.ast.internal.Utils.isNullOrEmpty; import static java.util.Collections.reverse; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.PackageDeclaration; import com.github.javaparser.ast.TypeParameter; import com.github.javaparser.ast.body.BodyDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.body.EmptyMemberDeclaration; import com.github.javaparser.ast.body.EmptyTypeDeclaration; import com.github.javaparser.ast.body.EnumConstantDeclaration; import com.github.javaparser.ast.body.EnumDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.InitializerDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.ModifierSet; import com.github.javaparser.ast.body.MultiTypeParameter; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.body.VariableDeclaratorId; import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.ast.comments.Comment; import com.github.javaparser.ast.comments.JavadocComment; import com.github.javaparser.ast.comments.LineComment; import com.github.javaparser.ast.expr.AnnotationExpr; import com.github.javaparser.ast.expr.ArrayAccessExpr; import com.github.javaparser.ast.expr.ArrayCreationExpr; import com.github.javaparser.ast.expr.ArrayInitializerExpr; import com.github.javaparser.ast.expr.AssignExpr; import com.github.javaparser.ast.expr.BinaryExpr; import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.CharLiteralExpr; import com.github.javaparser.ast.expr.ClassExpr; import com.github.javaparser.ast.expr.ConditionalExpr; import com.github.javaparser.ast.expr.DoubleLiteralExpr; import com.github.javaparser.ast.expr.EnclosedExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.InstanceOfExpr; import com.github.javaparser.ast.expr.IntegerLiteralExpr; import com.github.javaparser.ast.expr.IntegerLiteralMinValueExpr; import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.LongLiteralExpr; import com.github.javaparser.ast.expr.LongLiteralMinValueExpr; import com.github.javaparser.ast.expr.MemberValuePair; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.MethodReferenceExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.QualifiedNameExpr; import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.expr.SuperExpr; import com.github.javaparser.ast.expr.ThisExpr; import com.github.javaparser.ast.expr.TypeExpr; import com.github.javaparser.ast.expr.UnaryExpr; import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.AssertStmt; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.stmt.BreakStmt; import com.github.javaparser.ast.stmt.CatchClause; import com.github.javaparser.ast.stmt.ContinueStmt; import com.github.javaparser.ast.stmt.DoStmt; import com.github.javaparser.ast.stmt.EmptyStmt; import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.ForStmt; import com.github.javaparser.ast.stmt.ForeachStmt; import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.LabeledStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.stmt.SwitchEntryStmt; import com.github.javaparser.ast.stmt.SwitchStmt; import com.github.javaparser.ast.stmt.SynchronizedStmt; import com.github.javaparser.ast.stmt.ThrowStmt; import com.github.javaparser.ast.stmt.TryStmt; import com.github.javaparser.ast.stmt.TypeDeclarationStmt; import com.github.javaparser.ast.stmt.WhileStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.IntersectionType; import com.github.javaparser.ast.type.PrimitiveType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.type.UnionType; import com.github.javaparser.ast.type.UnknownType; import com.github.javaparser.ast.type.VoidType; import com.github.javaparser.ast.type.WildcardType; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; /* * Copyright (C) 2007-2010 Jlio Vilmar Gesser. Copyright (C) 2011, 2013-2015 The JavaParser Team. This file is part of JavaParser. JavaParser can be * used either under the terms of a) the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. b) the terms of the Apache License You should have received a copy of both licenses in LICENCE.LGPL * and LICENCE.APACHE. Please refer to those files for details. JavaParser 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 Lesser General Public License for * more details. */ @SuppressWarnings("Duplicates") /** * Dumps the AST to formatted Java source code. * * @author Julio Vilmar Gesser */ public class RustDumpVisitor extends VoidVisitorAdapter<Object> { static String[] mappedNames = { "NaN", "NAN", "NEGATIVE_INFINITY", "NEG_INFINITY", "POSITIVE_INFINITY", "INFINITY", "MIN_VALUE", "MIN", "MAX_VALUE", "MAX", }; static HashMap<String, String> namesMap = new HashMap<>(); static { for (int i = 0; i < mappedNames.length; i += 2) { namesMap.put(mappedNames[i], mappedNames[i + 1]); } } protected final SourcePrinter printer = createSourcePrinter(); private final IdTracker idTracker; private final TypeTrackerVisitor typeTracker; boolean commentOut = false; private boolean printComments; public RustDumpVisitor() { this(true, null, null); } public RustDumpVisitor(boolean printComments, IdTracker idTracker, TypeTrackerVisitor typeTrackerVisitor) { this.idTracker = idTracker; this.typeTracker = typeTrackerVisitor; this.printComments = printComments; } protected SourcePrinter createSourcePrinter() { return new SourcePrinter(" "); } public String getSource() { return printer.getSource(); } private String toSnakeIfNecessary(String n) { if (namesMap.containsKey(n)) { n = namesMap.get(n); } String name = n; if (Character.isLowerCase(name.charAt(0))) { StringBuilder sb = new StringBuilder(); for (Character c : name.toCharArray()) { if (Character.isUpperCase(c)) { sb.append("_").append(Character.toLowerCase(c)); } else { sb.append(c); } } return sb.toString(); } return n; } private String removePlusAndSuffix(String value, CharSequence... searchStrings) { if (value.startsWith("+")) { value = value.substring(1); } if (value.startsWith(".")) { value = "0" + value; } if (StringUtils.endsWithAny(value, searchStrings)) { value = value.substring(0, value.length() - 1); } if (value.endsWith(".")) { value = value + "0"; } value = value.replace("d.", "."); return value; } protected void printModifiers(final int modifiers) { if (ModifierSet.isPrivate(modifiers)) { if (commentOut) { printer.print("/* private */"); } } if (ModifierSet.isProtected(modifiers)) { if (commentOut) printer.print("/* protected */"); printer.print("pub "); } if (ModifierSet.isPublic(modifiers)) { printer.print("pub "); } if (ModifierSet.isAbstract(modifiers)) { if (commentOut) printer.print("/* abstract */"); } if (ModifierSet.isStatic(modifiers)) { if (commentOut) printer.print("/* static */"); } if (ModifierSet.isFinal(modifiers)) { if (commentOut) printer.print("/* final */"); } if (ModifierSet.isNative(modifiers)) { if (commentOut) printer.print("/* native */"); } if (ModifierSet.isStrictfp(modifiers)) { if (commentOut) printer.print("/* strictfp */"); } if (ModifierSet.isSynchronized(modifiers)) { if (commentOut) printer.print("/* synchronized */"); } if (ModifierSet.isTransient(modifiers)) { if (commentOut) printer.print("/* transient */"); } if (ModifierSet.isVolatile(modifiers)) { if (commentOut) printer.print("/* volatile */"); } } protected void printMembers(final List<BodyDeclaration> members, final Object arg, Function<BodyDeclaration, Boolean> filter) { for (final BodyDeclaration member : members) { if (filter == null || filter.apply(member)) { printer.printLn(); member.accept(this, arg); printer.printLn(); } } } protected void printTypeArgs(final List<Type> args, final Object arg) { if (!isNullOrEmpty(args)) { printer.print("<"); for (final Iterator<Type> i = args.iterator(); i.hasNext();) { final Type t = i.next(); t.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.print(">"); } } protected void printTypeParameters(final List<TypeParameter> args, final Object arg) { if (!isNullOrEmpty(args)) { printer.print("<"); for (final Iterator<TypeParameter> i = args.iterator(); i.hasNext();) { final TypeParameter t = i.next(); t.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.print(">"); } } protected void printArguments(final List<Expression> args, final Object arg) { printer.print("("); if (!isNullOrEmpty(args)) { for (final Iterator<Expression> i = args.iterator(); i.hasNext();) { final Expression e = i.next(); if (e instanceof NameExpr) { NameExpr ne = (NameExpr) e; Optional<Pair<TypeDescription, Node>> decl = idTracker.findDeclarationNodeFor(ne.getName(), ne); if (decl.isPresent() && decl.get().getLeft() != null) { final TypeDescription left = decl.get().getLeft(); if (!left.clazz.isPrimitive() || left.getArrayCount() > 0) { printer.print("&"); } } } else if (e instanceof MethodCallExpr) { printer.print("&"); } e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); } protected void printJavadoc(final JavadocComment javadoc, final Object arg) { if (javadoc != null) { javadoc.accept(this, arg); } } protected void printJavaComment(final Comment javacomment, final Object arg) { if (javacomment != null) { javacomment.accept(this, arg); } } @Override public void visit(final CompilationUnit n, final Object arg) { printJavaComment(n.getComment(), arg); /* if (n.getPackage() != null) { n.getPackage().accept(this, arg); } if (!isNullOrEmpty(n.getImports())) { for (final ImportDeclaration i : n.getImports()) { i.accept(this, arg); } printer.printLn(); } */ if (idTracker.hasThrows()) { printer.printLn("use std::rc::*;"); printer.printLn("use java::exc::*;"); } if (!isNullOrEmpty(n.getTypes())) { for (final Iterator<TypeDeclaration> i = n.getTypes().iterator(); i.hasNext();) { i.next().accept(this, arg); printer.printLn(); if (i.hasNext()) { printer.printLn(); } } } printOrphanCommentsEnding(n); } @Override public void visit(final PackageDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("package "); n.getName().accept(this, arg); printer.printLn(";"); printer.printLn(); printOrphanCommentsEnding(n); } @Override public void visit(final NameExpr n, final Object arg) { printJavaComment(n.getComment(), arg); Optional<Pair<TypeDescription, Node>> b = idTracker.findDeclarationNodeFor(n.getName(), n); if (b.isPresent() && (NodeEvaluator.isNonStaticFieldDeclaration(b.get().getRight()) && !idTracker.isInConstructor() || NodeEvaluator.isNonStaticMethodDeclaration(b.get().getRight()))) { printer.print("self."); } printer.print(toSnakeIfNecessary(n.getName())); printOrphanCommentsEnding(n); } @Override public void visit(final QualifiedNameExpr n, final Object arg) { printJavaComment(n.getComment(), arg); n.getQualifier().accept(this, arg); printer.print("::"); printer.print(n.getName()); printOrphanCommentsEnding(n); } @Override public void visit(final ImportDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("use "); if (n.isStatic()) { printer.print("/* static */"); } n.getName().accept(this, arg); if (n.isAsterisk()) { printer.print("::*"); } printer.printLn(";"); printOrphanCommentsEnding(n); } @Override public void visit(final ClassOrInterfaceDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); final boolean staticSearched[] = { true }; Function<BodyDeclaration, Boolean> selectFieldDeclarationBooleanFunction = mem -> { if (mem instanceof FieldDeclaration) { FieldDeclaration fd = (FieldDeclaration) mem; if (ModifierSet.isStatic(fd.getModifiers()) == staticSearched[0]) { return true; } else { return false; } } else { return false; } }; if (!isNullOrEmpty(n.getMembers())) { printMembers(n.getMembers(), arg, selectFieldDeclarationBooleanFunction); } if (!isNullOrEmpty(n.getImplements())) { printer.print("#[derive("); for (final Iterator<ClassOrInterfaceType> i = n.getImplements().iterator(); i.hasNext();) { final ClassOrInterfaceType c = i.next(); c.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.printLn(")]"); } printModifiers(n.getModifiers()); if (n.isInterface()) { printer.print("trait "); } else { printer.print("struct "); } printer.print(n.getName()); printTypeParameters(n.getTypeParameters(), arg); if (!isNullOrEmpty(n.getExtends())) { if (n.isInterface()) { printer.print(" : "); boolean first = true; for (ClassOrInterfaceType i : n.getExtends()) { if (first) first = false; else printer.print(" + "); i.accept(this, arg); } printer.printLn(" {"); printer.indent(); } else { printer.printLn(" {"); printer.indent(); int count = n.getExtends().size() > 1 ? 0 : -1; for (final Iterator<ClassOrInterfaceType> i = n.getExtends().iterator(); i.hasNext();) { final ClassOrInterfaceType c = i.next(); printer.print("super" + (count >= 0 ? ++count + "" : "") + ": "); c.accept(this, arg); printer.printLn(";"); } } } else { printer.printLn(" {"); printer.indent(); } staticSearched[0] = false; if (!isNullOrEmpty(n.getMembers())) { printMembers(n.getMembers(), arg, selectFieldDeclarationBooleanFunction); } printOrphanCommentsEnding(n); if (!n.isInterface()) { printer.unindent(); printer.printLn("}"); printer.printLn(""); printer.print("impl "); printer.print(n.getName()); printer.printLn(" {"); printer.indent(); } if (!isNullOrEmpty(n.getMembers())) { printMembers(n.getMembers(), arg, mem -> !(mem instanceof FieldDeclaration)); } printer.unindent(); printer.printLn("}"); } @Override public void visit(final EmptyTypeDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); printer.print(";"); printOrphanCommentsEnding(n); } @Override public void visit(final JavadocComment n, final Object arg) { printer.print("/**"); printer.print(n.getContent()); printer.printLn("*/"); } @Override public void visit(final ClassOrInterfaceType n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getScope() != null) { n.getScope().accept(this, arg); printer.print("."); } printer.print(n.getName()); if (n.isUsingDiamondOperator()) { printer.print("<>"); } else { printTypeArgs(n.getTypeArgs(), arg); } } @Override public void visit(final TypeParameter n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(n.getName()); if (!isNullOrEmpty(n.getTypeBound())) { printer.print(" extends "); for (final Iterator<ClassOrInterfaceType> i = n.getTypeBound().iterator(); i.hasNext();) { final ClassOrInterfaceType c = i.next(); c.accept(this, arg); if (i.hasNext()) { printer.print(" & "); } } } } @Override public void visit(final PrimitiveType n, final Object arg) { printJavaComment(n.getComment(), arg); switch (n.getType()) { case Boolean: printer.print("bool"); break; case Byte: printer.print("i8"); break; case Char: printer.print("char"); break; case Double: printer.print("f64"); break; case Float: printer.print("f32"); break; case Int: printer.print("i32"); break; case Long: printer.print("i64"); break; case Short: printer.print("i16"); break; } } @Override public void visit(final ReferenceType n, final Object arg) { printJavaComment(n.getComment(), arg); for (int i = 0; i < n.getArrayCount(); i++) { printer.print("Vec<"); } n.getType().accept(this, arg); for (int i = 0; i < n.getArrayCount(); i++) { printer.print(">"); } } @Override public void visit(final IntersectionType n, final Object arg) { printJavaComment(n.getComment(), arg); boolean isFirst = true; for (ReferenceType element : n.getElements()) { element.accept(this, arg); if (isFirst) { isFirst = false; } else { printer.print(" & "); } } } @Override public void visit(final UnionType n, final Object arg) { printJavaComment(n.getComment(), arg); boolean isFirst = true; for (ReferenceType element : n.getElements()) { element.accept(this, arg); if (isFirst) { isFirst = false; } else { printer.print(" | "); } } } @Override public void visit(final WildcardType n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("?"); if (n.getExtends() != null) { printer.print(" extends "); n.getExtends().accept(this, arg); } if (n.getSuper() != null) { printer.print(" super "); n.getSuper().accept(this, arg); } } @Override public void visit(final UnknownType n, final Object arg) { // Nothing to dump } @Override public void visit(final FieldDeclaration n, final Object arg) { printOrphanCommentsBeforeThisChildNode(n); printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); if (commentOut) { printer.printLn("/* "); printModifiers(n.getModifiers()); n.getType().accept(this, arg); printer.printLn(" */"); } printer.print(" "); for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext();) { final VariableDeclarator var = i.next(); var.accept(this, n.getType()); if (i.hasNext()) { printer.print(", "); } } printer.print(";"); } @Override public void visit(final VariableDeclarator n, final Object arg) { printJavaComment(n.getComment(), arg); String name = acceptAndCut(n.getId(), arg); boolean isConstant = false; if (Character.isUpperCase(name.charAt(0))) { printer.print("const "); isConstant = true; } else { printer.print("let "); if (idTracker.isChanged(name, n)) { printer.print("mut "); } } printer.print(name); boolean isInitializedArray = n.getInit() != null && (n.getInit() instanceof ArrayInitializerExpr || n.getInit() instanceof ArrayCreationExpr); if (arg instanceof Type && !isInitializedArray) { printer.print(": "); Type t = (Type) arg; String tmp = acceptAndCut(t, null); if (isConstant && tmp.equals("String")) { printer.print("&'static str"); } else { printer.print(tmp); } } if (n.getInit() != null) { if (!isInitializedArray) printer.print(" = "); n.getInit().accept(this, arg); } } @Override public void visit(final VariableDeclaratorId n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(toSnakeIfNecessary(n.getName())); } List<Integer> getDimensions(ArrayInitializerExpr n, Type t) { List<Integer> dimensions = new ArrayList<>(); Integer actsize = n.getValues().size(); while (n != null) { dimensions.add(actsize); actsize = null; Expression firstValue = n.getValues().get(0); if (firstValue instanceof ArrayInitializerExpr) { Integer size = null; for (Expression e : n.getValues()) { ArrayInitializerExpr ai = (ArrayInitializerExpr) e; if (size == null) { size = ai.getValues().size(); n = ai; } else { if (size < ai.getValues().size()) { size = ai.getValues().size(); n = ai; } } } actsize = size; } else { n = null; } } return dimensions; } String acceptAndCut(Node n, final Object arg) { int mark = printer.push(); n.accept(this, arg); String result = printer.getMark(mark); printer.pop(); return result; } String acceptAndCopy(Node n, final Object arg) { int mark = printer.push(); n.accept(this, arg); String result = printer.getMark(mark); printer.drop(); return result; } @Override public void visit(final ArrayInitializerExpr n, final Object arg) { Type t = arg instanceof Type ? (Type) arg : null; printJavaComment(n.getComment(), arg); if (!isNullOrEmpty(n.getValues())) { if (t != null) { List<Integer> dims = getDimensions(n, t); StringBuilder sb = new StringBuilder(); sb.append(acceptAndCut(t, arg)); reverse(dims); for (Integer i : dims) { sb.insert(0, "vec!["); sb.append("; ").append(i).append("]"); } printer.print(": "); printer.print(sb.toString()); printer.print(" = "); } printer.print("vec!["); for (Expression val : n.getValues()) { val.accept(this, null); printer.print(", "); } printer.printLn("]"); } } String defaultValue(String type) { switch (type) { case "f64": case "f32": return "0.0"; case "u64": case "u32": case "u16": case "u8": case "usize": case "i64": case "i32": case "i16": case "i8": return "0"; case "bool": return "false"; default: return "None"; } } @Override public void visit(final ArrayCreationExpr n, final Object arg) { printJavaComment(n.getComment(), arg); if (!isNullOrEmpty(n.getDimensions())) { String type = acceptAndCut(n.getType(), arg); String typeOrDefaultValue = defaultValue(type); if (typeOrDefaultValue.equals("None")) type = "Option<" + type + ">"; List<String> dims = n.getDimensions().stream().map(e -> acceptAndCut(e, arg)) .collect(Collectors.toList()); printer.print(": "); printer.print(getArrayDeclaration(type, dims)); printer.print(" = "); printer.print(getArrayDeclaration(typeOrDefaultValue, dims)); } else { printer.print(" "); n.getInitializer().accept(this, n.getType()); } } private String getArrayDeclaration(String typeOrDefaultValue, List<String> dims) { StringBuilder sb = new StringBuilder(); sb.append(typeOrDefaultValue); reverse(dims); for (String s : dims) { sb.insert(0, "["); sb.append("; ").append(s).append("]"); } reverse(dims); return sb.toString(); } @Override public void visit(final VoidType n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("void"); } @Override public void visit(final ArrayAccessExpr n, final Object arg) { printJavaComment(n.getComment(), arg); n.getName().accept(this, arg); printer.print("["); n.getIndex().accept(this, arg); printer.print("]"); } @Override public void visit(final AssignExpr n, final Object arg) { printJavaComment(n.getComment(), arg); n.getTarget().accept(this, arg); printer.print(" "); switch (n.getOperator()) { case assign: printer.print("="); break; case and: printer.print("&="); break; case or: printer.print("|="); break; case xor: printer.print("^="); break; case plus: printer.print("+="); break; case minus: printer.print("-="); break; case rem: printer.print("%="); break; case slash: printer.print("/="); break; case star: printer.print("*="); break; case lShift: printer.print("<<="); break; case rSignedShift: printer.print(">>="); break; case rUnsignedShift: printer.print(">>= /* >>>= */"); break; } printer.print(" "); n.getValue().accept(this, arg); } @Override public void visit(final BinaryExpr n, final Object arg) { if (String.class.equals(idTracker.getType(n))) { printStringExpression(n, arg); return; } printJavaComment(n.getComment(), arg); n.getLeft().accept(this, arg); printer.print(" "); switch (n.getOperator()) { case or: printer.print("||"); break; case and: printer.print("&&"); break; case binOr: printer.print("|"); break; case binAnd: printer.print("&"); break; case xor: printer.print("^"); break; case equals: printer.print("=="); break; case notEquals: printer.print("!="); break; case less: printer.print("<"); break; case greater: printer.print(">"); break; case lessEquals: printer.print("<="); break; case greaterEquals: printer.print(">="); break; case lShift: printer.print("<<"); break; case rSignedShift: printer.print(">>"); break; case rUnsignedShift: printer.print(">> /* >>> */"); break; case plus: printer.print("+"); break; case minus: printer.print("-"); break; case times: printer.print("*"); break; case divide: printer.print("/"); break; case remainder: printer.print("%"); break; } printer.print(" "); n.getRight().accept(this, arg); } List<Node> genStringExprSequence(BinaryExpr n) { List<Node> result = new ArrayList<>(); if (n.getOperator() == BinaryExpr.Operator.plus) { genStringPart(n.getLeft(), result); genStringPart(n.getRight(), result); } else { result.add(n); return result; } return result; } private void genStringPart(Node n, List<Node> result) { if (n instanceof BinaryExpr) { result.addAll(genStringExprSequence(((BinaryExpr) n))); } else { result.add(n); } } private void printStringExpression(BinaryExpr n, final Object arg) { List<Node> binChain = genStringExprSequence(n); printer.print("format!(\""); for (Node node : binChain) { if (node instanceof StringLiteralExpr) { String value = ((StringLiteralExpr) node).getValue(); printer.print(value); } else { printer.print("{}"); } } printer.print("\""); for (Node node : binChain) { if (!(node instanceof StringLiteralExpr)) { printer.print(", "); node.accept(this, arg); } } printer.print(")"); } @Override public void visit(final CastExpr n, final Object arg) { printJavaComment(n.getComment(), arg); n.getExpr().accept(this, arg); printer.print(" as "); n.getType().accept(this, arg); } @Override public void visit(final ClassExpr n, final Object arg) { printJavaComment(n.getComment(), arg); n.getType().accept(this, arg); printer.print(".class"); } @Override public void visit(final ConditionalExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(" if "); n.getCondition().accept(this, arg); printer.print(" { "); n.getThenExpr().accept(this, arg); printer.print(" } else { "); n.getElseExpr().accept(this, arg); printer.print(" }"); } @Override public void visit(final EnclosedExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("("); if (n.getInner() != null) { n.getInner().accept(this, arg); } printer.print(")"); } String replaceLengthAtEnd(String fieldAccess) { if (fieldAccess.equals("length")) return "len()"; else return fieldAccess; } @Override public void visit(final FieldAccessExpr n, final Object arg) { printJavaComment(n.getComment(), arg); int mark = printer.push(); n.getScope().accept(this, arg); String scope = printer.getMark(mark); printer.drop(); int i = StringUtils.lastIndexOfAny(StringUtils.stripEnd(scope, " "), "\n", "\t", " ", "."); String accessed = i <= 0 ? scope : scope.substring(i + 1); if (Character.isUpperCase(accessed.charAt(0)) && accessed.length() > 1 && Character.isLowerCase(accessed.charAt(1))) { printer.print("::"); } else { printer.print("."); } printer.print(replaceLengthAtEnd(n.getField())); } @Override public void visit(final InstanceOfExpr n, final Object arg) { printJavaComment(n.getComment(), arg); n.getExpr().accept(this, arg); printer.print(" instanceof "); n.getType().accept(this, arg); } @Override public void visit(final CharLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("'"); printer.print(n.getValue()); printer.print("'"); } @Override public void visit(final DoubleLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); String value = n.getValue(); if (!StringUtils.containsAny(value, '.', 'e', 'E', 'x', 'X')) value = value + ".0"; printer.print(removePlusAndSuffix(value, "D", "d")); } boolean isFloatInSiblings(Node n) { if (n == null || n.getParentNode() == null) return false; if (stopHistorySearch(n.getParentNode())) return false; List<Node> siblings = n.getParentNode().getChildrenNodes(); for (Node sibling : siblings) { if (idTracker.isFloat(sibling)) { return true; } } return false; } boolean isFloatInHistory(Node n) { if (stopHistorySearch(n)) return false; if (n == null) return false; if (isFloatInSiblings(n)) return true; Class clazz = idTracker.getType(n); if (idTracker.isFloat(clazz)) { return true; } else { return isFloatInHistory(n.getParentNode()); } } private boolean stopHistorySearch(Node n) { return n instanceof VariableDeclarator || n instanceof MethodCallExpr || n instanceof Statement || n instanceof ArrayAccessExpr; } @Override public void visit(final IntegerLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); String output = removePlusAndSuffix(n.getValue()); if (isFloatInHistory(n)) { printer.print(output + ".0"); } else { printer.print(output); } } @Override public void visit(final LongLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(removePlusAndSuffix(n.getValue(), "l", "L")); } @Override public void visit(final IntegerLiteralMinValueExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(n.getValue()); } @Override public void visit(final LongLiteralMinValueExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(n.getValue()); } @Override public void visit(final StringLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("\""); printer.print(n.getValue()); printer.print("\""); } @Override public void visit(final BooleanLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(String.valueOf(n.getValue())); } @Override public void visit(final NullLiteralExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("null"); } @Override public void visit(final ThisExpr n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getClassExpr() != null) { n.getClassExpr().accept(this, arg); } else { if (!idTracker.isInConstructor()) printer.print("self"); else { printer.print("let "); } } } @Override public void visit(final SuperExpr n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getClassExpr() != null) { n.getClassExpr().accept(this, arg); printer.print("."); } printer.print("super"); } @Override public void visit(final MethodCallExpr n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getScope() != null) { n.getScope().accept(this, arg); if (Character.isUpperCase(n.getScope().toString().charAt(0))) printer.print("::"); else printer.print("."); } printTypeArgs(n.getTypeArgs(), arg); if (n.getScope() == null) { Optional<Pair<TypeDescription, Node>> decl = idTracker.findDeclarationNodeFor(n.getName(), n); if (decl.isPresent()) { Node declNode = decl.get().getRight(); if (declNode != null) { if (declNode instanceof MethodDeclaration) { MethodDeclaration methodDeclaration = (MethodDeclaration) declNode; if (!ModifierSet.isStatic(methodDeclaration.getModifiers())) printer.print("self."); else printer.print("::"); } else { printer.print("self."); } } } } printer.print(toSnakeIfNecessary(n.getName())); printArguments(n.getArgs(), arg); } @Override public void visit(final ObjectCreationExpr n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getScope() != null) { n.getScope().accept(this, arg); printer.print("."); } printTypeArgs(n.getTypeArgs(), arg); if (!isNullOrEmpty(n.getTypeArgs())) { printer.print(" "); } n.getType().accept(this, arg); printer.print("::new"); printArguments(n.getArgs(), arg); if (n.getAnonymousClassBody() != null) { printer.printLn(" {"); printer.indent(); printMembers(n.getAnonymousClassBody(), arg, null); printer.unindent(); printer.print("}"); } } private void orgVisit(final UnaryExpr n, final Object arg) { printJavaComment(n.getComment(), arg); switch (n.getOperator()) { case positive: printer.print("+"); break; case negative: printer.print("-"); break; case inverse: printer.print("~"); break; case not: printer.print("!"); break; case preIncrement: printer.print("++"); break; case preDecrement: printer.print("--"); break; default: } n.getExpr().accept(this, arg); switch (n.getOperator()) { case posIncrement: printer.print("++"); break; case posDecrement: printer.print("--"); break; default: } } boolean isEmbeddedInStmt(UnaryExpr n) { Node parent = n.getParentNode(); if (parent instanceof ExpressionStmt || parent instanceof ForStmt) { return false; } return true; } @Override public void visit(UnaryExpr n, Object arg) { printJavaComment(n.getComment(), arg); String unarySuffix = ""; switch (n.getOperator()) { case preIncrement: unarySuffix = " += 1"; case posIncrement: if (unarySuffix.length() == 0) unarySuffix = " += 1" + (isEmbeddedInStmt(n) ? " !!!check!!! post increment" : ""); case preDecrement: if (unarySuffix.length() == 0) unarySuffix = " -= 1"; case posDecrement: if (unarySuffix.length() == 0) unarySuffix = " -= 1" + (isEmbeddedInStmt(n) ? " !!!check!!! post decrement" : ""); case positive: n.getExpr().accept(this, arg); printer.print(unarySuffix); break; default: orgVisit(n, arg); } } @Override public void visit(final ConstructorDeclaration n, final Object arg) { idTracker.setInConstructor(true); try { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); printModifiers(n.getModifiers()); printTypeParameters(n.getTypeParameters(), arg); if (!n.getTypeParameters().isEmpty()) { printer.print(" "); } printer.print("fn new"); printer.print("("); if (!n.getParameters().isEmpty()) { for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext();) { final Parameter p = i.next(); p.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(") -> "); printer.print(n.getName()); if (!isNullOrEmpty(n.getThrows())) { printer.print(" throws "); for (final Iterator<NameExpr> i = n.getThrows().iterator(); i.hasNext();) { final NameExpr name = i.next(); name.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(" "); n.getBlock().accept(this, arg); } finally { idTracker.setInConstructor(false); } } @Override public void visit(final MethodDeclaration n, final Object arg) { idTracker.setCurrentMethod(n.getName()); try { printOrphanCommentsBeforeThisChildNode(n); printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); for (AnnotationExpr a : n.getAnnotations()) { if (a.getName().getName().equals("Test")) { printer.printLn("#[test]"); } } printModifiers(n.getModifiers()); printer.print("fn "); if (n.isDefault()) { printer.print("default "); } printTypeParameters(n.getTypeParameters(), arg); if (!isNullOrEmpty(n.getTypeParameters())) { printer.print(" "); } int mark = printer.push(); n.getType().accept(this, arg); String typeString = printer.getMark(mark); printer.pop(); printer.print(" "); printer.print(toSnakeIfNecessary(n.getName())); printer.print("("); if (!ModifierSet.isStatic(n.getModifiers())) { printer.print("&self"); if (!isNullOrEmpty(n.getParameters())) printer.print(", "); } if (!isNullOrEmpty(n.getParameters())) { for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext();) { final Parameter p = i.next(); p.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(") "); if (!typeString.equals("void")) { printer.print("-> "); if (n.getArrayCount() > 0) { printer.print("/* "); for (int i = 0; i < n.getArrayCount(); i++) { printer.print("[]"); } printer.print(" */"); } if (!isNullOrEmpty(n.getThrows())) { replaceThrows(n, arg, typeString); } else { printer.print(typeString); } } else { if (!isNullOrEmpty(n.getThrows())) { printer.print(" -> "); replaceThrows(n, arg, "Void"); } } printer.print(" "); if (n.getBody() == null) { printer.print(";"); } else { printer.print(" "); n.getBody().accept(this, arg); } } finally { idTracker.setCurrentMethod(null); } } private void replaceThrows(MethodDeclaration n, Object arg, String typeString) { printer.print("/* "); printer.print(" throws "); for (final Iterator<ReferenceType> i = n.getThrows().iterator(); i.hasNext();) { final ReferenceType name = i.next(); name.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.print(" */"); printer.print("Result<"); printer.print(typeString); printer.print(", Rc<Exception>> "); } @Override public void visit(final Parameter n, final Object arg) { printJavaComment(n.getComment(), arg); if (commentOut) { printer.print("/* "); printModifiers(n.getModifiers()); if (n.isVarArgs()) { printer.print("..."); } printer.print(" */"); } printer.print(" "); n.getId().accept(this, arg); printer.print(": "); if (!(n.getType() instanceof PrimitiveType)) printer.print("&"); if (n.getType() != null) { n.getType().accept(this, arg); } } @Override public void visit(MultiTypeParameter n, Object arg) { printModifiers(n.getModifiers()); Type type = n.getType(); if (type != null) { type.accept(this, arg); } printer.print(" "); n.getId().accept(this, arg); } @Override public void visit(final ExplicitConstructorInvocationStmt n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.isThis()) { printTypeArgs(n.getTypeArgs(), arg); printer.print("this"); } else { if (n.getExpr() != null) { n.getExpr().accept(this, arg); printer.print("."); } printTypeArgs(n.getTypeArgs(), arg); printer.print("super"); } printArguments(n.getArgs(), arg); printer.print(";"); } @Override public void visit(final VariableDeclarationExpr n, final Object arg) { printJavaComment(n.getComment(), arg); printModifiers(n.getModifiers()); printer.print(" "); for (final Iterator<VariableDeclarator> i = n.getVars().iterator(); i.hasNext();) { final VariableDeclarator v = i.next(); v.accept(this, n.getType()); if (i.hasNext()) { printer.print(", "); } } } @Override public void visit(final TypeDeclarationStmt n, final Object arg) { printJavaComment(n.getComment(), arg); n.getTypeDeclaration().accept(this, arg); } @Override public void visit(final AssertStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("assert!( "); n.getCheck().accept(this, arg); if (n.getMessage() != null) { printer.print(" : "); n.getMessage().accept(this, arg); } printer.print(");"); } @Override public void visit(final BlockStmt n, final Object arg) { printOrphanCommentsBeforeThisChildNode(n); printJavaComment(n.getComment(), arg); printer.printLn("{"); if (n.getStmts() != null) { printer.indent(); for (final Statement s : n.getStmts()) { s.accept(this, arg); printer.printLn(); } printer.unindent(); } printOrphanCommentsEnding(n); printer.print("}"); } @Override public void visit(final LabeledStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("'"); printer.print(n.getLabel()); printer.print(": "); n.getStmt().accept(this, arg); } @Override public void visit(final EmptyStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(";"); } @Override public void visit(final ExpressionStmt n, final Object arg) { printOrphanCommentsBeforeThisChildNode(n); printJavaComment(n.getComment(), arg); n.getExpression().accept(this, arg); printer.print(";"); } @Override public void visit(final SwitchStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("match "); n.getSelector().accept(this, arg); printer.printLn(" {"); if (n.getEntries() != null) { printer.indent(); for (final SwitchEntryStmt e : n.getEntries()) { e.accept(this, arg); } printer.unindent(); } printer.print("}"); } @Override public void visit(final SwitchEntryStmt n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getLabel() != null) { printer.print(" "); n.getLabel().accept(this, arg); printer.print(" => "); } else { printer.print("_ => "); } printer.printLn(); printer.indent(); if (n.getStmts() != null) { printer.printLn(" {"); printer.indent(); for (final Statement s : n.getStmts()) { s.accept(this, arg); printer.printLn(); } printer.unindent(); printer.printLn("}"); } printer.unindent(); } @Override public void visit(final BreakStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("break"); if (n.getId() != null) { printer.print(" '"); printer.print(n.getId()); } printer.print(";"); } @Override public void visit(final ReturnStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("return"); if (n.getExpr() != null) { printer.print(" "); if (idTracker.hasThrows()) { printer.print("Ok("); } n.getExpr().accept(this, arg); if (idTracker.hasThrows()) { printer.print(")"); } } printer.print(";"); } @Override public void visit(final EnumDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); printModifiers(n.getModifiers()); printer.print("enum "); printer.print(n.getName()); if (!n.getImplements().isEmpty()) { printer.print(" implements "); for (final Iterator<ClassOrInterfaceType> i = n.getImplements().iterator(); i.hasNext();) { final ClassOrInterfaceType c = i.next(); c.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.printLn(" {"); printer.indent(); if (n.getEntries() != null) { printer.printLn(); for (final Iterator<EnumConstantDeclaration> i = n.getEntries().iterator(); i.hasNext();) { final EnumConstantDeclaration e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } if (!n.getMembers().isEmpty()) { printer.printLn(";"); printMembers(n.getMembers(), arg, null); } else { if (!n.getEntries().isEmpty()) { printer.printLn(); } } printer.unindent(); printer.print("}"); } @Override public void visit(final EnumConstantDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); printer.print(n.getName()); if (n.getArgs() != null) { printArguments(n.getArgs(), arg); } if (!n.getClassBody().isEmpty()) { printer.printLn(" {"); printer.indent(); printMembers(n.getClassBody(), arg, null); printer.unindent(); printer.printLn("}"); } } @Override public void visit(final EmptyMemberDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); printer.print(";"); } @Override public void visit(final InitializerDeclaration n, final Object arg) { printJavaComment(n.getComment(), arg); printJavadoc(n.getJavaDoc(), arg); if (n.isStatic()) { printer.print("static "); } n.getBlock().accept(this, arg); } @Override public void visit(final IfStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("if "); n.getCondition().accept(this, arg); final boolean thenBlock = n.getThenStmt() instanceof BlockStmt; if (thenBlock) // block statement should start on the same line printer.print(" "); else { printer.printLn(" {"); printer.indent(); } n.getThenStmt().accept(this, arg); if (!thenBlock) { printer.unindent(); printer.printLn(); printer.printLn("}"); } if (n.getElseStmt() != null) { if (thenBlock) printer.print(" "); final boolean elseIf = n.getElseStmt() instanceof IfStmt; final boolean elseBlock = n.getElseStmt() instanceof BlockStmt; if (elseIf || elseBlock) // put chained if and start of block statement on a same level printer.print("else "); else { printer.print("else {"); printer.indent(); } n.getElseStmt().accept(this, arg); if (!(elseIf || elseBlock)) { printer.unindent(); printer.printLn(); printer.printLn("}"); } } } @Override public void visit(final WhileStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("while "); n.getCondition().accept(this, arg); printer.print(" "); n.getBody().accept(this, arg); } @Override public void visit(final ContinueStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("continue"); if (n.getId() != null) { printer.print(" '"); printer.print(n.getId()); } printer.print(";"); } @Override public void visit(final DoStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("loop { "); n.getBody().accept(this, arg); printer.print("if !("); n.getCondition().accept(this, arg); printer.print(") break;"); printer.print("}"); } private void encapsulateIfNotBlock(Statement n, final Object arg) { if (n instanceof BlockStmt) { n.accept(this, arg); } else { printer.printLn(" {"); printer.indent(); n.accept(this, arg); printer.printLn("}"); } } @Override public void visit(final ForeachStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("for "); n.getVariable().accept(this, arg); printer.print(" in "); n.getIterable().accept(this, arg); printer.print(" "); encapsulateIfNotBlock(n.getBody(), arg); } @Override public void visit(final ForStmt n, final Object arg) { printJavaComment(n.getComment(), arg); if (n.getInit() != null && !n.getInit().isEmpty()) { printer.printLn(" {"); printer.indent(); for (final Iterator<Expression> i = n.getInit().iterator(); i.hasNext();) { final Expression e = i.next(); e.accept(this, arg); printer.printLn(";"); } } if (n.getCompare() != null) { printer.print("while "); n.getCompare().accept(this, arg); } else { printer.print("loop "); } if (n.getUpdate() != null && !n.getUpdate().isEmpty()) { printer.printLn(" {"); printer.indent(); } encapsulateIfNotBlock(n.getBody(), arg); printer.printLn(""); if (n.getUpdate() != null && !n.getUpdate().isEmpty()) { for (final Iterator<Expression> i = n.getUpdate().iterator(); i.hasNext();) { final Expression e = i.next(); e.accept(this, arg); printer.printLn(";"); } printer.unindent(); printer.printLn(" }"); } if (n.getInit() != null && !n.getInit().isEmpty()) { printer.unindent(); printer.printLn(" }"); } } @Override public void visit(final ThrowStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("throw "); n.getExpr().accept(this, arg); printer.print(";"); } @Override public void visit(final SynchronizedStmt n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print("synchronized ("); n.getExpr().accept(this, arg); printer.print(") "); n.getBlock().accept(this, arg); } @Override public void visit(final TryStmt n, final Object arg) { int tryCount = ++idTracker.tryCount; try { printJavaComment(n.getComment(), arg); printer.printLn("let tryResult" + tryCount + " = 0;"); printer.printLn("'try" + tryCount + ": loop {"); if (!n.getResources().isEmpty()) { printer.print("("); Iterator<VariableDeclarationExpr> resources = n.getResources().iterator(); boolean first = true; while (resources.hasNext()) { visit(resources.next(), arg); if (resources.hasNext()) { printer.print(";"); printer.printLn(); if (first) { printer.indent(); } } first = false; } if (n.getResources().size() > 1) { printer.unindent(); } printer.print(") "); } n.getTryBlock().accept(this, arg); printer.printLn(); printer.printLn("break 'try" + tryCount); printer.printLn("}"); if (n.getCatchs() != null) { printer.printLn("match tryResult" + tryCount + " {"); printer.indent(); for (final CatchClause c : n.getCatchs()) { c.accept(this, arg); } printer.printLn(" 0 => break"); printer.unindent(); printer.printLn("}"); } if (n.getFinallyBlock() != null) { printer.print(" finally "); n.getFinallyBlock().accept(this, arg); } } finally { idTracker.tryCount--; } } @Override public void visit(final CatchClause n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(" catch ("); n.getParam().accept(this, arg); printer.print(") "); n.getCatchBlock().accept(this, arg); } @Override public void visit(final MemberValuePair n, final Object arg) { printJavaComment(n.getComment(), arg); printer.print(n.getName()); printer.print(" = "); n.getValue().accept(this, arg); } @Override public void visit(final LineComment n, final Object arg) { if (!this.printComments) { return; } printer.print("//"); String tmp = n.getContent(); tmp = tmp.replace('\r', ' '); tmp = tmp.replace('\n', ' '); printer.printLn(tmp); } @Override public void visit(final BlockComment n, final Object arg) { if (!this.printComments) { return; } printer.print("/*"); printer.print(n.getContent()); printer.printLn("*/"); } @Override public void visit(LambdaExpr n, Object arg) { printJavaComment(n.getComment(), arg); List<Parameter> parameters = n.getParameters(); boolean printPar = false; printPar = n.isParametersEnclosed(); if (printPar) { printer.print("("); } if (parameters != null) { for (Iterator<Parameter> i = parameters.iterator(); i.hasNext();) { Parameter p = i.next(); p.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } if (printPar) { printer.print(")"); } printer.print(" -> "); Statement body = n.getBody(); if (body instanceof ExpressionStmt) { // Print the expression directly ((ExpressionStmt) body).getExpression().accept(this, arg); } else { body.accept(this, arg); } } @Override public void visit(MethodReferenceExpr n, Object arg) { printJavaComment(n.getComment(), arg); Expression scope = n.getScope(); String identifier = n.getIdentifier(); if (scope != null) { n.getScope().accept(this, arg); } printer.print("::"); if (!n.getTypeParameters().isEmpty()) { printer.print("<"); for (Iterator<TypeParameter> i = n.getTypeParameters().iterator(); i.hasNext();) { TypeParameter p = i.next(); p.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.print(">"); } if (identifier != null) { printer.print(identifier); } } @Override public void visit(TypeExpr n, Object arg) { printJavaComment(n.getComment(), arg); if (n.getType() != null) { n.getType().accept(this, arg); } } protected void printOrphanCommentsBeforeThisChildNode(final Node node) { if (node instanceof Comment) return; Node parent = node.getParentNode(); if (parent == null) return; List<Node> everything = new LinkedList<Node>(); everything.addAll(parent.getChildrenNodes()); sortByBeginPosition(everything); int positionOfTheChild = -1; for (int i = 0; i < everything.size(); i++) { if (everything.get(i) == node) positionOfTheChild = i; } if (positionOfTheChild == -1) throw new RuntimeException("My index not found!!! " + node); int positionOfPreviousChild = -1; for (int i = positionOfTheChild - 1; i >= 0 && positionOfPreviousChild == -1; i--) { if (!(everything.get(i) instanceof Comment)) positionOfPreviousChild = i; } for (int i = positionOfPreviousChild + 1; i < positionOfTheChild; i++) { Node nodeToPrint = everything.get(i); if (!(nodeToPrint instanceof Comment)) throw new RuntimeException( "Expected comment, instead " + nodeToPrint.getClass() + ". Position of previous child: " + positionOfPreviousChild + ", position of child " + positionOfTheChild); nodeToPrint.accept(this, null); } } private void printOrphanCommentsEnding(final Node node) { List<Node> everything = new LinkedList<Node>(); everything.addAll(node.getChildrenNodes()); sortByBeginPosition(everything); if (everything.isEmpty()) { return; } int commentsAtEnd = 0; boolean findingComments = true; while (findingComments && commentsAtEnd < everything.size()) { Node last = everything.get(everything.size() - 1 - commentsAtEnd); findingComments = (last instanceof Comment); if (findingComments) { commentsAtEnd++; } } for (int i = 0; i < commentsAtEnd; i++) { everything.get(everything.size() - commentsAtEnd + i).accept(this, null); } } public static class SourcePrinter { private final String indentation; private final StringBuilder buf = new StringBuilder(); private int level = 0; private boolean indented = false; private List<Integer> marks = new ArrayList<>(); public SourcePrinter(final String indentation) { this.indentation = indentation; } public void indent() { level++; } public void unindent() { level--; } private void makeIndent() { for (int i = 0; i < level; i++) { buf.append(indentation); } } public void print(final String arg) { if (!indented) { makeIndent(); indented = true; } buf.append(arg); } public void printLn(final String arg) { print(arg); printLn(); } public void printLn() { buf.append(System.getProperty("line.separator")); indented = false; } public String getSource() { return buf.toString(); } public int push() { marks.add(buf.length()); return marks.size(); } public String getMark(int mark) { return buf.substring(marks.get(mark - 1)); } public void pop() { buf.delete(marks.get(marks.size() - 1), buf.length()); marks.remove(marks.size() - 1); } public void drop() { marks.remove(marks.size() - 1); } @Override public String toString() { return getSource(); } } }