diff --git a/migrator/src/com/ohos/migrator/Main.java b/migrator/src/com/ohos/migrator/Main.java index cacf676685a13f98baa06f3ba87f271ff37abeee..fe277dd1cca6857381b0b0b42a0baac998e1d782 100644 --- a/migrator/src/com/ohos/migrator/Main.java +++ b/migrator/src/com/ohos/migrator/Main.java @@ -41,6 +41,7 @@ public class Main { static boolean verboseMode = false; static boolean strictMode = false; + static boolean convRateMode = false; public static void finish(ResultCode exitCode) { if(verboseMode) { for (TranspileException e: errorList) { @@ -66,6 +67,7 @@ public class Main { public static boolean isVerboseMode() { return verboseMode; } public static boolean isStrictMode() { return strictMode; } + public static boolean isConvRateMode() { return convRateMode; } public static boolean hasErrors() { return !errorList.isEmpty(); } public static void addError(ResultCode code, String message) { @@ -103,6 +105,7 @@ public class Main { if (cmd.hasOption("verbose")) verboseMode = true; if (cmd.hasOption("strict")) strictMode = true; + if (cmd.hasOption("conversion-rate")) convRateMode = true; String outDir = null; if (cmd.hasOption("o")) { @@ -195,7 +198,7 @@ public class Main { outFiles.addAll(javaTranspiler.getOutFiles()); errorList.addAll(javaTranspiler.getErrorList()); - convRate += javaTranspiler.getConversionRate(); + if (convRateMode) convRate += javaTranspiler.getConversionRate(); ++numLanguages; } @@ -208,15 +211,16 @@ public class Main { outFiles.addAll(kotlinTranspiler.getOutFiles()); errorList.addAll(kotlinTranspiler.getErrorList()); - convRate += kotlinTranspiler.getConversionRate(); + if (convRateMode) convRate += kotlinTranspiler.getConversionRate(); ++numLanguages; } - if (numLanguages > 0) convRate /= numLanguages; - if (resultCode == ResultCode.OK) System.out.println("Transpilation OK."); - if (cmd.hasOption("conversion-rate")) + + if (convRateMode) { + if (numLanguages > 0) convRate /= numLanguages; System.out.println("Conversion rate: " + String.format("%.1f", convRate) + "%"); + } // Check syntax of all STS files produced. // NOTE: This is for development process only, probably to be removed afterwards. diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 8a67148c8f843420dca6c6b10ac57712722c0da3..611d2c416f7df37e494f7ba55c4e1db10eed8027 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -29,9 +29,7 @@ import org.eclipse.jdt.core.dom.*; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; +import java.util.*; /** * Performs transformation of the Java AST (Eclipse JDT AST) into StaticTS AST. @@ -60,10 +58,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private static int countExprTotal = 0; private static int countDeclTotal = 0; private static int countTypeTotal = 0; - private static int countExprTransformed = 0; private static int countStmtTransformed = 0; + private static int countExprTransformed = 0; private static int countDeclTransformed = 0; private static int countTypeTransformed = 0; + private final Set exprTransformed = new HashSet<>(); + private final Set stmtTransformed = new HashSet<>(); + private final Set declTransformed = new HashSet<>(); + private final Set typeTransformed = new HashSet<>(); public static double getTransformationRate() { double result = 0.; @@ -86,6 +88,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { result += countTypeTransformed / (double)countTypeTotal; } + if (Main.isVerboseMode()) { + System.out.println("Statements: " + countStmtTransformed + " out of " + countStmtTotal); + System.out.println("Expressions: " + countExprTransformed + " out of " + countExprTotal); + System.out.println("Declarations: " + countDeclTransformed + " out of " + countDeclTotal); + System.out.println("Types: " + countTypeTransformed + " out of " + countTypeTotal); + } + return (normFactor > 0) ? result / (double)normFactor : 0.; } @@ -165,55 +174,194 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } public CompilationUnitContext transform() { - // Compute total counts of statements and expressions in - // Java AST. This is used in conversion rate computation. - javaCU.accept(new ASTVisitor() { - @Override - public void postVisit(ASTNode node) { - if (node instanceof Expression) - ++countExprTotal; - else if (node instanceof Statement) - ++countStmtTotal; - else if (node instanceof BodyDeclaration - || node instanceof VariableDeclaration - || node.getNodeType() == ASTNode.ANONYMOUS_CLASS_DECLARATION - || node.getNodeType() == ASTNode.IMPORT_DECLARATION - || node.getNodeType() == ASTNode.PACKAGE_DECLARATION) - ++countDeclTotal; - else if (node instanceof Type) - ++countTypeTotal; - } + if (Main.isConvRateMode()) { + // Compute total counts of statements, expressions, declarations + // and types in Java AST that we expect to transform. This is used + // in conversion rate computation. + javaCU.accept(new ASTVisitor() { + @Override + public void postVisit(ASTNode node) { + if (node instanceof Expression && + !(node instanceof Annotation) && + // names are translated manually by and large, + // almost never by accept, so it's hard to count + // them properly. Assume we handle them all and ignore. + !(node instanceof Name) && + node.getNodeType() != ASTNode.SWITCH_EXPRESSION && + node.getNodeType() != ASTNode.TEXT_BLOCK) + ++countExprTotal; + else if (node instanceof Statement && + node.getNodeType() != ASTNode.YIELD_STATEMENT) + ++countStmtTotal; + else if ((node instanceof BodyDeclaration + && node.getNodeType() != ASTNode.ANNOTATION_TYPE_DECLARATION + && node.getNodeType() != ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION) + || node instanceof VariableDeclaration + || node.getNodeType() == ASTNode.ANONYMOUS_CLASS_DECLARATION + || node.getNodeType() == ASTNode.IMPORT_DECLARATION + || node.getNodeType() == ASTNode.PACKAGE_DECLARATION) + ++countDeclTotal; + else if (node instanceof Type && node.getNodeType() != ASTNode.UNION_TYPE) + ++countTypeTotal; + } - // TODO: Remove as translation of remaining Java AST nodes is implemented! - @Override - public boolean visit(TryStatement node) { - return false; - } - @Override - public boolean visit(ThrowStatement node) { - return false; - } - @Override - public boolean visit(ExpressionMethodReference node) { - return false; - } - @Override - public boolean visit(SuperMethodReference node) { - return false; - } - @Override - public boolean visit(TypeMethodReference node) { - return false; - } - @Override - public boolean visit(CreationReference node) { - return false; - } - }); + // NOTE: The following AST nodes are not intended to be visited at the moment! + @Override + public boolean visit(MarkerAnnotation node) { + return false; + } + + @Override + public boolean visit(NormalAnnotation node) { + return false; + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + return false; + } + + @Override + public boolean visit(SwitchExpression node) { + return false; + } + + @Override + public boolean visit(TextBlock node) { + return false; + } + + @Override + public boolean visit(YieldStatement node) { + return false; + } + + @Override + public boolean visit(AnnotationTypeDeclaration node) { + return false; + } + + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + return false; + } + + @Override + public boolean visit(UnionType node) { + return false; + } + + // NOTE: The following AST nodes are being visited by JavaTransformer + // but need special treatment. + @Override + public boolean visit(ArrayCreation node) { + // If initializer is present, it's the only child node that gets visited. + ArrayInitializer initializer = node.getInitializer(); + if (initializer != null) { + initializer.accept(this); + return false; + } + + // We don't visit ArrayType inside ArrayCreation node. + node.getType().getElementType().accept(this); + + List indices = node.dimensions(); + for (Expression index : indices) + index.accept(this); + + return false; + } + + @Override + public boolean visit(MethodDeclaration node) { + // We don't visit list of exceptions thrown. + Type rt = node.getReturnType2(); + if (rt != null) rt.accept(this); + + List params = node.parameters(); + for (SingleVariableDeclaration param : params) + param.accept(this); + + // We don't visit the block itself, only statements inside it. + visitBodyStatements(node.getBody()); + + return false; + } + + private void visitBodyStatements(Block body) { + if (body != null) { + List stmts = body.statements(); + for (Statement stmt : stmts) + stmt.accept(this); + } + } + + @Override + public boolean visit(TryStatement node) { + // We don't visit the block itself, only statements inside it. + visitBodyStatements(node.getBody()); + + Block finallyBody = node.getFinally(); + if (finallyBody != null) finallyBody.accept(this); + + List catches = node.catchClauses(); + for (CatchClause catchClause : catches) + catchClause.accept(this); + + return false; + } + + @Override + public boolean visit(CatchClause node) { + // We visit only exception type, and if it's a union type, + // we visit only its component types. + SingleVariableDeclaration exception = node.getException(); + Type excType = exception.getType(); + if (excType.isUnionType()) { + List componentTypes = ((UnionType)excType).types(); + for (Type componentType : componentTypes) + componentType.accept(this); + } + else + excType.accept(this); + + // We don't visit the block itself, only statements inside it. + visitBodyStatements(node.getBody()); + + return false; + } + + @Override + public boolean visit(LambdaExpression node) { + List params = node.parameters(); + for (VariableDeclaration param : params) + param.accept(this); + + ASTNode body = node.getBody(); + if (body != null) { + // We don't visit the block itself, only statements inside it. + if (body.getNodeType() == ASTNode.BLOCK) + visitBodyStatements((Block)body); + else if (body instanceof Expression) + body.accept(this); + } + + return false; + } + }); + } // Visit Java AST and construct StaticTS AST. javaCU.accept(this); + if (Main.isConvRateMode()) { + // Update transformed AST node counts. + countStmtTransformed += stmtTransformed.size(); + countExprTransformed += exprTransformed.size(); + countDeclTransformed += declTransformed.size(); + countTypeTransformed += typeTransformed.size(); + } + return stsCU; } @@ -251,7 +399,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // PackageDeclarationContext - ++countDeclTransformed; + declTransformed.add(javaPackageDeclaration); return false; } @@ -330,7 +478,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // topDeclarationContext // Export? // ClassDeclarationContext - // TermminalNode <(static? (abstract | open) | (abstract | open)? static)?> ? + // TerminalNode <(static? (abstract | open) | (abstract | open)? static)?> ? // TerminalNode // TerminalNode // TypeParametersContext ? @@ -339,14 +487,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // ClassBodyContext // TerminalNode <{> // ClassMemberContext * - // clinit = CclassInitializerContext ? + // clinit = ClassInitializerContext ? // ClassMemberContext * // TerminalNode <}> // STS tree for interface declaration: // topDeclarationContext // Export? // InterfaceDeclarationContext - // TermminalNode ? + // TerminalNode ? // TerminalNode // TerminalNode // TypeParametersContext ? @@ -403,7 +551,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // Interface/ClassDeclarationContext popCurrent(); // DeclarationOrMemberContext - ++countDeclTransformed; + declTransformed.add(javaTypeDeclaration); return false; } @@ -484,7 +632,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaTypeParameter.getName())); - // ExtendedModifiers are ignored at the moment and seems do not need to be translated. + // ExtendedModifiers are ignored at the moment. List javaTypeBounds = javaTypeParameter.typeBounds(); @@ -667,7 +815,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // stsClassOrInterMember } - ++countDeclTransformed; + declTransformed.add(javaFieldDecl); return false; } @@ -694,7 +842,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ImportDeclarationContext - ++countDeclTransformed; + declTransformed.add(javaImportDeclaration); return false; } @@ -739,7 +887,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; + typeTransformed.add(javaPrimitiveType); return false; } @@ -760,7 +908,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; + typeTransformed.add(javaSimpleType); return false; } @@ -797,7 +945,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; + typeTransformed.add(javaQualifiedType); return false; } @@ -821,7 +969,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; + typeTransformed.add(javaNameQualifiedType); return false; } @@ -854,7 +1002,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; + typeTransformed.add(javaParametrizedType); return false; } @@ -876,7 +1024,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // WildcardTypeContext - ++countTypeTransformed; + typeTransformed.add(javaWildcardType); return false; } @@ -898,14 +1046,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; - return false; - } - - @Override - public boolean visit(UnionType javaUnionType) { - // UnionType is not expected to be present in Java sources the transpiler is supposed to translate. - assert(false) : "Unsupported Java syntax: Union types!"; + typeTransformed.add(javaArrayType); return false; } @@ -924,7 +1065,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (needPrimaryType) popCurrent(); // PrimaryTypeContext - ++countTypeTransformed; + typeTransformed.add(javaIntersectionType); return false; } @@ -956,7 +1097,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(NullLiteral javaLiteral) { stsCurrent.addChild(NodeBuilder.nullLiteral()).setParent(stsCurrent); - ++countExprTransformed; + exprTransformed.add(javaLiteral); return false; } @@ -968,7 +1109,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(BooleanLiteral javaLiteral) { stsCurrent.addChild(NodeBuilder.boolLiteral(javaLiteral.booleanValue())).setParent(stsCurrent); - ++countExprTransformed; + exprTransformed.add(javaLiteral); return false; } @@ -980,7 +1121,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(CharacterLiteral javaLiteral) { stsCurrent.addChild(NodeBuilder.charLiteral(javaLiteral.getEscapedValue())).setParent(stsCurrent); - ++countExprTransformed; + exprTransformed.add(javaLiteral); return false; } @@ -992,7 +1133,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(StringLiteral javaLiteral) { stsCurrent.addChild(NodeBuilder.stringLiteral(javaLiteral.getEscapedValue())).setParent(stsCurrent); - ++countExprTransformed; + exprTransformed.add(javaLiteral); return false; } @@ -1009,7 +1150,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(NumberLiteral javaLiteral) { stsCurrent.addChild(NodeBuilder.numericLiteral(javaLiteral.getToken())).setParent(stsCurrent); - ++countExprTransformed; + exprTransformed.add(javaLiteral); return false; } @@ -1022,7 +1163,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public boolean visit(SimpleName javaSimpleName) { String name = javaSimpleName.getIdentifier(); stsCurrent.addChild(NodeBuilder.identifierExpression(name)).setParent(stsCurrent); - ++countExprTransformed; + // Don't count names as transformed as most of them are transformed manually. return false; } @@ -1035,7 +1176,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public boolean visit(QualifiedName javaQualifiedName) { String name = javaQualifiedName.getFullyQualifiedName(); stsCurrent.addChild(NodeBuilder.identifierExpression(name)).setParent(stsCurrent); - ++countExprTransformed; + // Don't count names as transformed as most of them are transformed manually. return false; } @@ -1148,7 +1289,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // InfixExpression } - ++countExprTransformed; + exprTransformed.add(javaInfixExpression); return false; } @@ -1193,7 +1334,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); - ++countExprTransformed; + exprTransformed.add(javaPostfixExpression); return false; } @@ -1257,7 +1398,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); - ++countExprTransformed; + exprTransformed.add(javaPrefixExpression); return false; } @@ -1277,7 +1418,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); - ++countExprTransformed; + exprTransformed.add(javaParenthesizedExpression); return false; } @@ -1413,8 +1554,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (javaBlock == null) { // Abstract method. pushCurrent(new AbstractOrNativeClassMethodContext(stsClassMethodDeclaration)); - // TODO: Check if 'abstract' has to be forced here or it will be automatically added in translateJavaModifiers(). - //stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Abstract)).setParent(stsCurrent); } else { // not abstract method pushCurrent(new ClassMethodWithBodyContext(stsClassMethodDeclaration)); } @@ -1489,7 +1628,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ClassMemberContext or InterfaceMemberContext - ++countDeclTransformed; + declTransformed.add(javaMethodDeclaration); return false; } @@ -1534,9 +1673,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new ParameterContext(stsCurrent, 0)); } - // TODO: The next line is not applicable for FormalParameter. So it should be checked/reworked later. - //translateJavaModifiers(javaSingleVariableDeclaration.getModifiers()); - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaSingleVariableDeclaration.getName())); // Parameter type @@ -1547,17 +1683,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (extraDims > 0) NodeBuilder.addExtraDimensions(stsCurrent, extraDims); popCurrent(); // TypeAnnotationContext - - // TODO: { Dimension } - //javaSingleVariableDeclaration. - // TODO: [= Expression ] -// Expression javaExpression = javaSingleVariableDeclaration.getInitializer(); -// if (javaExpression != null) { -// } - popCurrent(); // ParameterContext | VariadicParameterContext - ++countDeclTransformed; + declTransformed.add(javaSingleVariableDeclaration); return false; } @@ -1597,7 +1725,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ParameterContext - ++countDeclTransformed; + declTransformed.add(javaVariableDeclarationFragment); return false; } @@ -1736,7 +1864,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // stsClassDecl popCurrent(); // member context - ++countDeclTransformed; + declTransformed.add(javaEnumDeclaration); return false; } @@ -1760,7 +1888,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Get parameter list or create if there isn't one ParameterListContext stsEnumCtorParams = stsEnumCtor.parameterList(); if (stsEnumCtorParams == null) { + // ParameterListContext ctor doesn't initialize children field + // which we use below, so initialize it explicitly. stsEnumCtorParams = new ParameterListContext(stsEnumCtor, 0); + stsEnumCtorParams.children = new ArrayList<>(); + stsEnumCtor.addChild(stsEnumCtorParams).setParent(stsEnumCtor); } @@ -1998,7 +2130,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ClassFieldDeclarationContext popCurrent(); // ClassMemberContext - ++countDeclTransformed; + declTransformed.add(javaEnumConstant); return false; } @@ -2016,7 +2148,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { translateBlockStatements(javaBlock); popStatement(); // BlockContext - ++countStmtTransformed; + stmtTransformed.add(javaBlock); return false; } @@ -2036,7 +2168,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); } - ++countStmtTransformed; + stmtTransformed.add(javaEmptyStmnt); return false; } @@ -2052,7 +2184,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); - ++countStmtTransformed; + stmtTransformed.add(javaLabeledStmnt); return false; } @@ -2104,7 +2236,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popCurrent(); // VarOrConstDeclaration - ++countDeclTransformed; // Each VariableDeclarationFragment is a separate declaration construct! + declTransformed.add(javaVarDeclFragment); // Each VariableDeclarationFragment is a separate declaration construct! } popCurrent(); // VarOrConstDeclarationList @@ -2130,7 +2262,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { createAndFillVarOrConstDeclarationList(javaVarStmnt.getModifiers(), javaVarStmnt.fragments(), javaVarStmnt.getType()); popStatement(); // VariableStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaVarStmnt); return false; } @@ -2144,7 +2276,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public boolean visit(VariableDeclarationExpression javaVarDeclExpr) { createAndFillVarOrConstDeclarationList(javaVarDeclExpr.getModifiers(), javaVarDeclExpr.fragments(), javaVarDeclExpr.getType()); - ++countExprTransformed; + exprTransformed.add(javaVarDeclExpr); return false; } @@ -2182,7 +2314,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // IfStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaIfStmt); return false; } @@ -2200,6 +2332,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaLoopBody.accept(this); popIterationStatement(); // WhileStatementContext + + stmtTransformed.add(javaWhileStmt); return false; } @@ -2220,6 +2354,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaExpr.accept(this); popIterationStatement(); // DoStatementContext + + stmtTransformed.add(javaDoStmt); return false; } @@ -2299,7 +2435,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsInitStmts.addAll(stsBlock.statementOrLocalDeclaration()); } - ++countDeclTransformed; + declTransformed.add(javaInitializer); return false; } @@ -2313,11 +2449,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // ClassLiteralExpressionContext // PrimaryTypeContext . class @Override - public boolean visit(TypeLiteral node) { + public boolean visit(TypeLiteral javaTypeLiteral) { pushCurrent(new ClassLiteralExpressionContext(pushSingleExpression())); // Translate type - node.getType().accept(this); + javaTypeLiteral.getType().accept(this); // Add . and class tokens stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Dot)); @@ -2325,7 +2461,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // ClassLiteralExpressionContext - ++countExprTransformed; + exprTransformed.add(javaTypeLiteral); return false; } @@ -2341,7 +2477,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaExprStmt.getExpression().accept(this); popStatement(); - ++countStmtTransformed; + stmtTransformed.add(javaExprStmt); return false; } @@ -2378,7 +2514,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // AssignmentExpressionContext or AssignmentOperatorExpressionContext - ++countExprTransformed; + exprTransformed.add(javaAssignment); return false; } @@ -2409,7 +2545,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); - ++countStmtTransformed; + stmtTransformed.add(javaAssertStmt); return false; } @@ -2440,7 +2576,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaCtorInvocation.arguments(), null, isThrowingCall); - ++countStmtTransformed; + stmtTransformed.add(javaCtorInvocation); return false; } @@ -2474,7 +2610,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaSuperCtorInvocation.getExpression(), isThrowingCall); - ++countStmtTransformed; + stmtTransformed.add(javaSuperCtorInvocation); return false; } @@ -2538,74 +2674,71 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // IndexExpressionContext popSingleExpression(); // ArrayAccessExpression - ++countExprTransformed; + exprTransformed.add(javaArrayAccess); return false; } // Java tree: - // Expression: - // | ArrayCreation // ArrayCreation: - // new PrimitiveType [ Expression ] { [ Expression ] } { [ ] } - // new TypeName [ < Type { , Type } > ] [ Expression ] { [ Expression ] } { [ ] } - // new PrimitiveType [ ] { [ ] } ArrayInitializer - // new TypeName [ < Type { , Type } > ] [ ] { [ ] } ArrayInitializer + // new PrimitiveType [ Expression ] { [ Expression ]+ } { [ ]+ } + // new TypeName [ < Type { , Type }* > ] [ Expression ] { [ Expression ]+ } { [ ]+ } // STS tree: // singleExpression: - // | New primaryType indexExpression+ # NewArrayExpression + // | New primaryType indexExpression+ (OpenBracket CloseBracket)* # NewArrayExpression + // + // Java tree: + // new PrimitiveType [ ] { [ ]+ } ArrayInitializer + // new TypeName [ < Type { , Type }* > ] [ ] { [ ]+ } ArrayInitializer + // STS tree: + // singleExpression: + // | OpenBracket expressionSequence? CloseBracket # ArrayLiteralExpression @Override public boolean visit(ArrayCreation javaArrayCreation) { - pushCurrent(new NewArrayExpressionContext(pushSingleExpression())); + ArrayInitializer javaArrayInitializer = javaArrayCreation.getInitializer(); + if (javaArrayInitializer != null) { + // For array creation expressions with array initializer, + // emit ArrayLiteralExpressionContext node + javaArrayInitializer.accept(this); + return false; + } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)).setParent(stsCurrent); + // Otherwise, emit NewArrayExpressionContext node + pushCurrent(new NewArrayExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)); - // Java tree: - // ArrayType: Type Dimension { Dimension } - // Dimension: { Annotation } [] - // STS tree: - // primaryType - javaArrayCreation.getType().getElementType().accept(this); + ArrayType javaArrayType = javaArrayCreation.getType(); + javaArrayType.getElementType().accept(this); List javaIndexExpressions = javaArrayCreation.dimensions(); for (Expression javaIndexExpression : javaIndexExpressions) { pushCurrent(new IndexExpressionContext(stsCurrent, 0)); - - if (javaIndexExpression != null) // May be 'null' to create just an empty index expression: [] - javaIndexExpression.accept(this); - + javaIndexExpression.accept(this); popCurrent(); // IndexExpressionContext } - // TODO: -// int n = javaArrayType.getDimensions(); -// for (int i = 0; i < n; i++) { -// createIndexExpression(null); // create just an empty index expression: [] -// } + int javaNumIndexExpr = javaIndexExpressions.size(); + int javaArrayTypeDims = javaArrayType.dimensions().size(); + if (javaArrayTypeDims > javaNumIndexExpr) { + // Dimensionality of array type can exceed the number of index expressions + // in the case current new array creation expression ends with empty dimensions. + // All we need to do here is to emit the same empty dimensions here. + for (int i = javaNumIndexExpr; i < javaArrayTypeDims; ++i) { + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.OpenBracket)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.CloseBracket)); + } + } - // The NewArrayExpression has to be pop in any case. If there's no initializers then - // this is the end of the translation. If the initializer is present then it will be - // added directly to the parent node without the NewArrayExpression. popSingleExpression(); // NewArrayExpressionContext - // STS tree: - ArrayInitializer javaArrayInitializer = javaArrayCreation.getInitializer(); - if (javaArrayInitializer != null) { - stsCurrent.removeLastChild(); // Remove NewArrayExpression from the parent Initializer. - - // Java tree: - // ArrayInitializer: { [ Expression { , Expression} [ , ]] } - // STS tree: - // arrayLiteral: OpenBracket expressionSequence? CloseBracket - javaArrayInitializer.accept(this); - } - + exprTransformed.add(javaArrayCreation); return false; } // Java tree: // ArrayInitializer: { [ Expression { , Expression} [ , ]] } // STS tree: - // arrayLiteral: OpenBracket expressionSequence? CloseBracket + // singleExpression: + // | OpenBracket expressionSequence? CloseBracket # ArrayLiteralExpression @Override public boolean visit(ArrayInitializer javaArrayInitializer) { List javaExpressions = javaArrayInitializer.expressions(); @@ -2621,8 +2754,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ExpressionSequenceContext popSingleExpression(); // ArrayLiteralContext - // TODO: Needs reworking - // ++countExprTransformed; + exprTransformed.add(javaArrayInitializer); return false; } @@ -2641,7 +2773,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CastExpressionContext - ++countExprTransformed; + exprTransformed.add(javaCastExpression); return false; } @@ -2661,7 +2793,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ClassBodyContext - ++countDeclTransformed; + declTransformed.add(javaAnonymousClassDeclaration); return false; } @@ -2674,12 +2806,12 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // AnonymousClassDeclaration: { ClassBodyDeclaration } // STS tree: // singleExpression: - // | New typeReference arguments? classBody? # NewClassExpression + // | New (singleExpression Dot)? typeReference arguments? classBody? # NewClassExpression // arguments: OpenParen expressionSequence? CloseParen // classBody: OpenBrace classMember* clinit=classInitializer? classMember* CloseBrace // NOTE: If ctor called by class instance creation expression can throw exceptions, // wrap result in try expression. - // | Try singleExpression #TryExpression + // | Try singleExpression #TryExpression @Override public boolean visit(ClassInstanceCreation javaClassInstanceCreation) { IMethodBinding javaCtorBinding = javaClassInstanceCreation.resolveConstructorBinding(); @@ -2698,9 +2830,12 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } pushCurrent(new NewClassExpressionContext(pushSingleExpression())); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)).setParent(stsCurrent); - // TODO: What to do with javaClassInstanceCreation.getExpression() ? + + // Add outer class object, if any. + Expression javaOuterObject = javaClassInstanceCreation.getExpression(); + if (javaOuterObject != null) javaOuterObject.accept(this); + javaClassInstanceCreation.getType().accept(this); translateArguments(javaClassInstanceCreation.arguments()); @@ -2710,13 +2845,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaAnonymousClassDeclaration.accept(this); } - popSingleExpression(); + popSingleExpression(); // NewClassExpressionContext if (ctorCanThrow) { popSingleExpression(); // TryExpressionContext } - ++countExprTransformed; + exprTransformed.add(javaClassInstanceCreation); return false; } @@ -2779,7 +2914,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popIterationStatement(); // IterationStatementContext + ForStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaForStmt); return false; } @@ -2809,7 +2944,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popIterationStatement(); // IterationStatementContext + ForOfStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaEnhancedForStmt); return false; } @@ -2829,7 +2964,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popStatement(); // BreakStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaBreak); return false; } @@ -2849,7 +2984,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popStatement(); // ContinueStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaContinue); return false; } @@ -2870,7 +3005,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popStatement(); // ReturnStatementContext - ++countStmtTransformed; + stmtTransformed.add(javaReturn); return false; } @@ -2890,7 +3025,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // TernaryExpressionContext - ++countExprTransformed; + exprTransformed.add(javaConditionalExpr); return false; } @@ -2909,7 +3044,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // MemberAccessExpressionContext - ++countExprTransformed; + exprTransformed.add(javaFieldAccess); return false; } @@ -2937,7 +3072,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaSuperFieldAccess.getName())); popSingleExpression(); // MemberAccessExpressionContext - ++countExprTransformed; + exprTransformed.add(javaSuperFieldAccess); return false; } @@ -2959,7 +3094,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // InstanceofExpression - ++countExprTransformed; + exprTransformed.add(javaInstanceofExpr); return false; } @@ -3019,7 +3154,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // TryExpressionContext } - ++countExprTransformed; + exprTransformed.add(javaMethodInvocation); return false; } @@ -3056,7 +3191,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { translateArguments(javaSuperMethodInvocation.arguments()); popSingleExpression(); // CallExpressionContext - ++countExprTransformed; + exprTransformed.add(javaSuperMethodInvocation); return false; } @@ -3076,7 +3211,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.This)); popSingleExpression(); // ThisExpressionContext - ++countExprTransformed; + exprTransformed.add(javaThisExpr); return false; } @@ -3092,7 +3227,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public boolean visit(TypeDeclarationStatement javaTypeDeclarationStmt) { javaTypeDeclarationStmt.getDeclaration().accept(this); - ++countStmtTransformed; + stmtTransformed.add(javaTypeDeclarationStmt); return false; } @@ -3192,7 +3327,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // BlockContext } - ++countStmtTransformed; + stmtTransformed.add(javaSwitchStmt); return false; } @@ -3220,7 +3355,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } // SwitchCase is treated as Statement node, thus increment the count. - ++countStmtTransformed; + stmtTransformed.add(javaSwitchCase); return false; } @@ -3331,7 +3466,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } } - ++countStmtTransformed; + stmtTransformed.add(javaVarDeclStmt); } private boolean isUsedInAnotherCaseClause(VariableDeclarationFragment javaVarDecl, SwitchCase javaSwitchCase, @@ -3455,7 +3590,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // LambdaBodyContext popSingleExpression(); // LambdaExpressionContext - ++countExprTransformed; + exprTransformed.add(javaLambdaExpr); return false; } @@ -3588,7 +3723,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // TrapStatementContext } - ++countStmtTransformed; + stmtTransformed.add(javaTryStatement); return false; } @@ -3672,7 +3807,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // BlockContext - ++countStmtTransformed; + stmtTransformed.add(javaSynchrStmt); return false; } @@ -3699,6 +3834,40 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return stsCallExpr; } + // NOTE: The following AST nodes should not appear in Java 9 sources + // but since they are supported by the version of Eclipse JDT we use, + // let's report in case we see them. + @Override + public boolean visit(UnionType javaUnionType) { + // Emit __UnknownType__, warn and continue. + reportError("Unsupported Java syntax (union type)", javaUnionType); + return false; + } + + @Override + public boolean visit(TextBlock javaTextBlock) { + // Emit __untranslatedExpression call, warn and continue. + stsCurrent.addChild(NodeBuilder.untranslatedExpression(javaTextBlock)).setParent(stsCurrent); + reportError("Unsupported Java syntax (text block)", javaTextBlock); + return false; + } + + @Override + public boolean visit(SwitchExpression javaSwitchExpression) { + // Emit __untranslatedExpression call, warn and continue. + stsCurrent.addChild(NodeBuilder.untranslatedExpression(javaSwitchExpression)).setParent(stsCurrent); + reportError("Unsupported Java syntax (switch expression)", javaSwitchExpression); + return false; + } + + @Override + public boolean visit(YieldStatement javaYieldStatement) { + // Emit __untranslatedStatement call, warn and continue. + stsCurrent.addChild(NodeBuilder.untranslatedStatement(javaYieldStatement)).setParent(stsCurrent); + reportError("Unsupported Java syntax (yield statement)", javaYieldStatement); + return false; + } + // The list of not yet translated Java Expressions: // CreationReference, // SuperMethodReference, diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index af215832cba79cb6f1270f7ee5d8082925b99d72..f235d8720f04b9844391e05a099f6b74018c6dec 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -418,11 +418,11 @@ expressionStatement // Expressions singleExpression - : OpenParen parameterList? CloseParen typeAnnotation Arrow lambdaBody # LambdaExpression + : OpenParen parameterList? CloseParen typeAnnotation Arrow lambdaBody # LambdaExpression | singleExpression indexExpression # ArrayAccessExpression | singleExpression Dot Identifier # MemberAccessExpression - | New typeReference arguments? classBody? # NewClassExpression - | New primaryType indexExpression+ # NewArrayExpression + | New (singleExpression Dot)? typeReference arguments? classBody? # NewClassExpression + | New primaryType indexExpression+ (OpenBracket CloseBracket)* # NewArrayExpression | singleExpression typeArguments? arguments # CallExpression | singleExpression {this.notLineTerminator()}? PlusPlus # PostIncrementExpression | singleExpression {this.notLineTerminator()}? MinusMinus # PostDecreaseExpression diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 6cff9ad2df8d68be43033f3f2cd285a4fadd7007..b50fd8cd6d7b9c6647d736f3ec804ea1e855f29c 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -1578,11 +1578,17 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // | New typeReference arguments? classBody? # NewClassExpression + // | New (singleExpression Dot)? typeReference arguments? classBody? # NewClassExpression @Override public Void visitNewClassExpression(NewClassExpressionContext stsNewClassExpression) { sb.append(stsNewClassExpression.New().getText()).append(' '); + SingleExpressionContext stsOuterObject = stsNewClassExpression.singleExpression(); + if (stsOuterObject != null) { + stsOuterObject.accept(this); + sb.append('.'); + } + visitTypeReference(stsNewClassExpression.typeReference()); ArgumentsContext stsArguments = stsNewClassExpression.arguments(); @@ -1598,11 +1604,11 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // | New primaryType indexExpression+ # NewArrayExpression + // | New primaryType indexExpression+ (OpenBracket CloseBracket)* # NewArrayExpression @Override public Void visitNewArrayExpression(NewArrayExpressionContext stsNewArrayExpression) { - TerminalNode termNew = stsNewArrayExpression.New(); - sb.append(termNew.getText()).append(' '); + TerminalNode stsTerm = stsNewArrayExpression.New(); + sb.append(stsTerm.getText()).append(' '); PrimaryTypeContext stsPrimaryType = stsNewArrayExpression.primaryType(); visitPrimaryType(stsPrimaryType); @@ -1612,6 +1618,14 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { for (IndexExpressionContext stsIndex : stsIndexList) visitIndexExpression(stsIndex); + List emptyDims = stsNewArrayExpression.OpenBracket(); + if (emptyDims != null && !emptyDims.isEmpty()) { + assert(stsNewArrayExpression.CloseBracket().size() == emptyDims.size()); + for (int i = 0; i < emptyDims.size(); ++i) { + sb.append("[]"); + } + } + return null; } diff --git a/migrator/test/java/array_creation.java b/migrator/test/java/array_creation.java index 03209c9a4df05c1d4e8df8e2a35aae135058bff4..85cea69edc3a41d5afdbd5603ad82faa2ee6d769 100644 --- a/migrator/test/java/array_creation.java +++ b/migrator/test/java/array_creation.java @@ -17,11 +17,13 @@ package com.ohos.migrator.test.java; public class array_creation { private final byte b1[] = new byte[8]; + private final byte b2[][] = new byte[8][]; private final char c1[] = new char[] {'a', 'b', 'c'}; + private final char c2[][][] = new char[5][][]; - private void foo(char c2[]) {} + private void foo(char c2[][]) {} public void bar() { - foo(new char[] {'g', 'k', 'h'}); + foo(new char[][] {{'g'}, {'k', 'h'}}); } -} \ No newline at end of file +} diff --git a/migrator/test/java/array_creation.java.sts b/migrator/test/java/array_creation.java.sts index 6267de61834d43927a3ead28edaa43d6c54b93c7..f71941dc66ae7cee61ab6b2f33b9d26bea7a7396 100644 --- a/migrator/test/java/array_creation.java.sts +++ b/migrator/test/java/array_creation.java.sts @@ -17,10 +17,12 @@ package com.ohos.migrator.test.java; export open class array_creation { private const b1 : byte[] = new byte[8]; + private const b2 : byte[][] = new byte[8][]; private const c1 : char[] = ['a', 'b', 'c']; - private foo(c2 : char[]): void { + private const c2 : char[][][] = new char[5][][]; + private foo(c2 : char[][]): void { } public open bar(): void { - foo(['g', 'k', 'h']); + foo([['g'], ['k', 'h']]); } } diff --git a/migrator/test/java/class_instance_creation.java b/migrator/test/java/class_instance_creation.java index 53d1eb020f644c0029497a93c44da23f9a1dcd60..f609c943c6b3769fad38bba47fbe03e3ba582c6c 100644 --- a/migrator/test/java/class_instance_creation.java +++ b/migrator/test/java/class_instance_creation.java @@ -29,4 +29,15 @@ class class_instance_creation { private int f; public void foo() { f = 2; } }; + + class inner { + inner(int i) {} + } + + inner inner_inst1 = new inner(1); + inner inner_inst2 = inst1.new inner(2); + inner inner_inst3 = inst4.new inner(3) { + private String s; + public void bar() { s = "bar"; } + }; } diff --git a/migrator/test/java/class_instance_creation.java.sts b/migrator/test/java/class_instance_creation.java.sts index 73b5678318ce06598c48c50fc23aaeaac287b0c7..fcd50901ce2f1062821f742251064c247adee745 100644 --- a/migrator/test/java/class_instance_creation.java.sts +++ b/migrator/test/java/class_instance_creation.java.sts @@ -36,5 +36,19 @@ open class class_instance_creation { f = 2; } }; + + open class inner { + constructor(i : int) { + } + } + + inner_inst1 : inner = new inner(1); + inner_inst2 : inner = new inst1.inner(2); + inner_inst3 : inner = new inst4.inner(3) { + private s : String ; + public open bar(): void { + s = "bar"; + } + }; } diff --git a/migrator/test/java/enum_with_class_behavior.java b/migrator/test/java/enum_with_class_behavior.java index 2331696add1f420761a96ce822c62bcfb44a78df..ff6d2406bee1f74e7b4a547a9bb15b4ee7f22792 100644 --- a/migrator/test/java/enum_with_class_behavior.java +++ b/migrator/test/java/enum_with_class_behavior.java @@ -78,6 +78,14 @@ enum Planet { this(mass, radius, PlanetType.ROCK); } + // Checks addition of name and ordinal parameters + // to explciitly-defined parameter-less enum ctor. + private Planet() { + mass = 0.; + radius = 0.; + type = PlanetType.ROCK; + } + // universal gravitational constant (m3 kg-1 s-2) public static final double G = 6.67300E-11; diff --git a/migrator/test/java/enum_with_class_behavior.java.sts b/migrator/test/java/enum_with_class_behavior.java.sts index 6fab978ac04fd1519eb76005d5a594c8711e98ac..2fb6e6d4c798de98332134aeef0c3a1fa564a8dd 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -101,6 +101,13 @@ class Planet extends Enum { this(name, ordinal, mass, radius, PlanetType.ROCK); } + private constructor(name : String, ordinal : int) { + super(name, ordinal); + mass = 0.; + radius = 0.; + type = PlanetType.ROCK; + } + public static const G : double = 6.67300E-11; open surfaceGravity(): double { diff --git a/migrator/test/java/generic_class_2.java.sts b/migrator/test/java/generic_class_2.java.sts index 1bd7124f446c87af7f0500a18e8e3dbb27c2a382..2837a5960f4c2223391bc31ce019a625192676f5 100644 --- a/migrator/test/java/generic_class_2.java.sts +++ b/migrator/test/java/generic_class_2.java.sts @@ -35,7 +35,7 @@ open class Seq { return new Seq>(); } else { - let tailZipper : Seq.Zipper = new Zipper(); + let tailZipper : Seq.Zipper = new tail.Zipper(); return new Seq>(new Pair(head, that.head), tailZipper.zip(that.tail)); } } @@ -57,7 +57,7 @@ open class Test { public static main(args : String[]): void { let strs : Seq = new Seq("a", new Seq("b", new Seq())); let nums : Seq = new Seq(new Integer(1), new Seq(new Double(1.5), new Seq())); - let zipper : Seq.Zipper = new Zipper(); + let zipper : Seq.Zipper = new strs.Zipper(); let combined : Seq> = zipper.zip(nums); } }