diff --git a/migrator/src/com/ohos/migrator/AbstractTranspiler.java b/migrator/src/com/ohos/migrator/AbstractTranspiler.java index 015b991043de3de7b92f20d2b9d0bdd6d2d0789c..f727ac86d59d310195999a38f562381aa7097bb1 100644 --- a/migrator/src/com/ohos/migrator/AbstractTranspiler.java +++ b/migrator/src/com/ohos/migrator/AbstractTranspiler.java @@ -70,6 +70,13 @@ public abstract class AbstractTranspiler implements Transpiler { if (strictMode) return transpileResult; } catch (Exception e) { + StringBuilder sb = new StringBuilder(e.getClass().getName()); + sb.append(" at:\n"); + + for (StackTraceElement ste : e.getStackTrace()) + sb.append(ste.toString()).append("\n"); + + errorList.add(new TranspileException(ResultCode.InputError, sb.toString())); transpileResult = ResultCode.majorValue(ResultCode.InputError, transpileResult); if (strictMode) return transpileResult; } diff --git a/migrator/src/com/ohos/migrator/java/JavaParser.java b/migrator/src/com/ohos/migrator/java/JavaParser.java index 6ef82f25816ab0479827fcfb2522155c93c0ed4d..5ecb4efc291b65cd077889f3559cff8836723848 100644 --- a/migrator/src/com/ohos/migrator/java/JavaParser.java +++ b/migrator/src/com/ohos/migrator/java/JavaParser.java @@ -40,7 +40,7 @@ public class JavaParser { private File sourceFile; private static Map packagePaths = new HashMap<>(); - private String[] sourcepathEntries = null; + private static String[] sourcepathEntries = null; private String[] classpathEntries = null; /* @@ -60,7 +60,11 @@ public class JavaParser { */ public JavaParser(File sourceFile, List sourceFiles, List classpaths) throws IOException { this(sourceFile); - setSourcepathEntries(sourceFiles); + + // Compute reference source paths once + if (sourcepathEntries == null) + setSourcepathEntries(sourceFiles); + setClasspathEntries(classpaths); } @@ -73,7 +77,7 @@ public class JavaParser { this.source = source; } - private String getPackagePath(File file) { + private static String getPackagePath(File file) { // If already processed this file, return the result from cache. if (packagePaths.containsKey(file)) { return packagePaths.get(file); @@ -125,13 +129,10 @@ public class JavaParser { return packagePath; } - private void setSourcepathEntries(List sourceFiles) { + private static void setSourcepathEntries(List sourceFiles) { Set filePaths = new HashSet<>(); for (File file : sourceFiles) { - // Skip source file that is to be parsed currently. - if (file == this.sourceFile) continue; - // ASTParser accepts only directories where reference sources // are located. Thus, store the parent of each source file path. String pkg = getPackagePath(file); diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 0292b37bab2d84a09809f1f4f8c6e5c259831721..aa5b7e7818f233de2964a1fe312ba99199f36e39 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -43,21 +43,38 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private final Stack stsSaved = new Stack<>(); private final String INSTANCE_INITIALIZER = "INSTANCE_INITIALIZER"; + private final String USED_IN_ANOTHER_CASE_CLAUSE = "USED_IN_ANOTHER_CASE_CLAUSE"; + private final String ENUM_TYPE_NAME = "ENUM_TYPE_NAME"; + + private final String ENUM_CONST_ORDINAL = "ENUM_CONST_ORDINAL"; private static int countStmtTotal = 0; private static int countExprTotal = 0; + + private static int countDeclTotal = 0; private static int countExprTransformed = 0; private static int countStmtTransformed = 0; + private static int countDeclTransformed = 0; public static double getTransformationRate() { double result = 0.; + int normFactor = 0; - if (countStmtTotal > 0) result += countStmtTransformed / (double)countStmtTotal; - if (countExprTotal > 0) result += countExprTransformed / (double)countExprTotal; + if (countStmtTotal > 0) { + ++normFactor; + result += countStmtTransformed / (double)countStmtTotal; + } + if (countExprTotal > 0) { + ++normFactor; + result += countExprTransformed / (double)countExprTotal; + } + if (countDeclTotal > 0) { + ++normFactor; + result += countDeclTransformed / (double)countDeclTotal; + } - double normFactor = (countStmtTotal > 0 && countExprTotal > 0) ? 2. : 1.; - return result / normFactor; + return (normFactor > 0) ? result / (double)normFactor : 0.; } /** @@ -141,6 +158,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { ++countExprTotal; else if (node instanceof Statement) ++countStmtTotal; + else if (node instanceof BodyDeclaration + || node instanceof VariableDeclaration) + ++countDeclTotal; } }); @@ -187,14 +207,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - private void translateNonAccessModifiers(FieldDeclaration javaFieldDecl) { - int javaModifiers = javaFieldDecl.getModifiers(); - - // A field may not have Abstract modifier. - if ((javaModifiers & Modifier.STATIC) != 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); - if ((javaModifiers & Modifier.FINAL) == 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Open)); - } - private void translateNonAccessModifiers(TypeDeclaration javaTypeDeclaration) { int javaModifiers = javaTypeDeclaration.getModifiers(); @@ -214,6 +226,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return true; } + for (ITypeBinding javaInterface : javaClassBinding.getInterfaces()) { + if (doesOverride(javaInterface, javaCheckedMethod)) + return true; + } + ITypeBinding javaSuperClassBinding = javaClassBinding.getSuperclass(); if (javaSuperClassBinding != null) return doesOverride(javaSuperClassBinding, javaCheckedMethod); @@ -241,15 +258,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if ((javaModifiers & Modifier.STATIC) != 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); if ((javaModifiers & Modifier.NATIVE) != 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Native)); } - - private void translateNonAccessModifiers(EnumDeclaration javaEnumDeclaration) { - // TODO: Check and correct to apply only enum related/valid modifiers. - int javaModifiers = javaEnumDeclaration.getModifiers(); - if ((javaModifiers & Modifier.ABSTRACT) != 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Abstract)); - if ((javaModifiers & Modifier.STATIC) != 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); - if ((javaModifiers & Modifier.FINAL) == 0) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Open)); - } - + // Java tree: // TypeDeclaration: // A type declaration is the union of a class declaration and an interface declaration. // ClassDeclaration @@ -269,7 +278,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // { { InterfaceBodyDeclaration | ; } } // // STS tree for interface: - // TopLevelElementContext + // topDeclarationContext // InterfaceDeclarationContext // TerminalNode // TerminalNode @@ -280,8 +289,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // // STS src: class TestClassB extends TestClassA implements TestInterfaceA, TestInterfaceB {} // Resulting tree: - // TopLevelElementContext | ClassMemberContext | InterfaceMemberContext - // TerminalNode ? (for TopLevelElementContext) + // topDeclarationContext | ClassMemberContext | InterfaceMemberContext + // TerminalNode ? (for topDeclarationContext) // | AccessibilityModifierContext? (for ClassMemberContext or InterfaceMemberContext) // ClassDeclarationContext // TerminalNode @@ -355,6 +364,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // Interface/ClassDeclarationContext popCurrent(); // stsMemberContext + ++countDeclTransformed; return false; } @@ -467,20 +477,41 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return stsMemberContext; } - private void addInstanceInitializersToCtors(TypeDeclaration javaTypeDeclaration) { + private void addInstanceInitializersToCtors(AbstractTypeDeclaration javaTypeDeclaration) { // Put statements from instance initializers into constructors which don't call // another constructor (i.e. don't have 'this()' call). - List stsInitStmts = (List) javaTypeDeclaration.getProperty(INSTANCE_INITIALIZER); + List stsInitStmts = (List)javaTypeDeclaration.getProperty(INSTANCE_INITIALIZER); if (stsCurrent instanceof ClassBodyContext && stsInitStmts != null && !stsInitStmts.isEmpty()) { ClassBodyContext stsClassBody = (ClassBodyContext) stsCurrent; + boolean needDefaultCtor = true; for (ClassMemberContext stsMember : stsClassBody.classMember()) { - addInstanceInitializersToCtor(stsMember.constructorDeclaration(), stsInitStmts); + ConstructorDeclarationContext stsCtorDecl = stsMember.constructorDeclaration(); + if (stsCtorDecl != null) { + addInstanceInitializersToCtor(stsCtorDecl, stsInitStmts); + needDefaultCtor = false; + } + } + + if (needDefaultCtor) { + // Create default ctor and add initializer statements to it + pushCurrent(new ClassMemberContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.accessibilityModifier(Modifier.PUBLIC)).setParent(stsCurrent); + + ConstructorDeclarationContext stsDefaultCtor = new ConstructorDeclarationContext(stsCurrent, 0); + pushCurrent(stsDefaultCtor); + + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Constructor)); + stsCurrent.addChild(new ConstructorBodyContext(stsCurrent, 0)).setParent(stsCurrent); + + popCurrent(); // stsDefaultCtor + popCurrent(); // ClassMemberContext + + addInstanceInitializersToCtor(stsDefaultCtor, stsInitStmts); } } } - - private void addInstanceInitializersToCtor(ConstructorDeclarationContext stsCtorDecl, List stsInitStmts) { + private void addInstanceInitializersToCtor(ConstructorDeclarationContext stsCtorDecl, List stsInitStmts) { // Sanity check. if (stsCtorDecl == null) return; @@ -541,20 +572,27 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(stsClassOrInterField); - // Non-access modifiers and field name. - translateNonAccessModifiers(javaFieldDecl); + // Non-access modifiers + if ((javaMods & Modifier.STATIC) != 0) + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); + // Note: Java allows final fields declared without initializer (to be initialized in ctor). + // STS doesn't allow constant fields without initializer, therefore the fields above will + // be translated without const modifier. ParserRuleContext stsVarOrConstDecl; - if ((javaMods & Modifier.FINAL) != 0 || !isInClassContext) { + Expression javaFragmentInit = javaVarDeclFragment.getInitializer(); + if (((javaMods & Modifier.FINAL) != 0 && javaFragmentInit != null) || !isInClassContext) { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Const)); stsVarOrConstDecl = new ConstantDeclarationContext(stsCurrent, 0); } else stsVarOrConstDecl = new VariableDeclarationContext(stsCurrent, 0); + // Field name pushCurrent(stsVarOrConstDecl); stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaVarDeclFragment.getName())); + // Field type pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Colon)); javaFieldDecl.getType().accept(this); @@ -564,11 +602,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // TypeAnnotationContext - Expression javaInitializer = javaVarDeclFragment.getInitializer(); - if (javaInitializer != null) { + // Field initializer, if any + if (javaFragmentInit != null) { pushCurrent(new InitializerContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Assign)); - javaInitializer.accept(this); + javaFragmentInit.accept(this); popCurrent(); // InitializerContext } @@ -577,6 +615,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // stsClassOrInterMember } + ++countDeclTransformed; return false; } @@ -642,7 +681,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { boolean needPrimaryType = isInPrimaryTypeContext(); if (needPrimaryType) pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - PredefinedTypeContext stsType = NodeBuilder.predefinedType(javaPrimitiveType); + PredefinedTypeContext stsType = NodeBuilder.predefinedType(javaPrimitiveType.getPrimitiveTypeCode()); stsCurrent.addChild(stsType).setParent(stsCurrent); if (needPrimaryType) popCurrent(); // PrimaryTypeContext @@ -1321,6 +1360,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popCurrent(); // ClassMemberContext or InterfaceMemberContext + + ++countDeclTransformed; return false; } @@ -1383,9 +1424,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // RestFormalParameterContext | FormalParameterContext + ++countDeclTransformed; return false; } + // NOTE: All Java enums are translated into STS classes because of + // built-in methods values() and valueOf() available to the former! + // // Java tree: // EnumDeclaration: // [ Javadoc ] { ExtendedModifier } enum Identifier @@ -1396,56 +1441,386 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // } // // STS tree: - // TopLevelElementContext | ClassMemberContext | InterfaceMemberContext - // TerminalNode ? (for TopLevelElementContext) + // TopDeclarationContext | ClassMemberContext | InterfaceMemberContext + // TerminalNode ? (for TopDeclarationContext) // | AccessibilityModifierContext? (for ClassMemberContext or InterfaceMemberContext) - // EnumDeclarationContext - // Enum Identifier OpenBrace enumBody CloseBrace + // ClassDeclarationContext + // TerminalNode + // Identifier + // ClassExtendsClauseContext + // TerminalNode + // TypeReferenceContext + // QualifiedNameContext + // TerminalNode + // ImplementsClauseContext + // TerminalNode + // InterfaceTypeListContext + // TypeReferenceContext + // QualifiedNameContext + // TerminalNode + // TerminalNode <,> + // TypeReferenceContext + // QualifiedNameContext + // TerminalNode + // ClassBodyContext @Override public boolean visit(EnumDeclaration javaEnumDeclaration) { // Create appropriate member context to put declaration into. - pushCurrent(createMemberContextWithAccessModifier(javaEnumDeclaration.getModifiers())); - pushCurrent(new EnumDeclarationContext(stsCurrent, 0)); + int javaEnumMods = javaEnumDeclaration.getModifiers(); + pushCurrent(createMemberContextWithAccessModifier(javaEnumMods)); - // Add remaining (non-access) modifiers and enum keyword. - translateNonAccessModifiers(javaEnumDeclaration); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Enum)); + // Create class declaration context + ClassDeclarationContext stsClassDecl = new ClassDeclarationContext(stsCurrent, 0); + pushCurrent(stsClassDecl); - // Enum name - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumDeclaration.getName())); + // Set static modifier as necessary. + if (stsCurrent.getParent().getRuleIndex() != StaticTSParser.RULE_topDeclaration) { + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); + } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBrace)); + // Add class keyword and enum name + SimpleName javaEnumName = javaEnumDeclaration.getName(); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Class)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumName)); + + // Add extends clause. + createEnumExtendsClause(javaEnumName.getIdentifier()); - pushCurrent(new EnumBodyContext(stsCurrent, 0)); + // Add implements clause, if necessary + translateSuperInterfaceTypes(javaEnumDeclaration.superInterfaceTypes()); + + pushCurrent(new ClassBodyContext(stsCurrent, 0)); + + // Translate enum constants. + // If any of the constants contain anonymous class body (e.g., extend enum type), + // add open modifier to the resulting class. + boolean needOpen = false; + int javaEnumConstOrdinal = 0; + List javaEnumConstNames = new ArrayList<>(); + List javaEnumConstants = javaEnumDeclaration.enumConstants(); + for (EnumConstantDeclaration javaEnumConst : javaEnumConstants) { + if (!needOpen) needOpen = javaEnumConst.getAnonymousClassDeclaration() != null; + + // Pass enum name and ordinal to enum constant node before visiting it + // as we'll need it to create appropriate initializers. + javaEnumConst.setProperty(ENUM_TYPE_NAME, javaEnumName.getIdentifier()); + javaEnumConst.setProperty(ENUM_CONST_ORDINAL, String.valueOf(javaEnumConstOrdinal)); + + // Store enum constant name in a list - we'll need it later to generate + // built-in values() method + javaEnumConstNames.add(javaEnumConst.getName().getIdentifier()); - // It looks for the transpiler there is no need to insert in the tree Comma terminal nodes. - // The writer adds them to the output without looking for them in the input tree. - List constants = javaEnumDeclaration.enumConstants(); - for(EnumConstantDeclaration javaEnumConst : constants) { javaEnumConst.accept(this); + ++javaEnumConstOrdinal; + } + if (needOpen) { + stsClassDecl.children.add(0, NodeBuilder.terminalNode(StaticTSParser.Open)); } - popCurrent(); // EnumBodyContext + // Translate body declarations (ctors, methods, nested types, and fields). + boolean hasCtors = false; + List javaEnumBodyDecls = javaEnumDeclaration.bodyDeclarations(); + for (BodyDeclaration javaEnumBodyDecl : javaEnumBodyDecls) { + javaEnumBodyDecl.accept(this); + if (!hasCtors) { + if (javaEnumBodyDecl.getNodeType() == ASTNode.METHOD_DECLARATION) { + MethodDeclaration javaEnumMethodDecl = (MethodDeclaration) javaEnumBodyDecl; + hasCtors = javaEnumMethodDecl.isConstructor(); + } + } + } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBrace)); + // Add values and valueOf built-in methods + String javaEnumTypeName = javaEnumDeclaration.getName().getIdentifier(); + createEnumValuesMethod(javaEnumTypeName, javaEnumConstNames); + createEnumValueOfMethod(javaEnumTypeName); - popCurrent(); // EnumDeclarationContext - popCurrent(); // stsMemberContext + // Add name and ordinal parameters to all ctors. + if (!hasCtors) { + // If no ctors present, generate default one with just the two parameters above, + // and a single super(name, ordinal) call in the body. + createEnumDefaultCtor(); + } + else { + // For all non-default ctors - if there is no call to another ctor in the body, + // generate super(name, ordinal) call, otherwise pass name and ordinal to existing ctor call. + ClassBodyContext stsEnumClassBody = (ClassBodyContext)stsCurrent; + for (ClassMemberContext stsEnumClassMember : stsEnumClassBody.classMember()) { + ConstructorDeclarationContext stsEnumCtor = stsEnumClassMember.constructorDeclaration(); + if (stsEnumCtor != null) { + modifyEnumCtor(stsEnumCtor); + } + } + } - return false; + // Process instance initializers, if any. + // NOTE: This has to happen here, after default ctor is generated if necessary, + // (see above), as default ctor of enum class is different from the one that + // addInstanceInitializersToCtors can create. + addInstanceInitializersToCtors(javaEnumDeclaration); + + popCurrent(); // ClassBodyContext + popCurrent(); // stsClassDecl + popCurrent(); // member context + + ++countDeclTransformed; + return false; + } + private void createEnumDefaultCtor() { + pushCurrent(new ClassMemberContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.accessibilityModifier(Modifier.PRIVATE)).setParent(stsCurrent); + pushCurrent(new ConstructorDeclarationContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Constructor)); + pushCurrent(new ParameterListContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.parameter("name", "String")).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.parameter("ordinal", PrimitiveType.INT)).setParent(stsCurrent); + popCurrent(); // ParameterListContext + pushCurrent(new ConstructorBodyContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.ctorCall(true, "name", "ordinal")).setParent(stsCurrent); + popCurrent(); // ConstructorBodyContext + popCurrent(); // ConstructorDeclarationContext + popCurrent(); // ClassMemberContext + } + + private void modifyEnumCtor(ConstructorDeclarationContext stsEnumCtor) { + // Get parameter list or create if there isn't one + ParameterListContext stsEnumCtorParams = stsEnumCtor.parameterList(); + if (stsEnumCtorParams == null) { + stsEnumCtorParams = new ParameterListContext(stsEnumCtor, 0); + stsEnumCtor.addChild(stsEnumCtorParams).setParent(stsEnumCtor); + } + + // Inject name and ordinal parameters + ParameterContext stsEnumCtorParam = NodeBuilder.parameter("name", "String"); + stsEnumCtorParams.children.add(0, stsEnumCtorParam); + stsEnumCtorParam.setParent(stsEnumCtorParams); + stsEnumCtorParam = NodeBuilder.parameter("ordinal", PrimitiveType.INT); + stsEnumCtorParams.children.add(1, stsEnumCtorParam); + stsEnumCtorParam.setParent(stsEnumCtorParams); + + ConstructorBodyContext stsEnumCtorBody = stsEnumCtor.constructorBody(); + ConstructorCallContext stsEnumCtorCall = stsEnumCtorBody.getRuleContext(ConstructorCallContext.class, 0); + if (stsEnumCtorCall == null) { + // Create super(name, ordinal) call + stsEnumCtorBody.addChild(NodeBuilder.ctorCall(true, "name", "ordinal")).setParent(stsEnumCtorBody); + } + else { + // Pass name and ordinal parameters to ctor call + ArgumentsContext stsEnumCtorCallArgs = stsEnumCtorCall.arguments(); + ExpressionSequenceContext stsExprSeq = stsEnumCtorCallArgs.expressionSequence(); + if (stsExprSeq == null) { + // Create expression sequence node, if necessary + stsExprSeq = new ExpressionSequenceContext(stsEnumCtorCallArgs, 0); + stsEnumCtorCallArgs.addChild(stsExprSeq).setParent(stsEnumCtorCallArgs); + } + + SingleExpressionContext stsEnumCtorCallArg = NodeBuilder.identifierExpression("name"); + stsExprSeq.children.add(0, stsEnumCtorCallArg); + stsEnumCtorCallArg.setParent(stsExprSeq); + stsEnumCtorCallArg = NodeBuilder.identifierExpression("ordinal"); + stsExprSeq.children.add(1, stsEnumCtorCallArg); + stsEnumCtorCallArg.setParent(stsExprSeq); + } + } + private void createEnumExtendsClause(String javaEnumName) { + // Note: A Java enum extends Enum class. + pushCurrent(new ClassExtendsClauseContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Extends)); + pushCurrent(NodeBuilder.typeReference("Enum")); + ParseTree lastChild = stsCurrent.getChild(stsCurrent.getChildCount()-1); + pushCurrent((TypeReferencePartContext)lastChild, false); + pushCurrent(new TypeArgumentsContext(stsCurrent, 0)); + pushCurrent(new TypeArgumentListContext(stsCurrent, 0)); + pushCurrent(new TypeArgumentContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.typeReference(javaEnumName)).setParent(stsCurrent); + popCurrent(); // TypeArgumentContext + popCurrent(); // TypeArgumentListContext + popCurrent(); // TypeArgumentsContext + popCurrent(); // (TypeReferencePartContext)lastChild + popCurrent(); // TypeReferenceContext + popCurrent(); // ClassExtendsClauseContext } + private void pushEnumBuiltinMethod() { + // Create class member context and add public modifier + pushCurrent(new ClassMemberContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.accessibilityModifier(Modifier.PUBLIC)); + // Create class method declaration context and add static modifier + pushCurrent(new ClassMethodDeclarationContext(stsCurrent, 0)); + pushCurrent(new ClassMethodWithBodyContext((ClassMethodDeclarationContext)stsCurrent)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); + } + private void popEnumBuiltinMethod() { + popCurrent(); // ClassMethodWithBodyContext + popCurrent(); // ClassMethodDeclarationContext + popCurrent(); // ClassMemberContext + } + + // Generates the following method + // public static values() : [] { + // return [ , , ... ]; + // } + private void createEnumValuesMethod(String javaEnumTypeName, List javaEnumConstNames) { + pushEnumBuiltinMethod(); + + // Add method name and signature + stsCurrent.addChild(NodeBuilder.terminalIdentifier("values")); + pushCurrent(new SignatureContext(stsCurrent, 0)); + ArrayTypeContext stsReturnType = NodeBuilder.arrayType(javaEnumTypeName, 1); + stsCurrent.addChild(NodeBuilder.typeAnnotation(stsReturnType)).setParent(stsCurrent); + popCurrent(); // SignatureContext + + // Add method body + // return [ enum_constant1, enum_constant2, ... ]; + pushCurrent(new BlockContext(stsCurrent, 0)); + pushStatement(new ReturnStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Return)); + pushCurrent(new ArrayLiteralExpressionContext(pushSingleExpression())); + pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); + for (String javaEnumConstName : javaEnumConstNames) { + stsCurrent.addChild(NodeBuilder.identifierExpression(javaEnumConstName)).setParent(stsCurrent); + } + popCurrent(); // ExpressionSequenceContext + popSingleExpression(); // ArrayLiteralExpressionContext + popStatement(); // ReturnStatementContext + popCurrent(); // BlockContext + + popEnumBuiltinMethod(); + } + + // Generates the following method: + // public static valueOf(String name) : { + // for (let value : of values()) { + // if (name == value.toString()) return value; + // } + // return null; + // } + private void createEnumValueOfMethod(String javaEnumTypeName) { + pushEnumBuiltinMethod(); + + // Add method name and signature + stsCurrent.addChild(NodeBuilder.terminalIdentifier("valueOf")); + pushCurrent(new SignatureContext(stsCurrent, 0)); + pushCurrent(new ParameterListContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.parameter("name", "String")).setParent(stsCurrent); + popCurrent(); // ParameterListContext + stsCurrent.addChild(NodeBuilder.typeAnnotation(javaEnumTypeName)).setParent(stsCurrent); + popCurrent(); // SignatureContext + + // Add method body + // for (let value : of values()) { + pushCurrent(new BlockContext(stsCurrent, 0)); + pushCurrent(new ForOfStatementContext(pushIterationStatement())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.For)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Let)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("value")); + stsCurrent.addChild(NodeBuilder.typeAnnotation(javaEnumTypeName)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Of)); + pushCurrent(new CallExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.identifierExpression("values")).setParent(stsCurrent); + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + popCurrent(); // ArgumentsContext + popSingleExpression(); // CallExpressionContext + pushStatement(new BlockContext(stsCurrent, 0)); + + // if (name == value.toString()) return value; + IfStatementContext stsIfStmt = new IfStatementContext(stsCurrent, 0); + pushStatement(stsIfStmt); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.If)); + pushCurrent(new EqualityExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.identifierExpression("name")).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Equals)); + pushCurrent(new CallExpressionContext(pushSingleExpression())); + pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.identifierExpression("value")).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("toString")); + popSingleExpression(); // MemberAccessExpressionContext + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + popCurrent(); // ArgumentsContext + popSingleExpression(); // CallExpressionContext + popSingleExpression(); // EqualityExpressionContext + pushStatement(new ReturnStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Return)); + stsCurrent.addChild(NodeBuilder.identifierExpression("value")).setParent(stsCurrent); + popStatement(); // ReturnStatementContext + ParseTree lastChild = stsCurrent.getChild(stsCurrent.getChildCount() - 1); + assert(lastChild instanceof StatementContext); + stsIfStmt.ifStmt = (StatementContext)lastChild; + popStatement(); // IfStatementContext + + // close off for-of statement + popStatement(); // BlockContext + popIterationStatement(); // ForOfStatementContext + + // return null; + pushStatement(new ReturnStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Return)); + stsCurrent.addChild(NodeBuilder.nullLiteral()).setParent(stsCurrent); + popStatement(); // ReturnStatementContext + + // close off method body + popCurrent(); // BlockContext + + popEnumBuiltinMethod(); + } @Override public boolean visit(EnumConstantDeclaration javaEnumConstant) { - pushCurrent(new EnumMemberContext(stsCurrent, 0)); + // Create class member context and add public modifier + pushCurrent(new ClassMemberContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.accessibilityModifier(Modifier.PUBLIC)); + + // Create class field declaration context and add static and const modifiers + pushCurrent(new ClassFieldDeclarationContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Const)); + + // Create constant declaration context and add enum constant name and type + pushCurrent(new ConstantDeclarationContext(stsCurrent, 0)); + String javaEnumConstName = javaEnumConstant.getName().getIdentifier(); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumConstName)); + String javaEnumTypeName = (String)javaEnumConstant.getProperty(ENUM_TYPE_NAME); + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotation + + // Add initializer to constant declaration context + pushCurrent(new InitializerContext(stsCurrent, 0)); + pushCurrent(new NewClassExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)); + stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); + + // Process ctor arguments, if any. + // NOTE: Always insert name and ordinal as first two ctor arguments! + List javaEnumConstArgs = javaEnumConstant.arguments(); + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.stringLiteral(javaEnumConstName)).setParent(stsCurrent); + String javaEnumConstOrdinal = (String)javaEnumConstant.getProperty(ENUM_CONST_ORDINAL); + stsCurrent.addChild(NodeBuilder.numericLiteral(javaEnumConstOrdinal)).setParent(stsCurrent); + if (javaEnumConstArgs != null && !javaEnumConstArgs.isEmpty()) { + for (Expression javaEnumConstArg : javaEnumConstArgs) { + javaEnumConstArg.accept(this); + } + } + popCurrent(); // ExpressionSequenceContext + popCurrent(); // ArgumentsContext - // Enum constant name - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumConstant.getName())); + // Process anonymous class body, if any + AnonymousClassDeclaration javaEnumConstClassBody = javaEnumConstant.getAnonymousClassDeclaration(); + if (javaEnumConstClassBody != null) { + javaEnumConstClassBody.accept(this); + } - // TODO: Initializer + popSingleExpression(); // NewClassExpressionContext + popCurrent(); // InitializerContext - popCurrent(); // EnumMemberContext + popCurrent(); // ConstantDeclarationContext + popCurrent(); // ClassFieldDeclarationContext + popCurrent(); // ClassMemberContext + ++countDeclTransformed; return false; } @@ -1549,6 +1924,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popCurrent(); // VarOrConstDeclaration + ++countDeclTransformed; // Each VariableDeclarationFragment is a separate declaration construct! } popCurrent(); // VarOrConstDeclarationList @@ -1559,7 +1935,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | VariableDeclarationStatement // VariableDeclarationStatement: { ExtendedModifier } Type VariableDeclarationFragment { , VariableDeclarationFragment } ; // STS tree: - // topLevelElement: Export? + // topDeclaration: Export? // | variableStatement // variableStatement: ((Let variableDeclarationList) | (Const constantDeclarationList)) SemiColon // variableDeclarationList: @@ -1682,13 +2058,12 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // StaticTS doesn't have syntax for separate instance initializer blocks. // We gather all statements from such blocks in class declaration and place // at the beginning of all constructor's bodies that don't call another constructor. - - TypeDeclaration javaTypeDecl = (TypeDeclaration) javaInitializer.getParent(); - List stsInitStmts = (List) javaTypeDecl.getProperty(INSTANCE_INITIALIZER); + ASTNode javaInitParent = javaInitializer.getParent(); + List stsInitStmts = (List) javaInitParent.getProperty(INSTANCE_INITIALIZER); if (stsInitStmts == null) { stsInitStmts = new ArrayList<>(); - javaTypeDecl.setProperty(INSTANCE_INITIALIZER, stsInitStmts); + javaInitParent.setProperty(INSTANCE_INITIALIZER, stsInitStmts); } // Use dummy block here to gather translated statements. Do not @@ -1706,6 +2081,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsInitStmts.addAll(stsBlock.statementOrLocalDeclaration()); } + ++countDeclTransformed; return false; } @@ -2024,7 +2400,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(AnonymousClassDeclaration javaAnonymousClassDeclaration) { pushCurrent(new ClassBodyContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBrace)).setParent(stsCurrent); List javaBodyDeclarations = javaAnonymousClassDeclaration.bodyDeclarations(); assert (javaBodyDeclarations != null); @@ -2032,7 +2407,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaBodyDeclaration.accept(this); } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBrace)).setParent(stsCurrent); popCurrent(); // ClassBodyContext return false; } @@ -2459,8 +2833,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // ThisExpression: // [ ClassName . ] this // STS tree: - // singleExpression: - // | (typeReference Dot)? This # ThisExpression @Override public boolean visit(ThisExpression javaThisExpr) { pushCurrent(new ThisExpressionContext(pushSingleExpression())); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index aa327e05eb3d731f5bb8ae5aced35df7a4899063..fe9bf32a166d28c03dff27c856dfad7c4a9a2a77 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -49,7 +49,7 @@ public class NodeBuilder { return stsName; } - private static TerminalNode terminalIdentifier(String identifier) { + public static TerminalNode terminalIdentifier(String identifier) { return new TerminalNodeImpl(new CommonToken(StaticTSParser.Identifier, identifier)); } @@ -68,27 +68,26 @@ public class NodeBuilder { return qualifiedName(javaName.getFullyQualifiedName()); } - private static int stsTypeNameCode(PrimitiveType javaPrimitive) { + private static int stsTypeNameCode(PrimitiveType.Code javaPrimitiveTypeCode) { int stsTypeNameCode = -1; - PrimitiveType.Code javaTypeCode = javaPrimitive.getPrimitiveTypeCode(); - if (javaTypeCode == PrimitiveType.BOOLEAN) + if (javaPrimitiveTypeCode == PrimitiveType.BOOLEAN) stsTypeNameCode = StaticTSParser.Boolean; - else if (javaTypeCode == PrimitiveType.BYTE) + else if (javaPrimitiveTypeCode == PrimitiveType.BYTE) stsTypeNameCode = StaticTSParser.Byte; - else if (javaTypeCode == PrimitiveType.CHAR) + else if (javaPrimitiveTypeCode == PrimitiveType.CHAR) stsTypeNameCode = StaticTSParser.Char; - else if (javaTypeCode == PrimitiveType.INT) + else if (javaPrimitiveTypeCode == PrimitiveType.INT) stsTypeNameCode = StaticTSParser.Int; - else if (javaTypeCode == PrimitiveType.DOUBLE) + else if (javaPrimitiveTypeCode == PrimitiveType.DOUBLE) stsTypeNameCode = StaticTSParser.Double; - else if (javaTypeCode == PrimitiveType.FLOAT) + else if (javaPrimitiveTypeCode == PrimitiveType.FLOAT) stsTypeNameCode = StaticTSParser.Float; - else if (javaTypeCode == PrimitiveType.LONG) + else if (javaPrimitiveTypeCode == PrimitiveType.LONG) stsTypeNameCode = StaticTSParser.Long; - else if (javaTypeCode == PrimitiveType.SHORT) + else if (javaPrimitiveTypeCode == PrimitiveType.SHORT) stsTypeNameCode = StaticTSParser.Short; - else if (javaTypeCode == PrimitiveType.VOID) + else if (javaPrimitiveTypeCode == PrimitiveType.VOID) stsTypeNameCode = StaticTSParser.Void; else assert false : "Unknown type"; @@ -96,10 +95,10 @@ public class NodeBuilder { return stsTypeNameCode; } - public static PredefinedTypeContext predefinedType(PrimitiveType javaPrimitive) { + public static PredefinedTypeContext predefinedType(PrimitiveType.Code javaPrimitiveTypeCode) { // predefinedType -> TerminalNode PredefinedTypeContext stsPredefinedType = new PredefinedTypeContext(null, 0); - stsPredefinedType.addChild(terminalNode(stsTypeNameCode(javaPrimitive))); + stsPredefinedType.addChild(terminalNode(stsTypeNameCode(javaPrimitiveTypeCode))); return stsPredefinedType; } @@ -147,6 +146,10 @@ public class NodeBuilder { // singleExpression: | literal # LiteralExpression // literal: | CharLiteral public static SingleExpressionContext charLiteral(String value) { + // Add leading and/or terminating quotes if missing + if (!value.startsWith("'")) value = "'" + value; + if (!value.endsWith("'")) value += "'"; + SingleExpressionContext stsExpression = new SingleExpressionContext(null, 0); LiteralContext stsLiteral = new LiteralContext(null, 0); stsLiteral.addChild(new TerminalNodeImpl(new CommonToken(StaticTSParser.CharLiteral, value))); @@ -159,6 +162,11 @@ public class NodeBuilder { // singleExpression: | literal # LiteralExpression // literal: | StringLiteral public static SingleExpressionContext stringLiteral(String value) { + // Add leading and/or terminating quotes if missing + if (!value.startsWith("\"")) value = "\"" + value; + if (!value.endsWith("\"")) value += "\""; + + // TODO: Escape all unescaped characters SingleExpressionContext stsExpression = new SingleExpressionContext(null, 0); LiteralContext stsLiteral = new LiteralContext(null, 0); stsLiteral.addChild(new TerminalNodeImpl(new CommonToken(StaticTSParser.StringLiteral, value))); @@ -235,8 +243,9 @@ public class NodeBuilder { } public static TypeReferenceContext typeReference(PrimitiveType javaPrimitivetype) { + PrimitiveType.Code javaPrimitiveTypeCode = javaPrimitivetype.getPrimitiveTypeCode(); TypeReferenceContext stsTypeReference = new TypeReferenceContext(null, 0); - stsTypeReference.addChild(qualifiedName(stsName(stsTypeNameCode(javaPrimitivetype)))).setParent(stsTypeReference); + stsTypeReference.addChild(qualifiedName(stsName(stsTypeNameCode(javaPrimitiveTypeCode)))).setParent(stsTypeReference); return stsTypeReference; } public static TypeReferenceContext typeReference(String stsQualifierText, Name javaName) { @@ -316,4 +325,72 @@ public class NodeBuilder { stsArrayType.addChild(terminalNode(StaticTSParser.CloseBracket)); } } + + public static ArrayTypeContext arrayType(String elementTypeName, int dimensions) { + ArrayTypeContext stsArrayType = new ArrayTypeContext(null, 0); + stsArrayType.addChild(typeReference(elementTypeName)).setParent(stsArrayType); + for (int i = 0; i < dimensions; ++i) { + stsArrayType.addChild(terminalNode(StaticTSParser.OpenBracket)); + stsArrayType.addChild(terminalNode(StaticTSParser.CloseBracket)); + } + return stsArrayType; + } + + public static TypeAnnotationContext typeAnnotation(TypeReferenceContext stsTypeRef) { + TypeAnnotationContext stsTypeAnno = new TypeAnnotationContext(null, 0); + PrimaryTypeContext stsPrimaryType = new PrimaryTypeContext(stsTypeAnno, 0); + stsPrimaryType.addChild(stsTypeRef).setParent(stsPrimaryType); + stsTypeAnno.addChild(stsPrimaryType).setParent(stsTypeAnno); + return stsTypeAnno; + } + + public static TypeAnnotationContext typeAnnotation(String stsTypeName) { + TypeReferenceContext stsTypeRef = typeReference(stsTypeName); + return typeAnnotation(stsTypeRef); + } + + public static TypeAnnotationContext typeAnnotation(PredefinedTypeContext stsPredefType) { + TypeAnnotationContext stsTypeAnno = new TypeAnnotationContext(null, 0); + PrimaryTypeContext stsPrimaryType = new PrimaryTypeContext(stsTypeAnno, 0); + stsPrimaryType.addChild(stsPredefType).setParent(stsPrimaryType); + stsTypeAnno.addChild(stsPrimaryType).setParent(stsTypeAnno); + return stsTypeAnno; + } + public static TypeAnnotationContext typeAnnotation(ArrayTypeContext stsArrayType) { + TypeAnnotationContext stsTypeAnno = new TypeAnnotationContext(null, 0); + PrimaryTypeContext stsPrimaryType = new PrimaryTypeContext(stsTypeAnno, 0); + stsPrimaryType.addChild(stsArrayType).setParent(stsPrimaryType); + stsTypeAnno.addChild(stsPrimaryType).setParent(stsTypeAnno); + return stsTypeAnno; + } + + public static ParameterContext parameter(String stsParamName, String stsParamType) { + ParameterContext stsParam = new ParameterContext(null, 0); + stsParam.addChild(terminalIdentifier(stsParamName)); + stsParam.addChild(typeAnnotation(stsParamType)).setParent(stsParam); + return stsParam; + } + + public static ParameterContext parameter(String stsParamName, PrimitiveType.Code javaPrimitiveTypeCode) { + ParameterContext stsParam = new ParameterContext(null, 0); + stsParam.addChild(terminalIdentifier(stsParamName)); + stsParam.addChild(typeAnnotation(predefinedType(javaPrimitiveTypeCode))).setParent(stsParam); + return stsParam; + } + + public static ConstructorCallContext ctorCall(boolean isSuperCall, String... stsArgNames) { + ConstructorCallContext stsSuperCtorCall = new ConstructorCallContext(null, 0); + stsSuperCtorCall.addChild(terminalNode(isSuperCall ? StaticTSParser.Super : StaticTSParser.This)); + + ArgumentsContext stsSuperCtorCallArgs = new ArgumentsContext(stsSuperCtorCall, 0); + stsSuperCtorCall.addChild(stsSuperCtorCallArgs).setParent(stsSuperCtorCall); + ExpressionSequenceContext stsExprSeq = new ExpressionSequenceContext(stsSuperCtorCallArgs, 0); + stsSuperCtorCallArgs.addChild(stsExprSeq).setParent(stsSuperCtorCallArgs); + + for (String stsArgName : stsArgNames) { + stsExprSeq.addChild(identifierExpression(stsArgName)).setParent(stsExprSeq); + } + + return stsSuperCtorCall; + } } diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 9835f278051dac775c76b145f4adab44f58333d5..51d8582b835bfafff5d15b6a472a54a55a075dd2 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -126,13 +126,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // typeParameterList: typeParameter (',' typeParameter)*; @Override public Void visitTypeParameterList(TypeParameterListContext stsTypeParameterList) { + int i = 0; for (TypeParameterContext stsTypeParameter : stsTypeParameterList.typeParameter()) { + if (i > 0) sb.append(", "); visitTypeParameter(stsTypeParameter); - sb.append(", "); + ++i; } - sb.setLength(sb.length() - 2); // Cut off the ending extra ", "; - return null; } @@ -187,13 +187,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // typeArgumentList: typeArgument (',' typeArgument)* @Override public Void visitTypeArgumentList(TypeArgumentListContext stsTypeArgumentList) { + int i = 0; for (TypeArgumentContext stsTypeArgument : stsTypeArgumentList.typeArgument()) { + if (i > 0) sb.append(", "); visitTypeArgument(stsTypeArgument); - sb.append(", "); + ++i; } - sb.setLength(sb.length() - 2); // Cut off the ending extra ", ". - return null; } @@ -292,12 +292,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // qualifiedName: Identifier (Dot Identifier)* @Override public Void visitQualifiedName(QualifiedNameContext stsQualName) { + int i = 0; for (TerminalNode identifier : stsQualName.Identifier()) { - sb.append(identifier.getText()).append('.'); + sb.append(identifier.getText()); + if (i > 0) sb.append('.'); + ++i; } - sb.setLength(sb.length() - 1); // Cut off the ending extra '.' - return null; } @@ -556,13 +557,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // classOrInterfaceTypeList: typeReference (',' typeReference)* @Override public Void visitInterfaceTypeList(InterfaceTypeListContext stsClassOrInterfaceTypeList) { + int i = 0; for (TypeReferenceContext stsTypeReference : stsClassOrInterfaceTypeList.typeReference()) { + if (i > 0) sb.append(", "); visitTypeReference(stsTypeReference); - sb.append(", "); + ++i; } - sb.setLength(sb.length() - 2); // Cut off the ending extra ", " - return null; } @@ -782,26 +783,25 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // variableDeclarationList: variableDeclaration (',' variableDeclaration)* @Override public Void visitVariableDeclarationList(VariableDeclarationListContext stsVariableDeclarationList) { + int i = 0; for (VariableDeclarationContext stsVariableDeclaration : stsVariableDeclarationList.variableDeclaration()) { + if (i > 0) sb.append(", "); visitVariableDeclaration(stsVariableDeclaration); - sb.append(", "); + ++i; } - - sb.setLength(sb.length() - 2); // Cut off the ending extra ", " - return null; } // constantDeclarationList: constantDeclaration (',' constantDeclaration)* @Override public Void visitConstantDeclarationList(ConstantDeclarationListContext stsConstantDeclarationList) { + int i = 0; for (ConstantDeclarationContext stsConstantDeclaration : stsConstantDeclarationList.constantDeclaration()) { + if (i > 0) sb.append(", "); visitConstantDeclaration(stsConstantDeclaration); - sb.append(", "); + ++i; } - sb.setLength(sb.length() - 2); // Cut off the ending extra ", " - return null; } @@ -961,14 +961,14 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // expressionSequence: singleExpression (',' singleExpression)* @Override public Void visitExpressionSequence(ExpressionSequenceContext stsExpressionSequence) { + int i = 0; for (SingleExpressionContext stsExpression : stsExpressionSequence.singleExpression()) { + if (i > 0) sb.append(", "); stsExpression.accept(this); - sb.append(", "); + ++i; } - sb.setLength(sb.length() - 2); // Cut off trailing ", " - - return null; + return null; } // | For '(' Let Identifier typeAnnotation? Of singleExpression ')' (statement | block) # ForInOfStatement @@ -1305,7 +1305,11 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitChildren(stsClassBody); indentDecrement(); - sb.append(indentCurrent).append("}\n\n"); + sb.append(indentCurrent).append("}"); + + // Don't start new line if this class body is a part of a object creation expression + if (!(stsClassBody.getParent() instanceof NewClassExpressionContext)) + sb.append("\n\n"); return null; } @@ -1411,12 +1415,12 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { List stsParameters = stsParameterList.parameter(); if (stsParameters != null) { + int i = 0; for (ParameterContext stsParameter : stsParameters) { + if (i > 0) sb.append(", "); visitParameter(stsParameter); - sb.append(", "); + ++i; } - - sb.setLength(sb.length() - 2); // Cut off trailing ", " } VariadicParameterContext stsVariadicParameter = stsParameterList.variadicParameter(); diff --git a/migrator/test/java/class_instance_creation.java b/migrator/test/java/class_instance_creation.java index 223ddcc5a66f15b1e473f16f41610bcedb0ad044..53d1eb020f644c0029497a93c44da23f9a1dcd60 100644 --- a/migrator/test/java/class_instance_creation.java +++ b/migrator/test/java/class_instance_creation.java @@ -20,7 +20,13 @@ class class_instance_creation { class_instance_creation() {} class_instance_creation(String s, double d) {} + public void foo() { } + static class_instance_creation inst1 = new class_instance_creation(); static class_instance_creation inst2 = new class_instance_creation(3); static class_instance_creation inst3 = new class_instance_creation("ss", 7.8); + static class_instance_creation inst4 = new class_instance_creation(3) { + private int f; + public void foo() { f = 2; } + }; } diff --git a/migrator/test/java/class_instance_creation.java.sts b/migrator/test/java/class_instance_creation.java.sts index 2dec21a27adcb447d2094a7f8de291a8ccfe0b66..73b5678318ce06598c48c50fc23aaeaac287b0c7 100644 --- a/migrator/test/java/class_instance_creation.java.sts +++ b/migrator/test/java/class_instance_creation.java.sts @@ -24,8 +24,17 @@ open class class_instance_creation { constructor(s : String, d : double) { } + public open foo(): void { + } + static inst1 : class_instance_creation = new class_instance_creation(); static inst2 : class_instance_creation = new class_instance_creation(3); static inst3 : class_instance_creation = new class_instance_creation("ss", 7.8); + static inst4 : class_instance_creation = new class_instance_creation(3) { + private f : int ; + public override foo(): void { + f = 2; + } + }; } diff --git a/migrator/test/java/class_instance_initializer.java b/migrator/test/java/class_instance_initializer.java index 1279d786ef0b3e5a0a560a70696f2288ff76eb8b..959ad31af8dcea2387d85e6501d86ded0de2e54f 100644 --- a/migrator/test/java/class_instance_initializer.java +++ b/migrator/test/java/class_instance_initializer.java @@ -76,4 +76,11 @@ class B extends A { c = 500; d = 600; } -} \ No newline at end of file +} + +// instance initializer without ctors +class C { + String foo; + + { foo = "bar"; } +} diff --git a/migrator/test/java/class_instance_initializer.java.sts b/migrator/test/java/class_instance_initializer.java.sts index 298d22cea75c321afeae0f3b464cb2e393a44e63..c77a40cc6db0538bf23e3e8911a7cff1f4ab7b23 100644 --- a/migrator/test/java/class_instance_initializer.java.sts +++ b/migrator/test/java/class_instance_initializer.java.sts @@ -65,3 +65,10 @@ open class B extends A { } +open class C { + foo : String ; + + public constructor() { + foo = "bar"; + } +} diff --git a/migrator/test/java/enum_with_class_behavior.java b/migrator/test/java/enum_with_class_behavior.java index a2524adc97ba583db831492f3c1ec2e076cab012..2331696add1f420761a96ce822c62bcfb44a78df 100644 --- a/migrator/test/java/enum_with_class_behavior.java +++ b/migrator/test/java/enum_with_class_behavior.java @@ -36,7 +36,13 @@ enum ArithmeticOperation implements IOperation { DIVIDE { @Override public int apply(int a, int b) { return a / b; } - } + }; + + // tests enum instance initializer translation + // super(name, ordinal) call should be inserted + // into resulting ctor! + private String foo; + { foo = "bar"; } } // Enum declaration with type members (ctor, methods, etc). @@ -46,17 +52,30 @@ enum Planet { VENUS (4.869e+24, 6.0518e6), EARTH (5.976e+24, 6.37814e6), MARS (6.421e+23, 3.3972e6), - JUPITER (1.9e+27, 7.1492e7), - SATURN (5.688e+26, 6.0268e7), - URANUS (8.686e+25, 2.5559e7), - NEPTUNE (1.024e+26, 2.4746e7); + JUPITER (1.9e+27, 7.1492e7, PlanetType.GAS), + SATURN (5.688e+26, 6.0268e7, PlanetType.GAS), + URANUS (8.686e+25, 2.5559e7, PlanetType.ICE), + NEPTUNE (1.024e+26, 2.4746e7, PlanetType.ICE); + + enum PlanetType { + ROCK, + GAS, + ICE + } private final double mass; // in kilograms private final double radius; // in meters + private final PlanetType type; - Planet(double mass, double radius) { + Planet(double mass, double radius, PlanetType type) { this.mass = mass; this.radius = radius; + this.type = type; + } + + Planet(double mass, double radius) { + // No super(name, ordinal) call in translation here! + this(mass, radius, PlanetType.ROCK); } // universal gravitational constant (m3 kg-1 s-2) @@ -69,4 +88,4 @@ enum Planet { double surfaceWeight(double otherMass) { return otherMass * surfaceGravity(); } -} \ No newline at end of file +} diff --git a/migrator/test/java/enum_with_class_behavior.java.sts b/migrator/test/java/enum_with_class_behavior.java.sts index 63344485c714c8ed039906e73418c5bf310740d2..6fab978ac04fd1519eb76005d5a594c8711e98ac 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -18,19 +18,106 @@ interface IOperation { apply(a : int, b : int): int ; } -enum ArithmeticOperation { - PLUS, - MINUS, - MULTIPLY, - DIVIDE +open class ArithmeticOperation extends Enum implements IOperation { + public static const PLUS : ArithmeticOperation = new ArithmeticOperation("PLUS", 0) { + public override apply(a : int, b : int): int { + return a + b; + } + }; + public static const MINUS : ArithmeticOperation = new ArithmeticOperation("MINUS", 1) { + public override apply(a : int, b : int): int { + return a - b; + } + }; + public static const MULTIPLY : ArithmeticOperation = new ArithmeticOperation("MULTIPLY", 2) { + public override apply(a : int, b : int): int { + return a * b; + } + }; + public static const DIVIDE : ArithmeticOperation = new ArithmeticOperation("DIVIDE", 3) { + public override apply(a : int, b : int): int { + return a / b; + } + }; + + private foo : String ; + + public static values(): ArithmeticOperation[] { + return [PLUS, MINUS, MULTIPLY, DIVIDE]; + } + public static valueOf(name : String): ArithmeticOperation { + for (let value : ArithmeticOperation of values()){ + if (name == value.toString()) return value; + } + return null; + } + + private constructor(name : String, ordinal : int) { + super(name, ordinal); + foo = "bar"; + } } -enum Planet { - MERCURY, - VENUS, - EARTH, - MARS, - JUPITER, - SATURN, - URANUS, - NEPTUNE +class Planet extends Enum { + public static const MERCURY : Planet = new Planet("MERCURY", 0, 3.303e+23, 2.4397e6); + public static const VENUS : Planet = new Planet("VENUS", 1, 4.869e+24, 6.0518e6); + public static const EARTH : Planet = new Planet("EARTH", 2, 5.976e+24, 6.37814e6); + public static const MARS : Planet = new Planet("MARS", 3, 6.421e+23, 3.3972e6); + public static const JUPITER : Planet = new Planet("JUPITER", 4, 1.9e+27, 7.1492e7, PlanetType.GAS); + public static const SATURN : Planet = new Planet("SATURN", 5, 5.688e+26, 6.0268e7, PlanetType.GAS); + public static const URANUS : Planet = new Planet("URANUS", 6, 8.686e+25, 2.5559e7, PlanetType.ICE); + public static const NEPTUNE : Planet = new Planet("NEPTUNE", 7, 1.024e+26, 2.4746e7, PlanetType.ICE); + + static class PlanetType extends Enum { + public static const ROCK : PlanetType = new PlanetType("ROCK", 0); + public static const GAS : PlanetType = new PlanetType("GAS", 1); + public static const ICE : PlanetType = new PlanetType("ICE", 2); + + public static values(): PlanetType[] { + return [ROCK, GAS, ICE]; + } + public static valueOf(name : String): PlanetType { + for (let value : PlanetType of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } + } + + private mass : double ; + private radius : double ; + private type : PlanetType ; + + constructor(name : String, ordinal : int, mass : double, radius : double, type : PlanetType) { + super(name, ordinal); + this.mass = mass; + this.radius = radius; + this.type = type; + } + + constructor(name : String, ordinal : int, mass : double, radius : double) { + this(name, ordinal, mass, radius, PlanetType.ROCK); + } + + public static const G : double = 6.67300E-11; + + open surfaceGravity(): double { + return G * mass / (radius * radius); + } + + open surfaceWeight(otherMass : double): double { + return otherMass * surfaceGravity(); + } + + public static values(): Planet[] { + return [MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE]; + } + public static valueOf(name : String): Planet { + for (let value : Planet of values()){ + if (name == value.toString()) return value; + } + return null; + } } diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index d0197e84a18ab2af42d97c07575bfbabcb556058..681a206d0c6673ed9086b4eacc048bd88b8c63d6 100644 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -28,9 +28,7 @@ open class SubClass1 extends SuperClass { public open run(): void { SubClass1.super.foo(); } - } - -; + }; } interface SuperInterface { @@ -53,9 +51,7 @@ open class SubClass3 implements SuperInterface { tweak : Runnable = new Runnable() { public open run(): void { } - } - -; + }; } open class Doubler { diff --git a/migrator/test/java/switch_statement.java.sts b/migrator/test/java/switch_statement.java.sts index 0e10a1c587e9c8a4e8a74bd6a60ee71459f1c190..36e61cd3b2975a6303b46c00a6fc5a33f331e637 100644 --- a/migrator/test/java/switch_statement.java.sts +++ b/migrator/test/java/switch_statement.java.sts @@ -223,11 +223,25 @@ export open class switch_statement { } } - enum Color { - Red, - Green, - Blue + + static class Color extends Enum { + public static const Red : Color = new Color("Red", 0); + public static const Green : Color = new Color("Green", 1); + public static const Blue : Color = new Color("Blue", 2); + public static values(): Color[] { + return [Red, Green, Blue]; + } + public static valueOf(name : String): Color { + for (let value : Color of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } + private static SwitchWithEnumValues(): void { let color : Color = Color.Green; switch (color) { diff --git a/migrator/test/java/test_enum.java.sts b/migrator/test/java/test_enum.java.sts index 05aaf180da5195dd7a52c9c994f23e3a0e09278e..5f835b0403abe9929731f93eb787a7f4f06e22c5 100644 --- a/migrator/test/java/test_enum.java.sts +++ b/migrator/test/java/test_enum.java.sts @@ -14,41 +14,118 @@ */ package com.ohos.migrator.test.java; -export enum test_enum { +export class test_enum extends Enum { + public static values(): test_enum[] { + return []; + } + public static valueOf(name : String): test_enum { + for (let value : test_enum of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } -enum Planet { - MERCURY, - VENUS, - EARTH, - MARS, - JUPITER, - SATURN, - URANUS, - NEPTUNE +class Planet extends Enum { + public static const MERCURY : Planet = new Planet("MERCURY", 0); + public static const VENUS : Planet = new Planet("VENUS", 1); + public static const EARTH : Planet = new Planet("EARTH", 2); + public static const MARS : Planet = new Planet("MARS", 3); + public static const JUPITER : Planet = new Planet("JUPITER", 4); + public static const SATURN : Planet = new Planet("SATURN", 5); + public static const URANUS : Planet = new Planet("URANUS", 6); + public static const NEPTUNE : Planet = new Planet("NEPTUNE", 7); + + public static values(): Planet[] { + return [MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE]; + } + public static valueOf(name : String): Planet { + for (let value : Planet of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } open class NestedEnums { - private enum Colors { - RED, - GREEN, - BLUE - } - protected enum Size { - SMALL, - MEDIUM, - LARGE - } - public enum Direction { - NORTH, - EAST, - SOUTH, - WEST - } - enum Operator { - PLUS, - MINUS, - MULTIPLY, - DIVIDE + private static class Colors extends Enum { + public static const RED : Colors = new Colors("RED", 0); + public static const GREEN : Colors = new Colors("GREEN", 1); + public static const BLUE : Colors = new Colors("BLUE", 2); + + public static values(): Colors[] { + return [RED, GREEN, BLUE]; + } + public static valueOf(name : String): Colors { + for (let value : Colors of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } + } + protected static class Size extends Enum { + public static const SMALL : Size = new Size("SMALL", 0); + public static const MEDIUM : Size = new Size("MEDIUM", 1); + public static const LARGE : Size = new Size("LARGE", 2); + + public static values(): Size[] { + return [SMALL, MEDIUM, LARGE]; + } + public static valueOf(name : String): Size { + for (let value : Size of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } + } + public static class Direction extends Enum { + public static const NORTH : Direction = new Direction("NORTH", 0); + public static const EAST : Direction = new Direction("EAST", 1); + public static const SOUTH : Direction = new Direction("SOUTH", 2); + public static const WEST : Direction = new Direction("WEST", 3); + + public static values(): Direction[] { + return [NORTH, EAST, SOUTH, WEST]; + } + public static valueOf(name : String): Direction { + for (let value : Direction of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } + } + static class Operator extends Enum { + public static const PLUS : Operator = new Operator("PLUS", 0); + public static const MINUS : Operator = new Operator("MINUS", 1); + public static const MULTIPLY : Operator = new Operator("MULTIPLY", 2); + public static const DIVIDE : Operator = new Operator("DIVIDE", 3); + + public static values(): Operator[] { + return [PLUS, MINUS, MULTIPLY, DIVIDE]; + } + public static valueOf(name : String): Operator { + for (let value : Operator of values()){ + if (name == value.toString()) return value; + } + return null; + } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } }