/* * Copyright (C) 2007 JĂșlio Vilmar Gesser. * Copyright (C) 2008 Mozilla Foundation * * This file is part of HTML Parser C++ Translator. It was derived from DumpVisitor * which was part of Java 1.5 parser and Abstract Syntax Tree and came with the following notice: * * Java 1.5 parser and Abstract Syntax Tree is free software: you can redistribute it and/or modify * it under the terms of 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. * * Java 1.5 parser and Abstract Syntax Tree 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. * * You should have received a copy of the GNU Lesser General Public License * along with Java 1.5 parser and Abstract Syntax Tree. If not, see <http://www.gnu.org/licenses/>. */ /* * Created on 05/10/2006 */ package nu.validator.htmlparser.cpptranslate; import japa.parser.ast.BlockComment; import japa.parser.ast.CompilationUnit; import japa.parser.ast.ImportDeclaration; import japa.parser.ast.LineComment; import japa.parser.ast.Node; import japa.parser.ast.PackageDeclaration; import japa.parser.ast.TypeParameter; import japa.parser.ast.body.AnnotationDeclaration; import japa.parser.ast.body.AnnotationMemberDeclaration; import japa.parser.ast.body.BodyDeclaration; import japa.parser.ast.body.ClassOrInterfaceDeclaration; import japa.parser.ast.body.ConstructorDeclaration; import japa.parser.ast.body.EmptyMemberDeclaration; import japa.parser.ast.body.EmptyTypeDeclaration; import japa.parser.ast.body.EnumConstantDeclaration; import japa.parser.ast.body.EnumDeclaration; import japa.parser.ast.body.FieldDeclaration; import japa.parser.ast.body.InitializerDeclaration; import japa.parser.ast.body.JavadocComment; import japa.parser.ast.body.MethodDeclaration; import japa.parser.ast.body.ModifierSet; import japa.parser.ast.body.Parameter; import japa.parser.ast.body.TypeDeclaration; import japa.parser.ast.body.VariableDeclarator; import japa.parser.ast.body.VariableDeclaratorId; import japa.parser.ast.expr.ArrayAccessExpr; import japa.parser.ast.expr.ArrayCreationExpr; import japa.parser.ast.expr.ArrayInitializerExpr; import japa.parser.ast.expr.AssignExpr; import japa.parser.ast.expr.BinaryExpr; import japa.parser.ast.expr.BooleanLiteralExpr; import japa.parser.ast.expr.CastExpr; import japa.parser.ast.expr.CharLiteralExpr; import japa.parser.ast.expr.ClassExpr; import japa.parser.ast.expr.ConditionalExpr; import japa.parser.ast.expr.DoubleLiteralExpr; import japa.parser.ast.expr.EnclosedExpr; import japa.parser.ast.expr.Expression; import japa.parser.ast.expr.FieldAccessExpr; import japa.parser.ast.expr.InstanceOfExpr; import japa.parser.ast.expr.IntegerLiteralExpr; import japa.parser.ast.expr.IntegerLiteralMinValueExpr; import japa.parser.ast.expr.LongLiteralExpr; import japa.parser.ast.expr.LongLiteralMinValueExpr; import japa.parser.ast.expr.MarkerAnnotationExpr; import japa.parser.ast.expr.MemberValuePair; import japa.parser.ast.expr.MethodCallExpr; import japa.parser.ast.expr.NameExpr; import japa.parser.ast.expr.NormalAnnotationExpr; import japa.parser.ast.expr.NullLiteralExpr; import japa.parser.ast.expr.ObjectCreationExpr; import japa.parser.ast.expr.QualifiedNameExpr; import japa.parser.ast.expr.SingleMemberAnnotationExpr; import japa.parser.ast.expr.StringLiteralExpr; import japa.parser.ast.expr.SuperExpr; import japa.parser.ast.expr.ThisExpr; import japa.parser.ast.expr.UnaryExpr; import japa.parser.ast.expr.VariableDeclarationExpr; import japa.parser.ast.stmt.AssertStmt; import japa.parser.ast.stmt.BlockStmt; import japa.parser.ast.stmt.BreakStmt; import japa.parser.ast.stmt.CatchClause; import japa.parser.ast.stmt.ContinueStmt; import japa.parser.ast.stmt.DoStmt; import japa.parser.ast.stmt.EmptyStmt; import japa.parser.ast.stmt.ExplicitConstructorInvocationStmt; import japa.parser.ast.stmt.ExpressionStmt; import japa.parser.ast.stmt.ForStmt; import japa.parser.ast.stmt.ForeachStmt; import japa.parser.ast.stmt.IfStmt; import japa.parser.ast.stmt.LabeledStmt; import japa.parser.ast.stmt.ReturnStmt; import japa.parser.ast.stmt.Statement; import japa.parser.ast.stmt.SwitchEntryStmt; import japa.parser.ast.stmt.SwitchStmt; import japa.parser.ast.stmt.SynchronizedStmt; import japa.parser.ast.stmt.ThrowStmt; import japa.parser.ast.stmt.TryStmt; import japa.parser.ast.stmt.TypeDeclarationStmt; import japa.parser.ast.stmt.WhileStmt; import japa.parser.ast.type.ClassOrInterfaceType; import japa.parser.ast.type.PrimitiveType; import japa.parser.ast.type.ReferenceType; import japa.parser.ast.type.Type; import japa.parser.ast.type.VoidType; import japa.parser.ast.type.WildcardType; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * @author Julio Vilmar Gesser * @author Henri Sivonen */ public class CppVisitor extends AnnotationHelperVisitor<LocalSymbolTable> { private static final String[] CLASS_NAMES = { "AttributeName", "ElementName", "HtmlAttributes", "LocatorImpl", "MetaScanner", "NamedCharacters", "NamedCharactersAccel", "Portability", "StackNode", "Tokenizer", "TreeBuilder", "UTF16Buffer" }; public class SourcePrinter { private int level = 0; private boolean indented = false; private final StringBuilder buf = new StringBuilder(); public void indent() { level++; } public void unindent() { level--; } private void makeIndent() { for (int i = 0; i < level; i++) { buf.append(" "); } } public void printWithoutIndent(String arg) { indented = false; buf.append(arg); } public void print(String arg) { if (!indented) { makeIndent(); indented = true; } buf.append(arg); } public void printLn(String arg) { print(arg); printLn(); } public void printLn() { buf.append("\n"); indented = false; } public String getSource() { return buf.toString(); } @Override public String toString() { return getSource(); } } private boolean supportErrorReporting = true; protected SourcePrinter printer = new SourcePrinter(); private SourcePrinter staticInitializerPrinter = new SourcePrinter(); private SourcePrinter tempPrinterHolder; protected final CppTypes cppTypes; protected String className = ""; protected int currentArrayCount; protected Set<String> forLoopsWithCondition = new HashSet<String>(); protected boolean inPrimitiveNoLengthFieldDeclarator = false; protected final SymbolTable symbolTable; protected String definePrefix; protected String javaClassName; protected boolean suppressPointer = false; private final List<String> staticReleases = new LinkedList<String>(); private boolean inConstructorBody = false; private String currentMethod = null; private Set<String> labels = null; private boolean destructor; protected boolean inStatic = false; private boolean reportTransitions = false; private int stateLoopCallCount = 0; /** * @param cppTypes */ public CppVisitor(CppTypes cppTypes, SymbolTable symbolTable) { this.cppTypes = cppTypes; this.symbolTable = symbolTable; staticInitializerPrinter.indent(); } public String getSource() { return printer.getSource(); } private String classNameFromExpression(Expression e) { if (e instanceof NameExpr) { NameExpr nameExpr = (NameExpr) e; String name = nameExpr.getName(); if (Arrays.binarySearch(CLASS_NAMES, name) > -1) { return name; } } return null; } protected void printModifiers(int modifiers) { } private void printMembers(List<BodyDeclaration> members, LocalSymbolTable arg) { for (BodyDeclaration member : members) { if ("Tokenizer".equals(javaClassName) && member instanceof MethodDeclaration && "stateLoop".equals(((MethodDeclaration) member).getName())) { reportTransitions = true; } member.accept(this, arg); reportTransitions = false; } } private void printTypeArgs(List<Type> args, LocalSymbolTable arg) { // if (args != null) { // printer.print("<"); // for (Iterator<Type> i = args.iterator(); i.hasNext();) { // Type t = i.next(); // t.accept(this, arg); // if (i.hasNext()) { // printer.print(", "); // } // } // printer.print(">"); // } } private void printTypeParameters(List<TypeParameter> args, LocalSymbolTable arg) { // if (args != null) { // printer.print("<"); // for (Iterator<TypeParameter> i = args.iterator(); i.hasNext();) { // TypeParameter t = i.next(); // t.accept(this, arg); // if (i.hasNext()) { // printer.print(", "); // } // } // printer.print(">"); // } } public void visit(Node n, LocalSymbolTable arg) { throw new IllegalStateException(n.getClass().getName()); } public void visit(CompilationUnit n, LocalSymbolTable arg) { if (n.getTypes() != null) { for (Iterator<TypeDeclaration> i = n.getTypes().iterator(); i.hasNext();) { i.next().accept(this, arg); printer.printLn(); if (i.hasNext()) { printer.printLn(); } } } } public void visit(PackageDeclaration n, LocalSymbolTable arg) { throw new IllegalStateException(n.getClass().getName()); } public void visit(NameExpr n, LocalSymbolTable arg) { if ("mappingLangToXmlLang".equals(n.getName())) { printer.print("0"); } else if ("LANG_NS".equals(n.getName())) { printer.print("ALL_NO_NS"); } else if ("LANG_PREFIX".equals(n.getName())) { printer.print("ALL_NO_PREFIX"); } else if ("HTML_LOCAL".equals(n.getName())) { printer.print(cppTypes.localForLiteral("html")); } else if ("documentModeHandler".equals(n.getName())) { printer.print("this"); } else if ("errorHandler".equals(n.getName())) { printer.print(cppTypes.errorHandler()); } else { String prefixedName = javaClassName + "." + n.getName(); String constant = symbolTable.cppDefinesByJavaNames.get(prefixedName); if (constant != null) { printer.print(constant); } else { printer.print(n.getName()); } } } public void visit(QualifiedNameExpr n, LocalSymbolTable arg) { n.getQualifier().accept(this, arg); printer.print("."); printer.print(n.getName()); } public void visit(ImportDeclaration n, LocalSymbolTable arg) { throw new IllegalStateException(n.getClass().getName()); } public void visit(ClassOrInterfaceDeclaration n, LocalSymbolTable arg) { javaClassName = n.getName(); className = cppTypes.classPrefix() + javaClassName; definePrefix = makeDefinePrefix(className); startClassDeclaration(); if (n.getMembers() != null) { printMembers(n.getMembers(), arg); } endClassDeclaration(); } private String makeDefinePrefix(String name) { StringBuilder sb = new StringBuilder(); boolean prevWasLowerCase = true; for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); if (c >= 'a' && c <= 'z') { sb.append((char) (c - 0x20)); prevWasLowerCase = true; } else if (c >= 'A' && c <= 'Z') { if (prevWasLowerCase) { sb.append('_'); } sb.append(c); prevWasLowerCase = false; } else if (c >= '0' && c <= '9') { sb.append(c); prevWasLowerCase = false; } } sb.append('_'); return sb.toString(); } protected void endClassDeclaration() { printer.printLn("void"); printer.print(className); printer.printLn("::initializeStatics()"); printer.printLn("{"); printer.print(staticInitializerPrinter.getSource()); printer.printLn("}"); printer.printLn(); printer.printLn("void"); printer.print(className); printer.printLn("::releaseStatics()"); printer.printLn("{"); printer.indent(); for (String del : staticReleases) { printer.print(del); printer.printLn(";"); } printer.unindent(); printer.printLn("}"); printer.printLn(); if (cppTypes.hasSupplement(javaClassName)) { printer.printLn(); printer.print("#include \""); printer.print(className); printer.printLn("CppSupplement.h\""); } } protected void startClassDeclaration() { printer.print("#define "); printer.print(className); printer.printLn("_cpp__"); printer.printLn(); String[] incs = cppTypes.boilerplateIncludes(javaClassName); for (int i = 0; i < incs.length; i++) { String inc = incs[i]; printer.print("#include \""); printer.print(inc); printer.printLn(".h\""); } printer.printLn(); for (int i = 0; i < Main.H_LIST.length; i++) { String klazz = Main.H_LIST[i]; if (!klazz.equals(javaClassName)) { printer.print("#include \""); printer.print(cppTypes.classPrefix()); printer.print(klazz); printer.printLn(".h\""); } } printer.printLn(); printer.print("#include \""); printer.print(className); printer.printLn(".h\""); if ("AttributeName".equals(javaClassName) || "ElementName".equals(javaClassName)) { printer.print("#include \""); printer.print(cppTypes.classPrefix()); printer.print("Releasable"); printer.print(javaClassName); printer.printLn(".h\""); } printer.printLn(); } public void visit(EmptyTypeDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } printer.print(";"); } public void visit(JavadocComment n, LocalSymbolTable arg) { printer.print("/**"); printer.print(n.getContent()); printer.printLn("*/"); } public void visit(ClassOrInterfaceType n, LocalSymbolTable arg) { if (n.getScope() != null) { n.getScope().accept(this, arg); printer.print("."); throw new IllegalStateException("Can't translate nested classes."); } String name = n.getName(); if ("String".equals(name)) { if (local()) { name = cppTypes.localType(); } else if (prefix()) { name = cppTypes.prefixType(); } else if (nsUri()) { name = cppTypes.nsUriType(); } else if (literal()) { name = cppTypes.literalType(); } else if (characterName()) { name = cppTypes.characterNameType(); } else { name = cppTypes.stringType(); } } else if ("T".equals(name) || "Object".equals(name)) { name = cppTypes.nodeType(); } else if ("TokenHandler".equals(name)) { name = cppTypes.classPrefix() + "TreeBuilder*"; } else if ("EncodingDeclarationHandler".equals(name)) { name = cppTypes.encodingDeclarationHandlerType(); } else if ("Interner".equals(name)) { name = cppTypes.internerType(); } else if ("TreeBuilderState".equals(name)) { name = cppTypes.treeBuilderStateType(); } else if ("DocumentModeHandler".equals(name)) { name = cppTypes.documentModeHandlerType(); } else if ("DocumentMode".equals(name)) { name = cppTypes.documentModeType(); } else { name = cppTypes.classPrefix() + name + (suppressPointer ? "" : "*"); } printer.print(name); printTypeArgs(n.getTypeArgs(), arg); } protected boolean inHeader() { return false; } public void visit(TypeParameter n, LocalSymbolTable arg) { printer.print(n.getName()); if (n.getTypeBound() != null) { printer.print(" extends "); for (Iterator<ClassOrInterfaceType> i = n.getTypeBound().iterator(); i.hasNext();) { ClassOrInterfaceType c = i.next(); c.accept(this, arg); if (i.hasNext()) { printer.print(" & "); } } } } public void visit(PrimitiveType n, LocalSymbolTable arg) { switch (n.getType()) { case Boolean: printer.print(cppTypes.booleanType()); break; case Byte: printer.print(cppTypes.byteType()); break; case Char: printer.print(cppTypes.charType()); break; case Double: throw new IllegalStateException("Unsupported primitive."); case Float: throw new IllegalStateException("Unsupported primitive."); case Int: printer.print(cppTypes.intType()); break; case Long: throw new IllegalStateException("Unsupported primitive."); case Short: throw new IllegalStateException("Unsupported primitive."); } } public void visit(ReferenceType n, LocalSymbolTable arg) { if (isConst()) { printer.print("const "); } if (noLength()) { n.getType().accept(this, arg); for (int i = 0; i < n.getArrayCount(); i++) { if (!inPrimitiveNoLengthFieldDeclarator) { printer.print("*"); } } } else { for (int i = 0; i < n.getArrayCount(); i++) { if (inStatic) { printer.print(cppTypes.staticArrayTemplate()); } else { if (auto()) { printer.print(cppTypes.autoArrayTemplate()); } else { printer.print(cppTypes.arrayTemplate()); } } printer.print("<"); } n.getType().accept(this, arg); for (int i = 0; i < n.getArrayCount(); i++) { printer.print(","); printer.print(cppTypes.intType()); printer.print(">"); } } } public void visit(WildcardType n, LocalSymbolTable 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); } } public void visit(FieldDeclaration n, LocalSymbolTable arg) { currentAnnotations = n.getAnnotations(); fieldDeclaration(n, arg); currentAnnotations = null; } protected boolean isNonToCharArrayMethodCall(Expression exp) { if (exp instanceof MethodCallExpr) { MethodCallExpr mce = (MethodCallExpr) exp; return !"toCharArray".equals(mce.getName()); } else { return false; } } protected void fieldDeclaration(FieldDeclaration n, LocalSymbolTable arg) { tempPrinterHolder = printer; printer = staticInitializerPrinter; int modifiers = n.getModifiers(); List<VariableDeclarator> variables = n.getVariables(); VariableDeclarator declarator = variables.get(0); if (ModifierSet.isStatic(modifiers) && ModifierSet.isFinal(modifiers) && !(n.getType() instanceof PrimitiveType) && declarator.getInit() != null) { if (n.getType() instanceof ReferenceType) { ReferenceType rt = (ReferenceType) n.getType(); currentArrayCount = rt.getArrayCount(); if (currentArrayCount > 0) { if (currentArrayCount != 1) { throw new IllegalStateException( "Multidimensional arrays not supported. " + n); } if (noLength()) { if (rt.getType() instanceof PrimitiveType) { inPrimitiveNoLengthFieldDeclarator = true; printer = tempPrinterHolder; n.getType().accept(this, arg); printer.print(" "); printer.print(className); printer.print("::"); declarator.getId().accept(this, arg); printer.print(" = "); declarator.getInit().accept(this, arg); printer.printLn(";"); printer = staticInitializerPrinter; } else { printer = tempPrinterHolder; n.getType().accept(this, arg); printer.print(" "); printer.print(className); printer.print("::"); declarator.getId().accept(this, arg); printer.printLn(" = 0;"); printer = staticInitializerPrinter; staticReleases.add("delete[] " + declarator.getId().getName()); ArrayInitializerExpr aie = (ArrayInitializerExpr) declarator.getInit(); declarator.getId().accept(this, arg); printer.print(" = new "); // suppressPointer = true; rt.getType().accept(this, arg); // suppressPointer = false; printer.print("["); printer.print("" + aie.getValues().size()); printer.printLn("];"); printArrayInit(declarator.getId(), aie.getValues(), arg); } } else if ((rt.getType() instanceof PrimitiveType) || "String".equals(rt.getType().toString())) { printer = tempPrinterHolder; printer.print("static "); rt.getType().accept(this, arg); printer.print(" const "); declarator.getId().accept(this, arg); printer.print("_DATA[] = "); declarator.getInit().accept(this, arg); printer.printLn(";"); printer.print(cppTypes.staticArrayTemplate()); printer.print("<"); suppressPointer = true; rt.getType().accept(this, arg); suppressPointer = false; printer.print(","); printer.print(cppTypes.intType()); printer.print("> "); printer.print(className); printer.print("::"); declarator.getId().accept(this, arg); printer.print(" = { "); declarator.getId().accept(this, arg); printer.print("_DATA, "); printer.print(cppTypes.arrayLengthMacro()); printer.print("("); declarator.getId().accept(this, arg); printer.printLn("_DATA) };"); printer = staticInitializerPrinter; } else if (isNonToCharArrayMethodCall(declarator.getInit())) { staticReleases.add(declarator.getId().getName() + ".release()"); declarator.getId().accept(this, arg); printer.print(" = "); if (declarator.getInit() instanceof ArrayInitializerExpr) { ArrayInitializerExpr aie = (ArrayInitializerExpr) declarator.getInit(); printer.print(cppTypes.arrayTemplate()); printer.print("<"); suppressPointer = true; rt.getType().accept(this, arg); suppressPointer = false; printer.print(","); printer.print(cppTypes.intType()); printer.print(">::"); printer.print(cppTypes.newArrayCreator()); printer.print("("); printer.print("" + aie.getValues().size()); printer.printLn(");"); printArrayInit(declarator.getId(), aie.getValues(), arg); } else { declarator.getInit().accept(this, arg); printer.printLn(";"); } } } else { if (ModifierSet.isStatic(modifiers)) { printer = tempPrinterHolder; n.getType().accept(this, arg); printer.print(" "); printer.print(className); printer.print("::"); if ("AttributeName".equals(n.getType().toString())) { printer.print("ATTR_"); } else if ("ElementName".equals(n.getType().toString())) { printer.print("ELT_"); } declarator.getId().accept(this, arg); printer.print(" = "); printer.print(cppTypes.nullLiteral()); printer.printLn(";"); printer = staticInitializerPrinter; } if ("AttributeName".equals(n.getType().toString())) { printer.print("ATTR_"); staticReleases.add("delete ATTR_" + declarator.getId().getName()); } else if ("ElementName".equals(n.getType().toString())) { printer.print("ELT_"); staticReleases.add("delete ELT_" + declarator.getId().getName()); } else { staticReleases.add("delete " + declarator.getId().getName()); } declarator.accept(this, arg); printer.printLn(";"); } } else { throw new IllegalStateException( "Non-reference, non-primitive fields not supported."); } } currentArrayCount = 0; printer = tempPrinterHolder; inPrimitiveNoLengthFieldDeclarator = false; } private void printArrayInit(VariableDeclaratorId variableDeclaratorId, List<Expression> values, LocalSymbolTable arg) { for (int i = 0; i < values.size(); i++) { Expression exp = values.get(i); variableDeclaratorId.accept(this, arg); printer.print("["); printer.print("" + i); printer.print("] = "); if (exp instanceof NameExpr) { if ("AttributeName".equals(javaClassName)) { printer.print("ATTR_"); } else if ("ElementName".equals(javaClassName)) { printer.print("ELT_"); } } exp.accept(this, arg); printer.printLn(";"); } } public void visit(VariableDeclarator n, LocalSymbolTable arg) { n.getId().accept(this, arg); if (n.getInit() != null) { printer.print(" = "); n.getInit().accept(this, arg); } } public void visit(VariableDeclaratorId n, LocalSymbolTable arg) { printer.print(n.getName()); if (noLength()) { for (int i = 0; i < currentArrayCount; i++) { if (inPrimitiveNoLengthFieldDeclarator) { printer.print("[]"); } } } for (int i = 0; i < n.getArrayCount(); i++) { printer.print("[]"); } } public void visit(ArrayInitializerExpr n, LocalSymbolTable arg) { printer.print("{"); if (n.getValues() != null) { printer.print(" "); for (Iterator<Expression> i = n.getValues().iterator(); i.hasNext();) { Expression expr = i.next(); expr.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.print(" "); } printer.print("}"); } public void visit(VoidType n, LocalSymbolTable arg) { printer.print("void"); } public void visit(ArrayAccessExpr n, LocalSymbolTable arg) { n.getName().accept(this, arg); printer.print("["); n.getIndex().accept(this, arg); printer.print("]"); } public void visit(ArrayCreationExpr n, LocalSymbolTable arg) { // printer.print("new "); // n.getType().accept(this, arg); // printTypeArgs(n.getTypeArgs(), arg); if (n.getDimensions() != null) { if (noLength()) { for (Expression dim : n.getDimensions()) { printer.print("new "); n.getType().accept(this, arg); printer.print("["); dim.accept(this, arg); printer.print("]"); } } else { for (Expression dim : n.getDimensions()) { printer.print(cppTypes.arrayTemplate()); printer.print("<"); n.getType().accept(this, arg); printer.print(","); printer.print(cppTypes.intType()); printer.print(">::"); printer.print(cppTypes.newArrayCreator()); printer.print("("); dim.accept(this, arg); printer.print(")"); } } if (n.getArrayCount() > 0) { throw new IllegalStateException( "Nested array allocation not supported. " + n.toString()); } } else { throw new IllegalStateException( "Array initializer as part of array creation not supported. " + n.toString()); } } public void visit(AssignExpr n, LocalSymbolTable arg) { if (inConstructorBody) { n.getTarget().accept(this, arg); printer.print("("); n.getValue().accept(this, arg); printer.print(")"); } else { 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); } } public void visit(BinaryExpr n, LocalSymbolTable arg) { Expression right = n.getRight(); switch (n.getOperator()) { case notEquals: if (right instanceof NullLiteralExpr) { printer.print("!!"); n.getLeft().accept(this, arg); return; } else if (right instanceof IntegerLiteralExpr) { IntegerLiteralExpr ile = (IntegerLiteralExpr) right; if ("0".equals(ile.getValue())) { n.getLeft().accept(this, arg); return; } } case equals: if (right instanceof NullLiteralExpr) { printer.print("!"); n.getLeft().accept(this, arg); return; } else if (right instanceof IntegerLiteralExpr) { IntegerLiteralExpr ile = (IntegerLiteralExpr) right; if ("0".equals(ile.getValue())) { printer.print("!"); n.getLeft().accept(this, arg); return; } } default: // fall thru } 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); } public void visit(CastExpr n, LocalSymbolTable arg) { printer.print("("); n.getType().accept(this, arg); printer.print(") "); n.getExpr().accept(this, arg); } public void visit(ClassExpr n, LocalSymbolTable arg) { n.getType().accept(this, arg); printer.print(".class"); } public void visit(ConditionalExpr n, LocalSymbolTable arg) { n.getCondition().accept(this, arg); printer.print(" ? "); n.getThenExpr().accept(this, arg); printer.print(" : "); n.getElseExpr().accept(this, arg); } public void visit(EnclosedExpr n, LocalSymbolTable arg) { printer.print("("); n.getInner().accept(this, arg); printer.print(")"); } public void visit(FieldAccessExpr n, LocalSymbolTable arg) { Expression scope = n.getScope(); String field = n.getField(); if (inConstructorBody && (scope instanceof ThisExpr)) { printer.print(field); } else if ("length".equals(field) && !(scope instanceof ThisExpr)) { scope.accept(this, arg); printer.print(".length"); } else if ("MAX_VALUE".equals(field) && "Integer".equals(scope.toString())) { printer.print(cppTypes.maxInteger()); } else { String clazzName = classNameFromExpression(scope); if (clazzName == null) { if ("DocumentMode".equals(scope.toString())) { // printer.print(cppTypes.documentModeType()); // printer.print("."); } else { scope.accept(this, arg); printer.print("->"); } } else { String prefixedName = clazzName + "." + field; String constant = symbolTable.cppDefinesByJavaNames.get(prefixedName); if (constant != null) { printer.print(constant); return; } else { printer.print(cppTypes.classPrefix()); printer.print(clazzName); printer.print("::"); if (symbolTable.isNotAnAttributeOrElementName(field)) { if ("AttributeName".equals(clazzName)) { printer.print("ATTR_"); } else if ("ElementName".equals(clazzName)) { printer.print("ELT_"); } } } } printer.print(field); } } public void visit(InstanceOfExpr n, LocalSymbolTable arg) { n.getExpr().accept(this, arg); printer.print(" instanceof "); n.getType().accept(this, arg); } public void visit(CharLiteralExpr n, LocalSymbolTable arg) { printCharLiteral(n.getValue()); } private void printCharLiteral(String val) { if (val.length() != 1) { printer.print("'"); printer.print(val); printer.print("'"); return; } char c = val.charAt(0); switch (c) { case 0: printer.print("'\\0'"); break; case '\n': printer.print("'\\n'"); break; case '\t': printer.print("'\\t'"); break; case 0xB: printer.print("'\\v'"); break; case '\b': printer.print("'\\b'"); break; case '\r': printer.print("'\\r'"); break; case 0xC: printer.print("'\\f'"); break; case 0x7: printer.print("'\\a'"); break; case '\\': printer.print("'\\\\'"); break; case '?': printer.print("'\\?'"); break; case '\'': printer.print("'\\''"); break; case '"': printer.print("'\\\"'"); break; default: if (c >= 0x20 && c <= 0x7F) { printer.print("'" + c); printer.print("'"); } else { printer.print("0x"); printer.print(Integer.toHexString(c)); } break; } } public void visit(DoubleLiteralExpr n, LocalSymbolTable arg) { printer.print(n.getValue()); } public void visit(IntegerLiteralExpr n, LocalSymbolTable arg) { printer.print(n.getValue()); } public void visit(LongLiteralExpr n, LocalSymbolTable arg) { printer.print(n.getValue()); } public void visit(IntegerLiteralMinValueExpr n, LocalSymbolTable arg) { printer.print(n.getValue()); } public void visit(LongLiteralMinValueExpr n, LocalSymbolTable arg) { printer.print(n.getValue()); } public void visit(StringLiteralExpr n, LocalSymbolTable arg) { String val = n.getValue(); if ("http://www.w3.org/1999/xhtml".equals(val)) { printer.print(cppTypes.xhtmlNamespaceLiteral()); } else if ("http://www.w3.org/2000/svg".equals(val)) { printer.print(cppTypes.svgNamespaceLiteral()); } else if ("http://www.w3.org/2000/xmlns/".equals(val)) { printer.print(cppTypes.xmlnsNamespaceLiteral()); } else if ("http://www.w3.org/XML/1998/namespace".equals(val)) { printer.print(cppTypes.xmlNamespaceLiteral()); } else if ("http://www.w3.org/1999/xlink".equals(val)) { printer.print(cppTypes.xlinkNamespaceLiteral()); } else if ("http://www.w3.org/1998/Math/MathML".equals(val)) { printer.print(cppTypes.mathmlNamespaceLiteral()); } else if ("".equals(val) && "AttributeName".equals(javaClassName)) { printer.print(cppTypes.noNamespaceLiteral()); } else if (val.startsWith("-/") || val.startsWith("+//") || val.startsWith("http://") || val.startsWith("XSLT")) { printer.print(cppTypes.stringForLiteral(val)); } else if (("hidden".equals(val) || "isindex".equals(val) || "text/html".equals(val) || "application/xhtml+xml".equals(val) || "content-type".equals(val)) && "TreeBuilder".equals(javaClassName)) { printer.print(cppTypes.stringForLiteral(val)); } else if ("isQuirky".equals(currentMethod) && "html".equals(val)) { printer.print(cppTypes.stringForLiteral(val)); } else { printer.print(cppTypes.localForLiteral(val)); } } public void visit(BooleanLiteralExpr n, LocalSymbolTable arg) { if (n.getValue()) { printer.print(cppTypes.trueLiteral()); } else { printer.print(cppTypes.falseLiteral()); } } public void visit(NullLiteralExpr n, LocalSymbolTable arg) { printer.print(cppTypes.nullLiteral()); } public void visit(ThisExpr n, LocalSymbolTable arg) { if (n.getClassExpr() != null) { n.getClassExpr().accept(this, arg); printer.print("."); } printer.print("this"); } public void visit(SuperExpr n, LocalSymbolTable arg) { if (n.getClassExpr() != null) { n.getClassExpr().accept(this, arg); printer.print("."); } printer.print("super"); } public void visit(MethodCallExpr n, LocalSymbolTable arg) { if ("releaseArray".equals(n.getName()) && "Portability".equals(n.getScope().toString())) { n.getArgs().get(0).accept(this, arg); printer.print(".release()"); } else if ("deleteArray".equals(n.getName()) && "Portability".equals(n.getScope().toString())) { printer.print("delete[] "); n.getArgs().get(0).accept(this, arg); } else if ("delete".equals(n.getName()) && "Portability".equals(n.getScope().toString())) { printer.print("delete "); n.getArgs().get(0).accept(this, arg); } else if (("retainElement".equals(n.getName()) || "releaseElement".equals(n.getName())) && "Portability".equals(n.getScope().toString())) { // ignore for now } else if ("transition".equals(n.getName()) && n.getScope() == null) { visitTransition(n, arg); } else if ("arraycopy".equals(n.getName()) && "System".equals(n.getScope().toString())) { printer.print(cppTypes.arrayCopy()); printer.print("("); if (n.getArgs().get(0).toString().equals( n.getArgs().get(2).toString())) { n.getArgs().get(0).accept(this, arg); printer.print(", "); n.getArgs().get(1).accept(this, arg); printer.print(", "); n.getArgs().get(3).accept(this, arg); printer.print(", "); n.getArgs().get(4).accept(this, arg); } else if (n.getArgs().get(1).toString().equals("0") && n.getArgs().get(3).toString().equals("0")) { n.getArgs().get(0).accept(this, arg); printer.print(", "); n.getArgs().get(2).accept(this, arg); printer.print(", "); n.getArgs().get(4).accept(this, arg); } else { for (Iterator<Expression> i = n.getArgs().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); } else if ("binarySearch".equals(n.getName()) && "Arrays".equals(n.getScope().toString())) { n.getArgs().get(0).accept(this, arg); printer.print(".binarySearch("); n.getArgs().get(1).accept(this, arg); printer.print(")"); } else { Expression scope = n.getScope(); if (scope != null) { if (scope instanceof StringLiteralExpr) { StringLiteralExpr strLit = (StringLiteralExpr) scope; String str = strLit.getValue(); if (!"toCharArray".equals(n.getName())) { throw new IllegalStateException( "Unsupported method call on string literal: " + n.getName()); } printer.print("{ "); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (i != 0) { printer.print(", "); } printCharLiteral("" + c); } printer.print(" }"); return; } else { String clazzName = classNameFromExpression(scope); if (clazzName == null) { scope.accept(this, arg); if ("length".equals(n.getName()) || "charAt".equals(n.getName())) { printer.print("."); } else { printer.print("->"); } } else { printer.print(cppTypes.classPrefix()); printer.print(clazzName); printer.print("::"); } } } printTypeArgs(n.getTypeArgs(), arg); printer.print(n.getName()); if ("stateLoop".equals(n.getName()) && "Tokenizer".equals(javaClassName) && cppTypes.stateLoopPolicies().length > 0) { printer.print("<"); printer.print(cppTypes.stateLoopPolicies()[stateLoopCallCount]); printer.print(">"); stateLoopCallCount++; } printer.print("("); if (n.getArgs() != null) { for (Iterator<Expression> i = n.getArgs().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); } } public void visit(ObjectCreationExpr n, LocalSymbolTable arg) { if (n.getScope() != null) { n.getScope().accept(this, arg); printer.print("."); } printer.print("new "); suppressPointer = true; printTypeArgs(n.getTypeArgs(), arg); if ("createAttributeName".equals(currentMethod) || "elementNameByBuffer".equals(currentMethod)) { printer.print(cppTypes.classPrefix()); printer.print("Releasable"); printer.print(n.getType().getName()); } else { n.getType().accept(this, arg); } suppressPointer = false; if ("AttributeName".equals(n.getType().getName())) { List<Expression> args = n.getArgs(); while (args.size() > 3) { args.remove(3); } } printer.print("("); if (n.getArgs() != null) { for (Iterator<Expression> i = n.getArgs().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); if (n.getAnonymousClassBody() != null) { printer.printLn(" {"); printer.indent(); printMembers(n.getAnonymousClassBody(), arg); printer.unindent(); printer.print("}"); } } public void visit(UnaryExpr n, LocalSymbolTable 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; } n.getExpr().accept(this, arg); switch (n.getOperator()) { case posIncrement: printer.print("++"); break; case posDecrement: printer.print("--"); break; } } public void visit(ConstructorDeclaration n, LocalSymbolTable arg) { if ("TreeBuilder".equals(javaClassName)) { return; } arg = new LocalSymbolTable(javaClassName, symbolTable); // if (n.getJavaDoc() != null) { // n.getJavaDoc().accept(this, arg); // } currentAnnotations = n.getAnnotations(); printModifiers(n.getModifiers()); printMethodNamespace(); printConstructorExplicit(n.getParameters()); printer.print(className); currentAnnotations = null; printer.print("("); if (n.getParameters() != null) { for (Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext();) { Parameter p = i.next(); p.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); printConstructorBody(n.getBlock(), arg); } protected void printConstructorExplicit(List<Parameter> params) { } protected void printConstructorBody(BlockStmt block, LocalSymbolTable arg) { inConstructorBody = true; List<Statement> statements = block.getStmts(); List<Statement> nonAssigns = new LinkedList<Statement>(); int i = 0; boolean needOutdent = false; for (Statement statement : statements) { if (statement instanceof ExpressionStmt && ((ExpressionStmt) statement).getExpression() instanceof AssignExpr) { if (i == 0) { printer.printLn(); printer.indent(); printer.print(": "); needOutdent = true; } else { printer.print(","); printer.printLn(); printer.print(" "); } statement.accept(this, arg); i++; } else { nonAssigns.add(statement); } } if (needOutdent) { printer.unindent(); } inConstructorBody = false; printer.printLn(); printer.printLn("{"); printer.indent(); String boilerplate = cppTypes.constructorBoilerplate(className); if (boilerplate != null) { printer.printLn(boilerplate); } for (Statement statement : nonAssigns) { statement.accept(this, arg); printer.printLn(); } printer.unindent(); printer.printLn("}"); printer.printLn(); } public void visit(MethodDeclaration n, LocalSymbolTable arg) { arg = new LocalSymbolTable(javaClassName, symbolTable); if (isPrintableMethod(n.getModifiers()) && !(n.getName().equals("endCoalescing") || n.getName().equals( "startCoalescing"))) { printMethodDeclaration(n, arg); } } private boolean isPrintableMethod(int modifiers) { return !(ModifierSet.isAbstract(modifiers) || (ModifierSet.isProtected(modifiers) && !(ModifierSet.isFinal(modifiers) || "Tokenizer".equals(javaClassName)))); } protected void printMethodDeclaration(MethodDeclaration n, LocalSymbolTable arg) { if (n.getName().startsWith("fatal") || n.getName().startsWith("err") || n.getName().startsWith("warn") || n.getName().startsWith("maybeErr") || n.getName().startsWith("maybeWarn") || n.getName().startsWith("note") || "releaseArray".equals(n.getName()) || "deleteArray".equals(n.getName()) || "delete".equals(n.getName())) { return; } currentMethod = n.getName(); destructor = "destructor".equals(currentMethod); // if (n.getJavaDoc() != null) { // n.getJavaDoc().accept(this, arg); // } currentAnnotations = n.getAnnotations(); boolean isInline = inline(); if (isInline && !inHeader()) { return; } if (destructor) { printModifiers(ModifierSet.PUBLIC); } else { printModifiers(n.getModifiers()); } if ("stateLoop".equals(currentMethod) && "Tokenizer".equals(javaClassName) && cppTypes.stateLoopPolicies().length > 0) { printer.print("template<class P>"); if (inHeader()) { printer.print(" "); } else { printer.printLn(); } } printTypeParameters(n.getTypeParameters(), arg); if (n.getTypeParameters() != null) { printer.print(" "); } if (!destructor) { n.getType().accept(this, arg); printer.print(" "); } printMethodNamespace(); if (destructor) { printer.print("~"); printer.print(className); } else { printer.print(n.getName()); } currentAnnotations = null; printer.print("("); if (n.getParameters() != null) { for (Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext();) { Parameter p = i.next(); p.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); for (int i = 0; i < n.getArrayCount(); i++) { printer.print("[]"); } if (inHeader() == isInline) { printMethodBody(n.getBody(), arg); } else { printer.printLn(";"); } } private void printMethodBody(BlockStmt n, LocalSymbolTable arg) { if (n == null) { printer.print(";"); } else { printer.printLn(); printer.printLn("{"); printer.indent(); if (destructor) { String boilerplate = cppTypes.destructorBoilderplate(className); if (boilerplate != null) { printer.printLn(boilerplate); } } if (n.getStmts() != null) { for (Statement s : n.getStmts()) { s.accept(this, arg); printer.printLn(); } } printer.unindent(); printer.print("}"); } printer.printLn(); printer.printLn(); } protected void printMethodNamespace() { printer.printLn(); printer.print(className); printer.print("::"); } public void visit(Parameter n, LocalSymbolTable arg) { currentAnnotations = n.getAnnotations(); arg.putLocalType(n.getId().getName(), convertType(n.getType(), n.getModifiers())); n.getType().accept(this, arg); if (n.isVarArgs()) { printer.print("..."); } printer.print(" "); n.getId().accept(this, arg); currentAnnotations = null; } public void visit(ExplicitConstructorInvocationStmt n, LocalSymbolTable 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"); } printer.print("("); if (n.getArgs() != null) { for (Iterator<Expression> i = n.getArgs().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(");"); } public void visit(VariableDeclarationExpr n, LocalSymbolTable arg) { currentAnnotations = n.getAnnotations(); arg.putLocalType(n.getVars().get(0).toString(), convertType( n.getType(), n.getModifiers())); n.getType().accept(this, arg); printer.print(" "); for (Iterator<VariableDeclarator> i = n.getVars().iterator(); i.hasNext();) { VariableDeclarator v = i.next(); v.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } currentAnnotations = null; } public void visit(TypeDeclarationStmt n, LocalSymbolTable arg) { n.getTypeDeclaration().accept(this, arg); } public void visit(AssertStmt n, LocalSymbolTable arg) { String macro = cppTypes.assertionMacro(); if (macro != null) { printer.print(macro); printer.print("("); n.getCheck().accept(this, arg); Expression msg = n.getMessage(); if (msg != null) { printer.print(", \""); if (msg instanceof StringLiteralExpr) { StringLiteralExpr sle = (StringLiteralExpr) msg; String str = sle.getValue(); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == '"') { printer.print("\""); } else if (c >= ' ' && c <= '~') { printer.print("" + c); } else { throw new RuntimeException("Bad assertion message string."); } } } else { throw new RuntimeException("Bad assertion message."); } printer.print("\""); } printer.print(");"); } } public void visit(BlockStmt n, LocalSymbolTable arg) { printer.printLn("{"); if (n.getStmts() != null) { printer.indent(); for (Statement s : n.getStmts()) { s.accept(this, arg); printer.printLn(); } printer.unindent(); } printer.print("}"); } public void visit(LabeledStmt n, LocalSymbolTable arg) { // Only conditionless for loops are needed and supported // Not implementing general Java continue semantics in order // to keep the generated C++ more readable. Statement stmt = n.getStmt(); if (stmt instanceof ForStmt) { ForStmt forLoop = (ForStmt) stmt; if (!(forLoop.getInit() == null && forLoop.getCompare() == null && forLoop.getUpdate() == null)) { forLoopsWithCondition.add(n.getLabel()); } } else { throw new IllegalStateException( "Only for loop supported as labeled statement. Line: " + n.getBeginLine()); } String label = n.getLabel(); if (labels.contains(label)) { printer.print(label); printer.print(": "); } stmt.accept(this, arg); printer.printLn(); label += "_end"; if (labels.contains(label)) { printer.print(label); printer.print(": ;"); } } public void visit(EmptyStmt n, LocalSymbolTable arg) { printer.print(";"); } public void visit(ExpressionStmt n, LocalSymbolTable arg) { Expression e = n.getExpression(); if (isCompletedCharacterReference(e)) { printer.print(cppTypes.completedCharacterReference()); printer.print(";"); return; } boolean needsCondition = isTokenizerErrorReportingExpression(e); if (!needsCondition && isDroppedExpression(e)) { return; } if (needsCondition) { printer.print("if ("); printer.print(cppTypes.tokenizerErrorCondition()); printer.printLn(") {"); printer.indent(); } e.accept(this, arg); if (!inConstructorBody) { printer.print(";"); } if (needsCondition) { printer.printLn(); printer.unindent(); printer.print("}"); } } private void visitTransition(MethodCallExpr call, LocalSymbolTable arg) { List<Expression> args = call.getArgs(); if (reportTransitions) { printer.print(cppTypes.transition()); printer.print("("); printer.print(cppTypes.firstTransitionArg()); printer.print(", "); args.get(1).accept(this, arg); printer.print(", "); args.get(2).accept(this, arg); printer.print(", "); args.get(3).accept(this, arg); printer.print(")"); } else { args.get(1).accept(this, arg); } } private boolean isTokenizerErrorReportingExpression(Expression e) { if (!reportTransitions) { return false; } if (e instanceof MethodCallExpr) { MethodCallExpr methodCallExpr = (MethodCallExpr) e; String name = methodCallExpr.getName(); if (supportErrorReporting && !name.startsWith("errHtml4") && ("stateLoop".equals(currentMethod)) && (name.startsWith("err") || name.startsWith("maybeErr"))) { return true; } } return false; } private boolean isCompletedCharacterReference(Expression e) { if (!reportTransitions) { return false; } if (e instanceof MethodCallExpr) { MethodCallExpr methodCallExpr = (MethodCallExpr) e; String name = methodCallExpr.getName(); if (name.equals("completedNamedCharacterReference")) { return true; } } return false; } private boolean isDroppedExpression(Expression e) { if (e instanceof MethodCallExpr) { MethodCallExpr methodCallExpr = (MethodCallExpr) e; String name = methodCallExpr.getName(); if (name.startsWith("fatal") || name.startsWith("note") || name.startsWith("errHtml4") || name.startsWith("warn") || name.startsWith("maybeWarn")) { return true; } if (supportErrorReporting && ("stateLoop".equals(currentMethod) && !reportTransitions) && (name.startsWith("err") || name.startsWith("maybeErr"))) { return true; } if (name.equals("completedNamedCharacterReference") && !reportTransitions) { return true; } } return false; } public void visit(SwitchStmt n, LocalSymbolTable arg) { printer.print("switch("); n.getSelector().accept(this, arg); printer.printLn(") {"); if (n.getEntries() != null) { printer.indent(); for (SwitchEntryStmt e : n.getEntries()) { e.accept(this, arg); } printer.unindent(); } printer.print("}"); } public void visit(SwitchEntryStmt n, LocalSymbolTable arg) { if (n.getLabel() != null) { boolean isMenuitem = n.getLabel().toString().equals("MENUITEM"); if (isMenuitem) { printer.printWithoutIndent("#ifdef ENABLE_VOID_MENUITEM\n"); } printer.print("case "); n.getLabel().accept(this, arg); printer.print(":"); if (isMenuitem) { printer.printWithoutIndent("\n#endif"); } } else { printer.print("default:"); } if (isNoStatement(n.getStmts())) { printer.printLn(); printer.indent(); if (n.getLabel() == null) { printer.printLn("; // fall through"); } printer.unindent(); } else { printer.printLn(" {"); printer.indent(); for (Statement s : n.getStmts()) { s.accept(this, arg); printer.printLn(); } printer.unindent(); printer.printLn("}"); } } private boolean isNoStatement(List<Statement> stmts) { if (stmts == null) { return true; } for (Statement statement : stmts) { if (!isDroppableStatement(statement)) { return false; } } return true; } private boolean isDroppableStatement(Statement statement) { if (statement instanceof AssertStmt) { return true; } else if (statement instanceof ExpressionStmt) { ExpressionStmt es = (ExpressionStmt) statement; if (isDroppedExpression(es.getExpression())) { return true; } } return false; } public void visit(BreakStmt n, LocalSymbolTable arg) { if (n.getId() != null) { printer.print(cppTypes.breakMacro()); printer.print("("); printer.print(n.getId()); printer.print(")"); } else { printer.print("break"); } printer.print(";"); } public void visit(ReturnStmt n, LocalSymbolTable arg) { printer.print("return"); if (n.getExpr() != null) { printer.print(" "); n.getExpr().accept(this, arg); } printer.print(";"); } public void visit(EnumDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } currentAnnotations = n.getAnnotations(); // if (annotations != null) { // for (AnnotationExpr a : annotations) { // a.accept(this, arg); // printer.printLn(); // } // } printModifiers(n.getModifiers()); printer.print("enum "); printer.print(n.getName()); currentAnnotations = null; if (n.getImplements() != null) { printer.print(" implements "); for (Iterator<ClassOrInterfaceType> i = n.getImplements().iterator(); i.hasNext();) { ClassOrInterfaceType c = i.next(); c.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.printLn(" {"); printer.indent(); if (n.getEntries() != null) { printer.printLn(); for (Iterator<EnumConstantDeclaration> i = n.getEntries().iterator(); i.hasNext();) { EnumConstantDeclaration e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } if (n.getMembers() != null) { printer.printLn(";"); printMembers(n.getMembers(), arg); } else { if (n.getEntries() != null) { printer.printLn(); } } printer.unindent(); printer.print("}"); } public void visit(EnumConstantDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } currentAnnotations = n.getAnnotations(); // if (annotations != null) { // for (AnnotationExpr a : annotations) { // a.accept(this, arg); // printer.printLn(); // } // } printer.print(n.getName()); currentAnnotations = null; if (n.getArgs() != null) { printer.print("("); for (Iterator<Expression> i = n.getArgs().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } printer.print(")"); } if (n.getClassBody() != null) { printer.printLn(" {"); printer.indent(); printMembers(n.getClassBody(), arg); printer.unindent(); printer.printLn("}"); } } public void visit(EmptyMemberDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } printer.print(";"); } public void visit(InitializerDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } if (n.isStatic()) { printer.print("static "); } n.getBlock().accept(this, arg); } public void visit(IfStmt n, LocalSymbolTable arg) { if (TranslatorUtils.isDocumentModeHandlerNullCheck(n.getCondition())) { Statement then = n.getThenStmt(); if (then instanceof BlockStmt) { BlockStmt block = (BlockStmt) then; List<Statement> statements = block.getStmts(); if (statements != null && statements.size() == 1) { statements.get(0).accept(this, arg); } else { then.accept(this, arg); } } else { then.accept(this, arg); } } else if (!TranslatorUtils.isErrorHandlerIf(n.getCondition(), supportErrorReporting)) { if (TranslatorUtils.isErrorOnlyBlock(n.getThenStmt(), supportErrorReporting)) { if (n.getElseStmt() != null && !TranslatorUtils.isErrorOnlyBlock(n.getElseStmt(), supportErrorReporting)) { printer.print("if ("); if (n.getCondition() instanceof BinaryExpr) { BinaryExpr binExpr = (BinaryExpr) n.getCondition(); switch (binExpr.getOperator()) { case equals: binExpr.getLeft().accept(this, arg); printer.print(" != "); binExpr.getRight().accept(this, arg); break; case notEquals: binExpr.getLeft().accept(this, arg); printer.print(" == "); binExpr.getRight().accept(this, arg); break; default: printer.print("!("); formatCondition(n.getCondition(), arg); printer.print(")"); break; } } else { printer.print("!("); formatCondition(n.getCondition(), arg); printer.print(")"); } printer.print(") "); n.getElseStmt().accept(this, arg); } } else { printer.print("if ("); formatCondition(n.getCondition(), arg); printer.print(") "); n.getThenStmt().accept(this, arg); if (n.getElseStmt() != null && !TranslatorUtils.isErrorOnlyBlock(n.getElseStmt(), supportErrorReporting)) { printer.print(" else "); n.getElseStmt().accept(this, arg); } } } } private void formatCondition(Expression expr, LocalSymbolTable arg) { if (expr instanceof BinaryExpr) { BinaryExpr binExpr = (BinaryExpr) expr; switch (binExpr.getOperator()) { case notEquals: if (binExpr.getRight() instanceof NullLiteralExpr) { binExpr.getLeft().accept(this, arg); return; } break; default: break; } } expr.accept(this, arg); } public void visit(WhileStmt n, LocalSymbolTable arg) { printer.print("while ("); n.getCondition().accept(this, arg); printer.print(") "); n.getBody().accept(this, arg); } public void visit(ContinueStmt n, LocalSymbolTable arg) { // Not supporting the general Java continue semantics. // Instead, making the generated code more readable for the // case at hand. if (n.getId() != null) { printer.print(cppTypes.continueMacro()); printer.print("("); printer.print(n.getId()); printer.print(")"); if (forLoopsWithCondition.contains(n.getId())) { throw new IllegalStateException( "Continue attempted with a loop that has a condition. " + className + " " + n.getId()); } } else { printer.print("continue"); } printer.print(";"); } public void visit(DoStmt n, LocalSymbolTable arg) { printer.print("do "); n.getBody().accept(this, arg); printer.print(" while ("); n.getCondition().accept(this, arg); printer.print(");"); } public void visit(ForeachStmt n, LocalSymbolTable arg) { printer.print("for ("); n.getVariable().accept(this, arg); printer.print(" : "); n.getIterable().accept(this, arg); printer.print(") "); n.getBody().accept(this, arg); } public void visit(ForStmt n, LocalSymbolTable arg) { printer.print("for ("); if (n.getInit() != null) { for (Iterator<Expression> i = n.getInit().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print("; "); if (n.getCompare() != null) { n.getCompare().accept(this, arg); } printer.print("; "); if (n.getUpdate() != null) { for (Iterator<Expression> i = n.getUpdate().iterator(); i.hasNext();) { Expression e = i.next(); e.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(") "); n.getBody().accept(this, arg); } public void visit(ThrowStmt n, LocalSymbolTable arg) { printer.print("throw "); n.getExpr().accept(this, arg); printer.print(";"); } public void visit(SynchronizedStmt n, LocalSymbolTable arg) { printer.print("synchronized ("); n.getExpr().accept(this, arg); printer.print(") "); n.getBlock().accept(this, arg); } public void visit(TryStmt n, LocalSymbolTable arg) { printer.print("try "); n.getTryBlock().accept(this, arg); if (n.getCatchs() != null) { for (CatchClause c : n.getCatchs()) { c.accept(this, arg); } } if (n.getFinallyBlock() != null) { printer.print(" finally "); n.getFinallyBlock().accept(this, arg); } } public void visit(CatchClause n, LocalSymbolTable arg) { printer.print(" catch ("); n.getExcept().accept(this, arg); printer.print(") "); n.getCatchBlock().accept(this, arg); } public void visit(AnnotationDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } currentAnnotations = n.getAnnotations(); // if (annotations != null) { // for (AnnotationExpr a : annotations) { // a.accept(this, arg); // printer.printLn(); // } // } printModifiers(n.getModifiers()); printer.print("@interface "); printer.print(n.getName()); currentAnnotations = null; printer.printLn(" {"); printer.indent(); if (n.getMembers() != null) { printMembers(n.getMembers(), arg); } printer.unindent(); printer.print("}"); } public void visit(AnnotationMemberDeclaration n, LocalSymbolTable arg) { if (n.getJavaDoc() != null) { n.getJavaDoc().accept(this, arg); } currentAnnotations = n.getAnnotations(); // if (annotations != null) { // for (AnnotationExpr a : annotations) { // a.accept(this, arg); // printer.printLn(); // } // } printModifiers(n.getModifiers()); n.getType().accept(this, arg); printer.print(" "); printer.print(n.getName()); currentAnnotations = null; printer.print("()"); if (n.getDefaultValue() != null) { printer.print(" default "); n.getDefaultValue().accept(this, arg); } printer.print(";"); } public void visit(MarkerAnnotationExpr n, LocalSymbolTable arg) { printer.print("@"); n.getName().accept(this, arg); } public void visit(SingleMemberAnnotationExpr n, LocalSymbolTable arg) { printer.print("@"); n.getName().accept(this, arg); printer.print("("); n.getMemberValue().accept(this, arg); printer.print(")"); } public void visit(NormalAnnotationExpr n, LocalSymbolTable arg) { printer.print("@"); n.getName().accept(this, arg); printer.print("("); if (n.getPairs() != null) { for (Iterator<MemberValuePair> i = n.getPairs().iterator(); i.hasNext();) { MemberValuePair m = i.next(); m.accept(this, arg); if (i.hasNext()) { printer.print(", "); } } } printer.print(")"); } public void visit(MemberValuePair n, LocalSymbolTable arg) { printer.print(n.getName()); printer.print(" = "); n.getValue().accept(this, arg); } public void visit(LineComment n, LocalSymbolTable arg) { printer.print("//"); printer.printLn(n.getContent()); } public void visit(BlockComment n, LocalSymbolTable arg) { printer.print("/*"); printer.print(n.getContent()); printer.printLn("*/"); } public void setLabels(Set<String> labels) { this.labels = labels; } }