From 0dc9aed9f6eacd185c50c723ae218bbf32804be5 Mon Sep 17 00:00:00 2001 From: Alexander Pavlyuk Date: Wed, 31 Aug 2022 16:30:28 +0300 Subject: [PATCH] Translation of expression method reference Change-Id: Iea7576dc9e0cac50d633ea103e7ad53d4e6d059e Signed-off-by: Alexander Pavlyuk --- .../ohos/migrator/java/JavaTransformer.java | 170 +++++++++++++++--- .../ohos/migrator/staticTS/NodeBuilder.java | 29 +++ 2 files changed, 177 insertions(+), 22 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index ff53eaf63..641e5572a 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -271,7 +271,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)); } - + // Java tree: // TypeDeclaration: // A type declaration is the union of a class declaration and an interface declaration. // ClassDeclaration @@ -1468,6 +1468,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // TypeAnnotationContext + // TODO: { Dimension } + //javaSingleVariableDeclaration. // TODO: [= Expression ] // Expression javaExpression = javaSingleVariableDeclaration.getInitializer(); // if (javaExpression != null) { @@ -1479,6 +1481,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: // VariableDeclarationFragment: // Identifier { Dimension } [ = Expression ] @@ -1646,6 +1651,7 @@ 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); @@ -1702,6 +1708,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsEnumCtorCallArg.setParent(stsExprSeq); } } + private void createEnumExtendsClause(String javaEnumName) { // Note: A Java enum extends Enum class. pushCurrent(new ClassExtendsClauseContext(stsCurrent, 0)); @@ -1720,6 +1727,7 @@ 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)); @@ -1730,6 +1738,7 @@ 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 @@ -1843,6 +1852,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popEnumBuiltinMethod(); } + @Override public boolean visit(EnumConstantDeclaration javaEnumConstant) { // Create class member context and add public modifier @@ -2461,10 +2471,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaArrayInitializer.accept(this); } -// popSingleExpression(); // NewArrayExpression - - // TODO: Needs reworking. - // ++countExprTransformed. return false; } @@ -2564,7 +2570,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - // Java tree: // ForStatement: // for ( @@ -3116,6 +3121,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // statement, so that variables are only visible in context of switch statement. List javaVarFragments = javaVarDeclStmt.fragments(); + for (VariableDeclarationFragment javaVarFragment : javaVarFragments) { if (isUsedInAnotherCaseClause(javaVarFragment, javaCurrentSwitchCase, javaSwitchStmt)) { javaVariablesToMove.add(javaVarFragment); @@ -3274,8 +3280,143 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // BlockContext } + popCurrent(); // LambdaBodyContext + popSingleExpression(); // LambdaExpressionContext + + ++countExprTransformed; + return false; + } + + // ExpressionMethodReference: Expression :: [ < Type { , Type } > ] Identifier + // STS tree: + // singleExpression: + // | OpenParen parameterList? CloseParen typeAnnotation Arrow lambdaBody # LambdaExpression + // lambdaBody: singleExpression | block; + @Override + public boolean visit(ExpressionMethodReference javaExpressionMethodReference) { + pushCurrent(new LambdaExpressionContext(pushSingleExpression())); + + javaExpressionMethodReference.getExpression().accept(this); + ParseTree lastChild = stsCurrent.getChild(stsCurrent.getChildCount() - 1); + stsCurrent.removeLastChild(); + assert(lastChild instanceof SingleExpressionContext); + SingleExpressionContext stsTypeExpr = (SingleExpressionContext)lastChild; + + // Form the list of parameters. It will contain one object of type defined by stsTypeExpr. + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenParen)); + // parameterList: parameter... + pushCurrent(new ParameterListContext(stsCurrent, 0)); + // parameter: Identifier typeAnnotation + pushCurrent(new ParameterContext(stsCurrent, 0)); + + // TODO: Check if the fixed object name used here may cause a names conflict. + stsCurrent.addChild(NodeBuilder.terminalIdentifier("object_arg")); // Identifier + + // typeAnnotation: Colon primaryType + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Colon)); + // primaryType: predefinedType | typeReference | arrayType + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + + // Depending on type of stsTypeExpr create proper child for PrimaryTypeContext object. + assert (stsTypeExpr.getChildCount() == 1); + ParseTree stsNode = stsTypeExpr.getChild(0); + if (stsNode instanceof IdentifierExpressionContext) { + String typeName = ((IdentifierExpressionContext)stsNode).Identifier().getText(); + stsCurrent.addChild(NodeBuilder.typeReference(typeName)).setParent(stsCurrent); + } + else { + // TODO: May it ever happens? + assert false; + } + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotationContext + + popCurrent(); // ParameterContext + popCurrent(); // ParameterListContext + + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseParen)); // End of parameters list. + + IMethodBinding javaMethodBinding = javaExpressionMethodReference.resolveMethodBinding(); + ITypeBinding javaReturnType = javaMethodBinding.getReturnType(); + + // typeAnnotation: Colon primaryType + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Colon)); + // primaryType: predefinedType | typeReference | arrayType + pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); + if (javaReturnType.isPrimitive()) { + stsCurrent.addChild(NodeBuilder.predefinedType(javaReturnType)).setParent(stsCurrent); + } else if (javaReturnType.isClass() || javaReturnType.isInterface()) { + stsCurrent.addChild(NodeBuilder.typeReference(javaReturnType.getQualifiedName())).setParent(stsCurrent); + } + else if (javaReturnType.isEnum()) { + // TODO: + } else if (javaReturnType.isArray()) { + // TODO: + pushCurrent(new ArrayTypeContext(stsCurrent, 0)); + + ITypeBinding javaElementType = javaReturnType.getElementType(); + if (javaElementType.isPrimitive()) { + stsCurrent.addChild(NodeBuilder.predefinedType(javaReturnType)).setParent(stsCurrent); + } else if (javaElementType.isClass() || javaElementType.isInterface()) { + stsCurrent.addChild(NodeBuilder.typeReference(javaReturnType.getQualifiedName())).setParent(stsCurrent); + } + else if (javaElementType.isEnum()) { + // TODO: + } else { + // Is this ever can be in case of array type? + assert false; + } + + int numDims = javaReturnType.getDimensions(); + for (int i = 0; i < numDims; ++i) { + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBracket)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBracket)); + } + + popCurrent(); // ArrayTypeContext + } else { + assert false : "Need implementation of the translation"; + } + + popCurrent(); // PrimaryTypeContext + popCurrent(); // TypeAnnotationContext + + // TODO: translation of type arguments. +// List javaTypeArguments = javaExpressionMethodReference.typeArguments(); +// if (javaTypeArguments != null && !javaTypeArguments.isEmpty()) { +// translateTypeArgumens(javaTypeArguments); +// } + + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); + // lambdaBody: singleExpression | block + // Use here + // singleExpression: + // | singleExpression typeArguments? arguments # CallExpression + // to produce object_arg.method_name() + pushCurrent(new LambdaBodyContext(stsCurrent, 0)); + pushCurrent(new CallExpressionContext(pushSingleExpression())); + + // | singleExpression Dot identifier # MemberAccessExpression + pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); + // singleExpression + // | Identifier IdentifierExpression + pushCurrent(new IdentifierExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("object_arg")); + popSingleExpression(); // IdentifierExpressionContext + + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaExpressionMethodReference.getName())); + popSingleExpression(); // MemberAccessExpressionContext + + //translateTypeArguments(javaMethodInvocation.typeArguments()); + //translateArguments(javaMethodInvocation.arguments()); + stsCurrent.addChild(new ArgumentsContext(stsCurrent, 0)); // Empty list of arguments. + + popSingleExpression(); // CallExpressionContext + popCurrent(); // LambdaBodyContext popSingleExpression(); // LambdaExpressionContext ++countExprTransformed; @@ -3324,16 +3465,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - @Override - public boolean visit(ExpressionMethodReference javaExprMethodRef) { - // TODO: To be implemented - // Emit __untranslated_expression call with commented-out original syntax as argument for now. - // This is done to avoid building invalid STS AST which causes exceptions in StaticTSWriter. - stsCurrent.addChild(NodeBuilder.untranslatedExpression(javaExprMethodRef)).setParent(stsCurrent); - - return false; - } - @Override public boolean visit(TryStatement javaTryStatement) { // TODO: To be implemented @@ -3366,11 +3497,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // The list of not yet translated Java Expressions: // CreationReference, - //?? ExpressionMethodReference, - // LambdaExpression, // SuperMethodReference, // TypeMethodReference - // TryStatement - // SynchronizedStatement - // ThrowStatement -} \ No newline at end of file +} diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index ec7daf0ac..c02eb1037 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -104,6 +104,35 @@ public class NodeBuilder { return stsPredefinedType; } + private static int stsTypeNameCode(String javaTypeName) { + int stsTypeNameCode = -1; + + if (PrimitiveType.BOOLEAN.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Boolean; + else if (PrimitiveType.BYTE.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Byte; + else if (PrimitiveType.CHAR.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Char; + else if (PrimitiveType.INT.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Int; + else if (PrimitiveType.DOUBLE.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Double; + else if (PrimitiveType.FLOAT.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Float; + else if (PrimitiveType.LONG.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Long; + else if (PrimitiveType.SHORT.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Short; + else if (PrimitiveType.VOID.toString().equals(javaTypeName)) stsTypeNameCode = StaticTSParser.Void; + else + assert false : "Unknown type"; + + return stsTypeNameCode; + } + + public static PredefinedTypeContext predefinedType(ITypeBinding javaTypeBinding) { + assert javaTypeBinding.isPrimitive() : "Not a primitive Java type"; + + String javaTypeName = javaTypeBinding.getName(); + + // predefinedType -> TerminalNode + PredefinedTypeContext stsPredefinedType = new PredefinedTypeContext(null, 0); + stsPredefinedType.addChild(terminalNode(stsTypeNameCode(javaTypeName))); + return stsPredefinedType; + } + public static AccessibilityModifierContext accessibilityModifier(int javaModifiers) { int stsModifierCode = -1; if ((javaModifiers & Modifier.PRIVATE) != 0) -- Gitee