From 029d77ea66842fad061f6abdcf99e417cd680ed2 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Wed, 3 Aug 2022 17:17:16 +0300 Subject: [PATCH 1/8] Enum translation (incomplete). Also minor bugfix and housekeeping in JavaTransformer code. Changes to tests to account for all of the above. Change-Id: I244038b63e07240aed4a882cab6385a07a50c487 Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 262 ++++++++++++++---- .../ohos/migrator/staticTS/NodeBuilder.java | 2 +- .../staticTS/writer/StaticTSWriter.java | 58 ++-- .../test/java/class_instance_creation.java | 6 + .../java/class_instance_creation.java.sts | 9 + .../java/enum_with_class_behavior.java.sts | 69 ++++- migrator/test/java/method_invocation.java.sts | 8 +- migrator/test/java/test_enum.java.sts | 80 ++++-- 8 files changed, 361 insertions(+), 133 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 0292b37ba..601a93241 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -43,8 +43,11 @@ 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 static int countStmtTotal = 0; private static int countExprTotal = 0; private static int countExprTransformed = 0; @@ -187,14 +190,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 +209,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 +241,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 +261,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // { { InterfaceBodyDeclaration | ; } } // // STS tree for interface: - // TopLevelElementContext + // topDeclarationContext // InterfaceDeclarationContext // TerminalNode // TerminalNode @@ -280,8 +272,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 @@ -541,20 +533,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 +563,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 } @@ -1386,6 +1385,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { 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,55 +1398,207 @@ 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)); + + // Create class declaration context + ClassDeclarationContext stsClassDecl = new ClassDeclarationContext(stsCurrent, 0); + pushCurrent(stsClassDecl); + + // Set static modifier as necessary. + if (stsCurrent.getParent().getRuleIndex() != StaticTSParser.RULE_topDeclaration) { + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); + } - // Add remaining (non-access) modifiers and enum keyword. - translateNonAccessModifiers(javaEnumDeclaration); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Enum)); + // 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()); + + // Add implements clause, if necessary + translateSuperInterfaceTypes(javaEnumDeclaration.superInterfaceTypes()); + + pushCurrent(new ClassBodyContext(stsCurrent, 0)); - // Enum name - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumDeclaration.getName())); + // 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; + List javaEnumConstNames = new ArrayList<>(); + List javaEnumConstants = javaEnumDeclaration.enumConstants(); + for (EnumConstantDeclaration javaEnumConst : javaEnumConstants) { + if (!needOpen) needOpen = javaEnumConst.getAnonymousClassDeclaration() != null; - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBrace)); + // Pass enum name to enum constant node before visiting it + // as we'll need it to create appropriate initializers. + javaEnumConst.setProperty(ENUM_TYPE_NAME, javaEnumName.getIdentifier()); - pushCurrent(new EnumBodyContext(stsCurrent, 0)); + // 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); } + if (needOpen) { + stsClassDecl.children.add(0, NodeBuilder.terminalNode(StaticTSParser.Open)); + } - popCurrent(); // EnumBodyContext + // Translate body declarations (ctors, methods, nested types, and fields). + List javaEnumBodyDecls = javaEnumDeclaration.bodyDeclarations(); + for (BodyDeclaration javaEnumBodyDecl : javaEnumBodyDecls) { + javaEnumBodyDecl.accept(this); + } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBrace)); + // TODO: valueOf(), toString() and ordinal() methods! + createEnumValuesMethod(javaEnumDeclaration.getName().getIdentifier(), javaEnumConstNames); - popCurrent(); // EnumDeclarationContext - popCurrent(); // stsMemberContext + popCurrent(); // ClassBodyContext + popCurrent(); // stsClassDecl + popCurrent(); // member context return false; } + 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 createEnumValuesMethod(String javaEnumTypeName, List javaEnumConstNames) { + // Create class member context and add public modifier + pushCurrent(new ClassMemberContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.accessibilityModifier(Modifier.PUBLIC)); + + // Create class declaration context and add static modifier + pushCurrent(new ClassMethodDeclarationContext(stsCurrent, 0)); + pushCurrent(new ClassMethodWithBodyContext((ClassMethodDeclarationContext)stsCurrent)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); + + // Add method name and signature + stsCurrent.addChild(NodeBuilder.terminalIdentifier("values")); + pushCurrent(new SignatureContext(stsCurrent, 0)); + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + pushCurrent(new ArrayTypeContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBracket)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBracket)); + popCurrent(); // ArrayTypeContext + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotationContext + popCurrent(); // SignatureContext + + // Add function body + 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 + + popCurrent(); // ClassMethodWithBodyContext + popCurrent(); // ClassMethodDeclarationContext + popCurrent(); // ClassMemberContext + } @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)); - // Enum constant name + // 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)); stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumConstant.getName())); + 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 - // TODO: Initializer + // 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); - popCurrent(); // EnumMemberContext + // Process ctor arguments, if any + List javaEnumConstArgs = javaEnumConstant.arguments(); + if (javaEnumConstArgs != null && !javaEnumConstArgs.isEmpty()) { + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); + for (Expression javaEnumConstArg : javaEnumConstArgs) { + javaEnumConstArg.accept(this); + } + popCurrent(); // ExpressionSequenceContext + popCurrent(); // ArgumentsContext + } + + // Process anonymous class body, if any + AnonymousClassDeclaration javaEnumConstClassBody = javaEnumConstant.getAnonymousClassDeclaration(); + if (javaEnumConstClassBody != null) { + javaEnumConstClassBody.accept(this); + } + + popSingleExpression(); // NewClassExpressionContext + popCurrent(); // InitializerContext + + popCurrent(); // ConstantDeclarationContext + popCurrent(); // ClassFieldDeclarationContext + popCurrent(); // ClassMemberContext return false; } @@ -1559,7 +1713,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: @@ -2024,7 +2178,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 +2185,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 +2611,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 aa327e05e..b0e1182c3 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)); } diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 9835f2780..51d8582b8 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 223ddcc5a..53d1eb020 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 2dec21a27..73b567831 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/enum_with_class_behavior.java.sts b/migrator/test/java/enum_with_class_behavior.java.sts index 63344485c..d47fe7b36 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -18,19 +18,60 @@ 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 { + public override apply(a : int, b : int): int { + return a + b; + } + }; + public static const MINUS : ArithmeticOperation = new ArithmeticOperation { + public override apply(a : int, b : int): int { + return a - b; + } + }; + public static const MULTIPLY : ArithmeticOperation = new ArithmeticOperation { + public override apply(a : int, b : int): int { + return a * b; + } + }; + public static const DIVIDE : ArithmeticOperation = new ArithmeticOperation { + public override apply(a : int, b : int): int { + return a / b; + } + }; + public static values(): ArithmeticOperation[] { + return [PLUS, MINUS, MULTIPLY, DIVIDE]; + } } -enum Planet { - MERCURY, - VENUS, - EARTH, - MARS, - JUPITER, - SATURN, - URANUS, - NEPTUNE +class Planet extends Enum { + public static const MERCURY : Planet = new Planet(3.303e+23, 2.4397e6); + public static const VENUS : Planet = new Planet(4.869e+24, 6.0518e6); + public static const EARTH : Planet = new Planet(5.976e+24, 6.37814e6); + public static const MARS : Planet = new Planet(6.421e+23, 3.3972e6); + public static const JUPITER : Planet = new Planet(1.9e+27, 7.1492e7); + public static const SATURN : Planet = new Planet(5.688e+26, 6.0268e7); + public static const URANUS : Planet = new Planet(8.686e+25, 2.5559e7); + public static const NEPTUNE : Planet = new Planet(1.024e+26, 2.4746e7); + + private mass : double ; + private radius : double ; + + constructor(mass : double, radius : double) { + this.mass = mass; + this.radius = radius; + } + + 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]; + } } diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index d0197e84a..681a206d0 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/test_enum.java.sts b/migrator/test/java/test_enum.java.sts index 05aaf180d..9958c48d3 100644 --- a/migrator/test/java/test_enum.java.sts +++ b/migrator/test/java/test_enum.java.sts @@ -14,41 +14,63 @@ */ package com.ohos.migrator.test.java; -export enum test_enum { - +export class test_enum extends Enum { + public static values(): test_enum[] { + return []; + } } -enum Planet { - MERCURY, - VENUS, - EARTH, - MARS, - JUPITER, - SATURN, - URANUS, - NEPTUNE +class Planet extends Enum { + public static const MERCURY : Planet = new Planet; + public static const VENUS : Planet = new Planet; + public static const EARTH : Planet = new Planet; + public static const MARS : Planet = new Planet; + public static const JUPITER : Planet = new Planet; + public static const SATURN : Planet = new Planet; + public static const URANUS : Planet = new Planet; + public static const NEPTUNE : Planet = new Planet; + + public static values(): Planet[] { + return [MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE]; + } } open class NestedEnums { - private enum Colors { - RED, - GREEN, - BLUE + private static class Colors extends Enum { + public static const RED : Colors = new Colors; + public static const GREEN : Colors = new Colors; + public static const BLUE : Colors = new Colors; + + public static values(): Colors[] { + return [RED, GREEN, BLUE]; + } } - protected enum Size { - SMALL, - MEDIUM, - LARGE + protected static class Size extends Enum { + public static const SMALL : Size = new Size; + public static const MEDIUM : Size = new Size; + public static const LARGE : Size = new Size; + + public static values(): Size[] { + return [SMALL, MEDIUM, LARGE]; + } } - public enum Direction { - NORTH, - EAST, - SOUTH, - WEST + public static class Direction extends Enum { + public static const NORTH : Direction = new Direction; + public static const EAST : Direction = new Direction; + public static const SOUTH : Direction = new Direction; + public static const WEST : Direction = new Direction; + + public static values(): Direction[] { + return [NORTH, EAST, SOUTH, WEST]; + } } - enum Operator { - PLUS, - MINUS, - MULTIPLY, - DIVIDE + static class Operator extends Enum { + public static const PLUS : Operator = new Operator; + public static const MINUS : Operator = new Operator; + public static const MULTIPLY : Operator = new Operator; + public static const DIVIDE : Operator = new Operator; + + public static values(): Operator[] { + return [PLUS, MINUS, MULTIPLY, DIVIDE]; + } } } -- Gitee From 16c9fdddd778a643a7d1acdb30e958d3dc076880 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Thu, 4 Aug 2022 15:19:32 +0300 Subject: [PATCH 2/8] Enum translation: Implemented valueOf method and updates to tests to cover these changes. Also minor fix to error processing. Change-Id: I4278b38afc634c2f05559edb301cfb70c9d93517 Signed-off-by: Mikhail Velikanov --- .../com/ohos/migrator/AbstractTranspiler.java | 7 + .../ohos/migrator/java/JavaTransformer.java | 122 ++++++++++++++++-- .../java/enum_with_class_behavior.java.sts | 12 ++ migrator/test/java/test_enum.java.sts | 37 ++++++ 4 files changed, 170 insertions(+), 8 deletions(-) diff --git a/migrator/src/com/ohos/migrator/AbstractTranspiler.java b/migrator/src/com/ohos/migrator/AbstractTranspiler.java index 015b99104..f727ac86d 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/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 601a93241..f2169c726 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -1477,8 +1477,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaEnumBodyDecl.accept(this); } - // TODO: valueOf(), toString() and ordinal() methods! - createEnumValuesMethod(javaEnumDeclaration.getName().getIdentifier(), javaEnumConstNames); + // TODO: toString() and ordinal() methods! + String javaEnumTypeName = javaEnumDeclaration.getName().getIdentifier(); + createEnumValuesMethod(javaEnumTypeName, javaEnumConstNames); + createEnumValueOfMethod(javaEnumTypeName); popCurrent(); // ClassBodyContext popCurrent(); // stsClassDecl @@ -1506,15 +1508,29 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ClassExtendsClauseContext } - private void createEnumValuesMethod(String javaEnumTypeName, List javaEnumConstNames) { + private void pushEnumBuiltinMethod() { // Create class member context and add public modifier pushCurrent(new ClassMemberContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.accessibilityModifier(Modifier.PUBLIC)); - // Create class declaration context and add static modifier + // 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")); @@ -1530,7 +1546,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // TypeAnnotationContext popCurrent(); // SignatureContext - // Add function body + // Add method body + // return [ enum_constant1, enum_constant2, ... ]; pushCurrent(new BlockContext(stsCurrent, 0)); pushStatement(new ReturnStatementContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Return)); @@ -1544,9 +1561,98 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // ReturnStatementContext popCurrent(); // BlockContext - popCurrent(); // ClassMethodWithBodyContext - popCurrent(); // ClassMethodDeclarationContext - popCurrent(); // ClassMemberContext + 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)); + pushCurrent(new ParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("name")); + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.typeReference("String")).setParent(stsCurrent); + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotationContext + popCurrent(); // ParameterContext + popCurrent(); // ParameterListContext + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotationContext + 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")); + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotationContext + 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) { diff --git a/migrator/test/java/enum_with_class_behavior.java.sts b/migrator/test/java/enum_with_class_behavior.java.sts index d47fe7b36..fe0a741d1 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -42,6 +42,12 @@ open class ArithmeticOperation extends Enum implements IOpe 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; + } } class Planet extends Enum { public static const MERCURY : Planet = new Planet(3.303e+23, 2.4397e6); @@ -74,4 +80,10 @@ class Planet extends Enum { 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/test_enum.java.sts b/migrator/test/java/test_enum.java.sts index 9958c48d3..e0893fd67 100644 --- a/migrator/test/java/test_enum.java.sts +++ b/migrator/test/java/test_enum.java.sts @@ -18,6 +18,13 @@ 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; + } + } class Planet extends Enum { public static const MERCURY : Planet = new Planet; @@ -32,6 +39,12 @@ class Planet extends Enum { 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; + } } open class NestedEnums { private static class Colors extends Enum { @@ -42,6 +55,12 @@ open class NestedEnums { 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; + } } protected static class Size extends Enum { public static const SMALL : Size = new Size; @@ -51,6 +70,12 @@ open class NestedEnums { 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; + } } public static class Direction extends Enum { public static const NORTH : Direction = new Direction; @@ -61,6 +86,12 @@ open class NestedEnums { 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; + } } static class Operator extends Enum { public static const PLUS : Operator = new Operator; @@ -71,6 +102,12 @@ open class NestedEnums { 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; + } } } -- Gitee From 22f634512a531ea458050ad83ac64f3efc479a6e Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Thu, 4 Aug 2022 17:14:35 +0300 Subject: [PATCH 3/8] Minor refactoring of the code around enum translation. Change-Id: I017b70ce1ae1509c757ace4e5fb323d2ca63b938 Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 29 +++-------------- .../ohos/migrator/staticTS/NodeBuilder.java | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index f2169c726..1ab0a24dc 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -1535,15 +1535,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Add method name and signature stsCurrent.addChild(NodeBuilder.terminalIdentifier("values")); pushCurrent(new SignatureContext(stsCurrent, 0)); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - pushCurrent(new ArrayTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBracket)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBracket)); - popCurrent(); // ArrayTypeContext - popCurrent(); // PrimaryTypeContext - popCurrent(); // TypeAnnotationContext + ArrayTypeContext stsReturnType = NodeBuilder.arrayType(javaEnumTypeName, 1); + stsCurrent.addChild(NodeBuilder.typeAnnotation(stsReturnType)).setParent(stsCurrent); popCurrent(); // SignatureContext // Add method body @@ -1580,18 +1573,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new ParameterListContext(stsCurrent, 0)); pushCurrent(new ParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier("name")); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference("String")).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext - popCurrent(); // TypeAnnotationContext + stsCurrent.addChild(NodeBuilder.typeAnnotation("String")).setParent(stsCurrent); popCurrent(); // ParameterContext popCurrent(); // ParameterListContext - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext - popCurrent(); // TypeAnnotationContext + stsCurrent.addChild(NodeBuilder.typeAnnotation(javaEnumTypeName)).setParent(stsCurrent); popCurrent(); // SignatureContext // Add method body @@ -1601,11 +1586,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.For)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Let)); stsCurrent.addChild(NodeBuilder.terminalIdentifier("value")); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext - popCurrent(); // TypeAnnotationContext + stsCurrent.addChild(NodeBuilder.typeAnnotation(javaEnumTypeName)).setParent(stsCurrent); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Of)); pushCurrent(new CallExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.identifierExpression("values")).setParent(stsCurrent); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index b0e1182c3..f8dc5a98a 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -316,4 +316,35 @@ 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(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; + } } -- Gitee From 1fb7af04635deaaa32a84be65f081d36304f7a94 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 5 Aug 2022 12:48:09 +0300 Subject: [PATCH 4/8] Add declaration counts to metrics report. Change-Id: I4e85b31e55396dd8e2f67f8d7c94aa923f0402c5 Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 1ab0a24dc..1f6b3b688 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -50,17 +50,30 @@ public class JavaTransformer extends ASTVisitor implements Transformer { 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.; } /** @@ -144,6 +157,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { ++countExprTotal; else if (node instanceof Statement) ++countStmtTotal; + else if (node instanceof BodyDeclaration + || node instanceof VariableDeclaration) + ++countDeclTotal; } }); @@ -347,6 +363,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // Interface/ClassDeclarationContext popCurrent(); // stsMemberContext + ++countDeclTransformed; return false; } @@ -576,6 +593,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // stsClassOrInterMember } + ++countDeclTransformed; return false; } @@ -1320,6 +1338,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popCurrent(); // ClassMemberContext or InterfaceMemberContext + + ++countDeclTransformed; return false; } @@ -1382,6 +1402,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // RestFormalParameterContext | FormalParameterContext + ++countDeclTransformed; return false; } @@ -1486,6 +1507,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // stsClassDecl popCurrent(); // member context + ++countDeclTransformed; return false; } @@ -1687,6 +1709,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ClassFieldDeclarationContext popCurrent(); // ClassMemberContext + ++countDeclTransformed; return false; } @@ -1790,6 +1813,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popCurrent(); // VarOrConstDeclaration + ++countDeclTransformed; // Each VariableDeclarationFragment is a separate declaration construct! } popCurrent(); // VarOrConstDeclarationList @@ -1947,6 +1971,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsInitStmts.addAll(stsBlock.statementOrLocalDeclaration()); } + ++countDeclTransformed; return false; } -- Gitee From ec4c24c50c28ecba80a4183df3c0dc42af0a3209 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 5 Aug 2022 14:02:19 +0300 Subject: [PATCH 5/8] Don't re-compute reference source paths for JavaParser. Change-Id: I0758cf25ab1d5b3bf677988b30052f826dd1f968 Signed-off-by: Mikhail Velikanov --- .../src/com/ohos/migrator/java/JavaParser.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaParser.java b/migrator/src/com/ohos/migrator/java/JavaParser.java index 6ef82f258..5ecb4efc2 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); -- Gitee From 00578f24198667ab2dc276c9718d1b6850fafb21 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 5 Aug 2022 17:36:14 +0300 Subject: [PATCH 6/8] Inject name and ordinal args into enum class ctor calls. Generate default enum class ctor if no explicit ctor exists. Change-Id: Ibc07d16cef715a2412a048b6399ca75c1798cdae Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 79 ++++++++++++++++--- .../ohos/migrator/staticTS/NodeBuilder.java | 44 +++++++---- .../java/enum_with_class_behavior.java.sts | 27 ++++--- migrator/test/java/test_enum.java.sts | 62 +++++++++------ 4 files changed, 155 insertions(+), 57 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 1f6b3b688..ea2e13c56 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -48,6 +48,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { 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; @@ -659,7 +660,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 @@ -1473,36 +1474,60 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // 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 to enum constant node before visiting it + // 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()); javaEnumConst.accept(this); + ++javaEnumConstOrdinal; } if (needOpen) { stsClassDecl.children.add(0, NodeBuilder.terminalNode(StaticTSParser.Open)); } // 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(); + } + else { + hasCtors = javaEnumBodyDecl.getNodeType() == ASTNode.INITIALIZER; + } + } } - // TODO: toString() and ordinal() methods! + // Add values and valueOf built-in methods String javaEnumTypeName = javaEnumDeclaration.getName().getIdentifier(); createEnumValuesMethod(javaEnumTypeName, javaEnumConstNames); createEnumValueOfMethod(javaEnumTypeName); + // 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 { + // TODO: 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. + } + popCurrent(); // ClassBodyContext popCurrent(); // stsClassDecl popCurrent(); // member context @@ -1511,6 +1536,37 @@ public class JavaTransformer extends ASTVisitor implements Transformer { 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)); + pushCurrent(new ParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("name")); + stsCurrent.addChild(NodeBuilder.typeAnnotation("String")).setParent(stsCurrent); + popCurrent(); // ParameterContext + pushCurrent(new ParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("ordinal")); + PredefinedTypeContext stsPredefType = NodeBuilder.predefinedType(PrimitiveType.INT); + stsCurrent.addChild(NodeBuilder.typeAnnotation(stsPredefType)).setParent(stsCurrent); + popCurrent(); // ParameterContext + popCurrent(); // ParameterListContext + pushCurrent(new ConstructorBodyContext(stsCurrent, 0)); + pushCurrent(new ConstructorCallContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.identifierExpression("name")).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.identifierExpression("ordinal")).setParent(stsCurrent); + popCurrent(); // ExpressionSequenceContext + popCurrent(); // ArgumentsContext + popCurrent(); // ConstructorCallContext + popCurrent(); // ConstructorBodyContext + popCurrent(); // ConstructorDeclarationContext + popCurrent(); // ClassMemberContext + } + private void createEnumExtendsClause(String javaEnumName) { // Note: A Java enum extends Enum class. pushCurrent(new ClassExtendsClauseContext(stsCurrent, 0)); @@ -1670,7 +1726,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Create constant declaration context and add enum constant name and type pushCurrent(new ConstantDeclarationContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaEnumConstant.getName())); + 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)); @@ -1684,17 +1741,21 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)); stsCurrent.addChild(NodeBuilder.typeReference(javaEnumTypeName)).setParent(stsCurrent); - // Process ctor arguments, if any + // 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()) { - pushCurrent(new ArgumentsContext(stsCurrent, 0)); - pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); for (Expression javaEnumConstArg : javaEnumConstArgs) { javaEnumConstArg.accept(this); } - popCurrent(); // ExpressionSequenceContext - popCurrent(); // ArgumentsContext } + popCurrent(); // ExpressionSequenceContext + popCurrent(); // ArgumentsContext // Process anonymous class body, if any AnonymousClassDeclaration javaEnumConstClassBody = javaEnumConstant.getAnonymousClassDeclaration(); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index f8dc5a98a..92bfbcdb6 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -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) { @@ -340,6 +349,13 @@ public class NodeBuilder { 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); diff --git a/migrator/test/java/enum_with_class_behavior.java.sts b/migrator/test/java/enum_with_class_behavior.java.sts index fe0a741d1..c90e6c465 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -19,22 +19,22 @@ interface IOperation { } open class ArithmeticOperation extends Enum implements IOperation { - public static const PLUS : ArithmeticOperation = new ArithmeticOperation { + 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 { + 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 { + 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 { + public static const DIVIDE : ArithmeticOperation = new ArithmeticOperation("DIVIDE", 3) { public override apply(a : int, b : int): int { return a / b; } @@ -48,16 +48,19 @@ open class ArithmeticOperation extends Enum implements IOpe } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } class Planet extends Enum { - public static const MERCURY : Planet = new Planet(3.303e+23, 2.4397e6); - public static const VENUS : Planet = new Planet(4.869e+24, 6.0518e6); - public static const EARTH : Planet = new Planet(5.976e+24, 6.37814e6); - public static const MARS : Planet = new Planet(6.421e+23, 3.3972e6); - public static const JUPITER : Planet = new Planet(1.9e+27, 7.1492e7); - public static const SATURN : Planet = new Planet(5.688e+26, 6.0268e7); - public static const URANUS : Planet = new Planet(8.686e+25, 2.5559e7); - public static const NEPTUNE : Planet = new Planet(1.024e+26, 2.4746e7); + 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); + public static const SATURN : Planet = new Planet("SATURN", 5, 5.688e+26, 6.0268e7); + public static const URANUS : Planet = new Planet("URANUS", 6, 8.686e+25, 2.5559e7); + public static const NEPTUNE : Planet = new Planet("NEPTUNE", 7, 1.024e+26, 2.4746e7); private mass : double ; private radius : double ; diff --git a/migrator/test/java/test_enum.java.sts b/migrator/test/java/test_enum.java.sts index e0893fd67..5f835b040 100644 --- a/migrator/test/java/test_enum.java.sts +++ b/migrator/test/java/test_enum.java.sts @@ -24,17 +24,20 @@ export class test_enum extends Enum { } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } class Planet extends Enum { - public static const MERCURY : Planet = new Planet; - public static const VENUS : Planet = new Planet; - public static const EARTH : Planet = new Planet; - public static const MARS : Planet = new Planet; - public static const JUPITER : Planet = new Planet; - public static const SATURN : Planet = new Planet; - public static const URANUS : Planet = new Planet; - public static const NEPTUNE : Planet = new Planet; + 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]; @@ -45,12 +48,15 @@ class Planet extends Enum { } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } open class NestedEnums { private static class Colors extends Enum { - public static const RED : Colors = new Colors; - public static const GREEN : Colors = new Colors; - public static const BLUE : Colors = new Colors; + 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]; @@ -61,11 +67,14 @@ open class NestedEnums { } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } protected static class Size extends Enum { - public static const SMALL : Size = new Size; - public static const MEDIUM : Size = new Size; - public static const LARGE : Size = new Size; + 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]; @@ -76,12 +85,15 @@ open class NestedEnums { } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } public static class Direction extends Enum { - public static const NORTH : Direction = new Direction; - public static const EAST : Direction = new Direction; - public static const SOUTH : Direction = new Direction; - public static const WEST : Direction = new Direction; + 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]; @@ -92,12 +104,15 @@ open class NestedEnums { } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } static class Operator extends Enum { - public static const PLUS : Operator = new Operator; - public static const MINUS : Operator = new Operator; - public static const MULTIPLY : Operator = new Operator; - public static const DIVIDE : Operator = new Operator; + 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]; @@ -108,6 +123,9 @@ open class NestedEnums { } return null; } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + } } } -- Gitee From 000f1ec62ee1d828a859aa957f36a529ed1380d5 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Mon, 8 Aug 2022 17:14:09 +0300 Subject: [PATCH 7/8] Process explicit enum ctors. Also a to translation of instance initializers, namely creating default ctor if there are no explicit ctors, just an instance initializer (one or many). Updates to tests to cover all of the changes above. Change-Id: Id1db76398321c56e8ac2da5742fdcd5a2676ff29 Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 125 ++++++++++++------ .../ohos/migrator/staticTS/NodeBuilder.java | 30 +++++ .../test/java/class_instance_initializer.java | 9 +- .../java/class_instance_initializer.java.sts | 7 + .../test/java/enum_with_class_behavior.java | 33 ++++- .../java/enum_with_class_behavior.java.sts | 41 +++++- 6 files changed, 194 insertions(+), 51 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index ea2e13c56..aa5b7e781 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -477,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; @@ -1506,9 +1527,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { MethodDeclaration javaEnumMethodDecl = (MethodDeclaration) javaEnumBodyDecl; hasCtors = javaEnumMethodDecl.isConstructor(); } - else { - hasCtors = javaEnumBodyDecl.getNodeType() == ASTNode.INITIALIZER; - } } } @@ -1524,10 +1542,23 @@ public class JavaTransformer extends ASTVisitor implements Transformer { createEnumDefaultCtor(); } else { - // TODO: For all non-default ctors - if there is no call to another ctor in the body, + // 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); + } + } } + // 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 @@ -1535,38 +1566,62 @@ public class JavaTransformer extends ASTVisitor implements Transformer { ++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)); - pushCurrent(new ParameterContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalIdentifier("name")); - stsCurrent.addChild(NodeBuilder.typeAnnotation("String")).setParent(stsCurrent); - popCurrent(); // ParameterContext - pushCurrent(new ParameterContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalIdentifier("ordinal")); - PredefinedTypeContext stsPredefType = NodeBuilder.predefinedType(PrimitiveType.INT); - stsCurrent.addChild(NodeBuilder.typeAnnotation(stsPredefType)).setParent(stsCurrent); - popCurrent(); // ParameterContext + stsCurrent.addChild(NodeBuilder.parameter("name", "String")).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.parameter("ordinal", PrimitiveType.INT)).setParent(stsCurrent); popCurrent(); // ParameterListContext pushCurrent(new ConstructorBodyContext(stsCurrent, 0)); - pushCurrent(new ConstructorCallContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); - pushCurrent(new ArgumentsContext(stsCurrent, 0)); - pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.identifierExpression("name")).setParent(stsCurrent); - stsCurrent.addChild(NodeBuilder.identifierExpression("ordinal")).setParent(stsCurrent); - popCurrent(); // ExpressionSequenceContext - popCurrent(); // ArgumentsContext - popCurrent(); // ConstructorCallContext + 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)); @@ -1585,7 +1640,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // TypeReferenceContext popCurrent(); // ClassExtendsClauseContext } - private void pushEnumBuiltinMethod() { // Create class member context and add public modifier pushCurrent(new ClassMemberContext(stsCurrent, 0)); @@ -1596,7 +1650,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new ClassMethodWithBodyContext((ClassMethodDeclarationContext)stsCurrent)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Static)); } - private void popEnumBuiltinMethod() { popCurrent(); // ClassMethodWithBodyContext popCurrent(); // ClassMethodDeclarationContext @@ -1649,10 +1702,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalIdentifier("valueOf")); pushCurrent(new SignatureContext(stsCurrent, 0)); pushCurrent(new ParameterListContext(stsCurrent, 0)); - pushCurrent(new ParameterContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalIdentifier("name")); - stsCurrent.addChild(NodeBuilder.typeAnnotation("String")).setParent(stsCurrent); - popCurrent(); // ParameterContext + stsCurrent.addChild(NodeBuilder.parameter("name", "String")).setParent(stsCurrent); popCurrent(); // ParameterListContext stsCurrent.addChild(NodeBuilder.typeAnnotation(javaEnumTypeName)).setParent(stsCurrent); popCurrent(); // SignatureContext @@ -2008,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 diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index 92bfbcdb6..fe9bf32a1 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -363,4 +363,34 @@ public class NodeBuilder { 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/test/java/class_instance_initializer.java b/migrator/test/java/class_instance_initializer.java index 1279d786e..959ad31af 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 298d22cea..c77a40cc6 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 a2524adc9..2331696ad 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 c90e6c465..6fab978ac 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -39,6 +39,9 @@ open class ArithmeticOperation extends Enum implements IOpe return a / b; } }; + + private foo : String ; + public static values(): ArithmeticOperation[] { return [PLUS, MINUS, MULTIPLY, DIVIDE]; } @@ -48,8 +51,10 @@ open class ArithmeticOperation extends Enum implements IOpe } return null; } + private constructor(name : String, ordinal : int) { super(name, ordinal); + foo = "bar"; } } class Planet extends Enum { @@ -57,17 +62,43 @@ class Planet extends Enum { 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); - public static const SATURN : Planet = new Planet("SATURN", 5, 5.688e+26, 6.0268e7); - public static const URANUS : Planet = new Planet("URANUS", 6, 8.686e+25, 2.5559e7); - public static const NEPTUNE : Planet = new Planet("NEPTUNE", 7, 1.024e+26, 2.4746e7); + 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(mass : double, radius : double) { + 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; -- Gitee From 1983e853f40ba6f1bd8c27543424ebf085ec7e94 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Wed, 10 Aug 2022 17:39:52 +0300 Subject: [PATCH 8/8] Minor change to the test validating switch statement translation to account for re-implemented enum translation. Change-Id: Ibe389e6fa584eaed12196c2c8f063881f5f541fb Signed-off-by: Mikhail Velikanov --- migrator/test/java/switch_statement.java.sts | 22 ++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/migrator/test/java/switch_statement.java.sts b/migrator/test/java/switch_statement.java.sts index 0e10a1c58..36e61cd3b 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) { -- Gitee