diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 057415c05b86f058ab1e6840316dad7bee3716d0..97e651b0f8d8d8ff777216e602c02b56a41bb16b 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -53,6 +53,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private final String ENUM_CONST_ORDINAL = "ENUM_CONST_ORDINAL"; + private final ITypeBinding RUNTIME_EXCEPTION_TYPE; + private final ITypeBinding THROWABLE_TYPE; + private static int countStmtTotal = 0; private static int countExprTotal = 0; private static int countDeclTotal = 0; @@ -156,6 +159,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public JavaTransformer(CompilationUnit javaCU, File srcFile) { this.javaCU = javaCU; this.srcFile = srcFile; + AST javaAST = this.javaCU.getAST(); + RUNTIME_EXCEPTION_TYPE = javaAST.resolveWellKnownType("java.lang.RuntimeException"); + THROWABLE_TYPE = javaAST.resolveWellKnownType("java.lang.Throwable"); } public CompilationUnitContext transform() { @@ -664,11 +670,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // import [ static ] Name [ . * ] ; // // STS tree: - // importStatement - // : Import qualifiedName (Dot Multiply)? SemiColon + // importDeclaration + // : Import qualifiedName (Dot Multiply)? SemiColon? @Override public boolean visit(ImportDeclaration javaImportDeclaration) { - pushCurrent(new ImportStatementContext(stsCurrent, 0)); + pushCurrent(new ImportDeclarationContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Import)); stsCurrent.addChild(NodeBuilder.qualifiedName(javaImportDeclaration.getName())); @@ -680,7 +686,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.SemiColon)); - popCurrent(); // ImportStatementContext + popCurrent(); // ImportDeclarationContext ++countDeclTransformed; return false; @@ -1569,24 +1575,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaVariableDeclarationFragment.getName())); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); IVariableBinding variableBinding = javaVariableDeclarationFragment.resolveBinding(); if (variableBinding != null) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); translateType(variableBinding.getType()); + popCurrent(); // TypeAnnotationContext } else { // Warn and emit __UnknownType__ as variable type - String loc = srcFile.getPath() + ":" + javaCU.getLineNumber(javaVariableDeclarationFragment.getStartPosition()); - Main.addError(ResultCode.TranspileError, "Failed to resolve lambda parameter at " + loc); - - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference("__UnknownType__")).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext + reportError("Failed to resolve lambda parameter", javaVariableDeclarationFragment); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(null)).setParent(stsCurrent); } - popCurrent(); // TypeAnnotationContext - // Note: no need to process the "{ Dimension }" part, as the extra dimensions // of the declaration are covered by "translateType(ITypeBinding)" call. @@ -1992,16 +1993,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - @Override - public boolean visit(Block javaBlock) { - BlockContext stsBlock = new BlockContext(null, 0); - pushStatement(stsBlock); + private void translateBlockStatements(Block javaBlock) { List javaBlockStmts = javaBlock.statements(); for(Statement javaStmt : javaBlockStmts) { javaStmt.accept(this); } + } + @Override + public boolean visit(Block javaBlock) { + pushStatement(new BlockContext(stsCurrent, 0)); + translateBlockStatements(javaBlock); popStatement(); // BlockContext ++countStmtTransformed; @@ -2407,16 +2410,36 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // this ( [ Expression { , Expression } ] ) ; // STS tree: // constructorCall: - // this typeArguments? arguments SemiColon + // Try? + // ( + // This typeArguments? arguments + // | (singleExpression Dot)? Super typeArguments? arguments + // ) @Override public boolean visit(ConstructorInvocation javaCtorInvocation) { - TerminalNode stsThis = NodeBuilder.terminalNode(StaticTSParser.This); - translateCtorInvocation(stsThis, javaCtorInvocation.typeArguments(), javaCtorInvocation.arguments(), null); + IMethodBinding javaCtorBinding = javaCtorInvocation.resolveConstructorBinding(); + boolean isThrowingCall = false; + if (javaCtorBinding != null) { + isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to resolve constructor call", javaCtorInvocation); + } + + translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.This), + javaCtorInvocation.typeArguments(), + javaCtorInvocation.arguments(), + null, isThrowingCall); ++countStmtTransformed; return false; } + private void reportError(String message, ASTNode node) { + String loc = srcFile.getPath() + ":" + javaCU.getLineNumber(node.getStartPosition()); + Main.addError(ResultCode.TranspileError, message + " at " + loc); + } + // Java tree: // SuperConstructorInvocation: // [ Expression . ] @@ -2427,16 +2450,34 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | (singleExpression . )? super typeArguments? arguments SemiColon @Override public boolean visit(SuperConstructorInvocation javaSuperCtorInvocation) { - TerminalNode stsSuper = NodeBuilder.terminalNode(StaticTSParser.Super); - translateCtorInvocation(stsSuper, javaSuperCtorInvocation.typeArguments(), javaSuperCtorInvocation.arguments(), javaSuperCtorInvocation.getExpression()); + IMethodBinding javaCtorBinding = javaSuperCtorInvocation.resolveConstructorBinding(); + boolean isThrowingCall = false; + if (javaCtorBinding != null) { + isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to report constructor call", javaSuperCtorInvocation); + } + + translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.Super), + javaSuperCtorInvocation.typeArguments(), + javaSuperCtorInvocation.arguments(), + javaSuperCtorInvocation.getExpression(), + isThrowingCall); ++countStmtTransformed; return false; } - private void translateCtorInvocation(TerminalNode stsThisOrSuper, List javaTypeArgs, List javaArgs, Expression javaCtorExpr) { + // NOTE: If ctor called can throw exceptions, prepend 'try' keyword to result. + private void translateCtorInvocation(TerminalNode stsThisOrSuper, List javaTypeArgs, + List javaArgs, Expression javaCtorExpr, + boolean isThrowingCall) { pushCurrent(new ConstructorCallContext(stsCurrent, 0)); + // Add 'try' keyword if this is a throwing call. + if (isThrowingCall) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + if (javaCtorExpr != null) { javaCtorExpr.accept(this); } @@ -2631,8 +2672,26 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | New 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 @Override public boolean visit(ClassInstanceCreation javaClassInstanceCreation) { + IMethodBinding javaCtorBinding = javaClassInstanceCreation.resolveConstructorBinding(); + boolean ctorCanThrow = false; + if (javaCtorBinding != null) { + ctorCanThrow = javaCtorBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to resolve instance creation expression", javaClassInstanceCreation); + } + + // Add TryExpressionContext if ctor invoked can throw + if (ctorCanThrow) { + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } + pushCurrent(new NewClassExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)).setParent(stsCurrent); @@ -2648,6 +2707,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); + if (ctorCanThrow) { + popSingleExpression(); // TryExpressionContext + } + ++countExprTransformed; return false; } @@ -2909,8 +2972,25 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // typeArgument: typeReference | arrayType // arguments: OpenParen expressionSequence? CloseParen // expressionSequence: singleExpression (Comma singleExpression)* + // NOTE: If method called can throw exceptions, wrap result in try expression. + // | Try singleExpression #TryExpression @Override public boolean visit(MethodInvocation javaMethodInvocation) { + IMethodBinding javaMethodBinding = javaMethodInvocation.resolveMethodBinding(); + boolean isThrowingCall = false; + if (javaMethodBinding != null) { + isThrowingCall = javaMethodBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to resolve method call", javaMethodInvocation); + } + + // Add TryExpressionContext if this is a throwing call. + if (isThrowingCall) { + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } + pushCurrent(new CallExpressionContext(pushSingleExpression())); Expression javaObjectExpression = javaMethodInvocation.getExpression(); @@ -2931,6 +3011,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CallExpressionContext + if (isThrowingCall) { + popSingleExpression(); // TryExpressionContext + } + ++countExprTransformed; return false; } @@ -3336,23 +3420,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { createStsParameterList(javaLambdaExpr.parameters()); IMethodBinding lambdaMethod = javaLambdaExpr.resolveMethodBinding(); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); if (lambdaMethod != null) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); translateType(lambdaMethod.getReturnType()); + popCurrent(); // TypeAnnotationContext } else { // Warn and emit __UnknownType__ as return type - String loc = srcFile.getPath() + ":" + javaCU.getLineNumber(javaLambdaExpr.getStartPosition()); - Main.addError(ResultCode.TranspileError, "Failed to resolve lambda expression at " + loc); - - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference("__UnknownType__")).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext + reportError("Failed to resolve lambda expression", javaLambdaExpr); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(null)).setParent(stsCurrent); } - popCurrent(); // TypeAnnotationContext - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); pushCurrent(new LambdaBodyContext(stsCurrent, 0)); @@ -3361,17 +3440,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (javaBody instanceof Expression) { javaBody.accept(this); } else { - // Better this than calling javaBody.accept(this) here - // as visit(Block) will call pushStatement() which will - // add StatementContext node which isn't needed here. + // NOTE: Can't call javaBody.accept as that will emit + // StatementContext which we don't need here pushCurrent(new BlockContext(stsCurrent, 0)); - - Block javaBlock = (Block) javaBody; - List javaBlockStmts = javaBlock.statements(); - for (Statement javaStmt : javaBlockStmts) { - javaStmt.accept(this); - } - + translateBlockStatements((Block)javaBody); popCurrent(); // BlockContext } popCurrent(); // LambdaBodyContext @@ -3434,16 +3506,131 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + // Java AST: + // TryStatement: + // try Block Catches + // try Block [Catches] Finally + // + // STS AST: + // trapStatement + // : Trap block catchOrRecoverClause+ + // ; + // + // catchOrRecoverClause + // : (Catch | Recover) exceptionParameter? block + // ; + // + // exceptionParameter + // : OpenParen Identifier typeAnnotation CloseParen + // ; @Override public boolean visit(TryStatement javaTryStatement) { - // TODO: To be implemented - // Emit __untranslated_statement 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.untranslatedStatement(javaTryStatement)).setParent(stsCurrent); + List javaCatchClauses = javaTryStatement.catchClauses(); + + // If there are no catch clauses (implying there must be a finally clause), + // don't emit trap statement. Emit a plain block instead with defer statement + // representing finally clause. + if (!javaCatchClauses.isEmpty()) { + pushStatement(new TrapStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); + pushCurrent(new BlockContext(stsCurrent, 0)); + } + else { + pushStatement(new BlockContext(stsCurrent, 0)); + } + + // If there is a finally clause, create a defer statement + // and add it to the beginning of trap block + Block javaFinally = javaTryStatement.getFinally(); + if (javaFinally != null) { + pushStatement(new DeferStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Defer)); + javaFinally.accept(this); + popStatement(); // DeferStatementContext + } + + // NOTE: Can't call javaTryBlock.accept as that will + // emit StatementContext which we don't need here + Block javaTryBlock = javaTryStatement.getBody(); + translateBlockStatements(javaTryBlock); + + if (!javaCatchClauses.isEmpty()) { + popCurrent(); // BlockContext + } + else { + popStatement(); // BlockContext + } + + for (CatchClause javaCatchClause: javaCatchClauses) { + SingleVariableDeclaration javaException = javaCatchClause.getException(); + Type javaExceptionType = javaException.getType(); + Block javaCatchBody = javaCatchClause.getBody(); + SimpleName javaExceptionName = javaException.getName(); + if (javaExceptionType.isUnionType()) { + List javaExcTypes = ((UnionType)javaExceptionType).types(); + for (Type javaExcType : javaExcTypes) { + createCatchOrRecoverClause(javaExcType, javaExceptionName, javaCatchBody); + } + } + else { + createCatchOrRecoverClause(javaExceptionType, javaExceptionName, javaCatchBody); + } + + } + + if (!javaCatchClauses.isEmpty()) { + popStatement(); // TrapStatementContext + } + + ++countStmtTransformed; return false; } + private void createCatchOrRecoverClause(Type javaExceptionType, + SimpleName javaExceptionName, + Block javaClauseBody) { + pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); + + // Emit 'recover' keyword instead of 'catch' if + // exception type is a subtype of RuntimeException. + ITypeBinding javaExcTypeBinding = javaExceptionType.resolveBinding(); + int termCode = isRuntimeExceptionType(javaExcTypeBinding) ? + StaticTSParser.Recover : StaticTSParser.Catch; + stsCurrent.addChild(NodeBuilder.terminalNode(termCode)); + + pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaExceptionName)); + if (isValidExceptionType(javaExcTypeBinding)) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + javaExceptionType.accept(this); + popCurrent(); // TypeAnnotationContext + } + else { + // Warn and emit __UnknownType__ for invalid exception types + reportError("Failed to resolve exception type", javaExceptionType); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaExceptionType)).setParent(stsCurrent); + } + popCurrent(); // ExceptionParameterContext + + // NOTE: Can't call javaClauseBody.accept as that will + // emit StatementContext which we don't need here + pushCurrent(new BlockContext(stsCurrent, 0)); + translateBlockStatements(javaClauseBody); + popCurrent(); // BlockContext + + popCurrent(); // CatchOrRecoverClauseContext + } + private boolean isRuntimeExceptionType(ITypeBinding javaExcType) { + return isValidExceptionType(javaExcType) && + (javaExcType.isEqualTo(RUNTIME_EXCEPTION_TYPE) || + javaExcType.isSubTypeCompatible(RUNTIME_EXCEPTION_TYPE)); + } + + private boolean isValidExceptionType(ITypeBinding javaExcType) { + return javaExcType != null && !javaExcType.isRecovered() && javaExcType.isClass() && + (javaExcType.isEqualTo(THROWABLE_TYPE) || javaExcType.isSubTypeCompatible(THROWABLE_TYPE)); + } @Override public boolean visit(ThrowStatement javaThrowStatement) { // TODO: To be implemented diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index cdea22909f9aa16e8de0a564334a2fd1c45c8ca8..4c755679afcf689c5fa6069ee5e994923296b506 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -411,6 +411,16 @@ public class NodeBuilder { return stsExpression; } + public static TypeAnnotationContext unknownTypeAnnotation(Type javaType) { + TypeAnnotationContext stsTypeAnnotation = typeAnnotation("__UnknownType__"); + + if (javaType != null) { + stsTypeAnnotation.addChild(multiLineComment("/* " + javaType.toString() + " */")); + } + + return stsTypeAnnotation; + } + public static StatementContext untranslatedStatement(ASTNode node) { StatementContext stsStatement = new StatementContext(null, 0); ExpressionStatementContext stsExprStatement = new ExpressionStatementContext(stsStatement, 0); diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 index d915ba7ca59a71b474f92584b195eb5e1132c523..691dbf922e0e8326991bdeda5d18c5e451aff731 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 @@ -111,8 +111,6 @@ Instanceof: 'instanceof'; Case: 'case'; Else: 'else'; New: 'new'; -Catch: 'catch'; -Finally: 'finally'; Return: 'return'; Continue: 'continue'; For: 'for'; @@ -127,6 +125,9 @@ Throw: 'throw'; Of: 'of'; Try: 'try'; Defer: 'defer'; +Trap: 'trap'; +Catch: 'catch'; +Recover: 'recover'; From: 'from'; As: 'as'; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index ca2f06803c73b85c89d63c120361c6ad318ce28b..af215832cba79cb6f1270f7ee5d8082925b99d72 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -50,15 +50,15 @@ options { } compilationUnit - : packageDeclaration? importStatement* topDeclaration* EOF + : packageDeclaration? importDeclaration* topDeclaration* EOF ; packageDeclaration : Package qualifiedName SemiColon? // notLineTerminator ; -importStatement - : Import qualifiedName ((As Identifier) | (Dot Multiply))? SemiColon // notLineTerminator +importDeclaration + : Import qualifiedName ((As Identifier) | (Dot Multiply))? SemiColon? // notLineTerminator ; qualifiedName @@ -138,8 +138,11 @@ constructorBody ; constructorCall - : This typeArguments? arguments - | (singleExpression Dot)? Super typeArguments? arguments + : Try? + ( + This typeArguments? arguments + | (singleExpression Dot)? Super typeArguments? arguments + ) ; statementOrLocalDeclaration @@ -325,8 +328,8 @@ statement | labelledStatement | switchStatement | throwStatement - | tryStatement | deferStatement + | trapStatement | expressionStatement ; @@ -393,16 +396,16 @@ throwStatement : Throw {this.notLineTerminator()}? singleExpression SemiColon ; -tryStatement - : Try block (catchClause+ finallyClause? | finallyClause) +trapStatement + : Trap block catchOrRecoverClause+ ; -catchClause - : Catch OpenParen Identifier typeAnnotation CloseParen block +catchOrRecoverClause + : (Catch | Recover) exceptionParameter? block ; -finallyClause - : Finally block +exceptionParameter + : OpenParen Identifier typeAnnotation CloseParen ; deferStatement @@ -451,6 +454,7 @@ singleExpression | primaryType Dot Class # ClassLiteralExpression | OpenParen singleExpression CloseParen # ParenthesizedExpression | singleExpression As (intersectionType | primaryType) # CastExpression + | Try singleExpression # TryExpression ; shiftOperator diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 4e652d54f2f7574cb2d1c5fc885bff01b959f54d..6cff9ad2df8d68be43033f3f2cd285a4fadd7007 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -353,9 +353,22 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { PrimaryTypeContext stsType = stsTypeAnnotation.primaryType(); stsType.accept(this); - if (!(stsTypeAnnotation.parent instanceof ParameterContext)) + if (stsTypeAnnotation.parent.getRuleIndex() != StaticTSParser.RULE_parameter && + stsTypeAnnotation.parent.getRuleIndex() != StaticTSParser.RULE_exceptionParameter) sb.append(' '); + if (stsTypeAnnotation.getChildCount() > 1) { + // In case of unresolved or invalid type, we add a comment to TypeAnnotationContext + // node indicating the original type name where we can (the type itself is emitted as + // __UnknownType__, see, e.g., JavaTransformer.createCatchOrRecoverClause method). + // Here we check if that additional child of TypeAnnotationContext node exists, + // and if so, emit it in STS source code. + ParseTree lastChild = stsTypeAnnotation.getChild(stsTypeAnnotation.getChildCount()-1); + if (lastChild instanceof TerminalNode) { + stsTypeAnnotation.getChild(1).accept(this); + } + } + return null; } @@ -428,13 +441,16 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { public Void visitConstructorCall(ConstructorCallContext stsConstructorCall) { doNeededIndent(); + TerminalNode term = stsConstructorCall.Try(); + if (term != null) sb.append(term.getText()).append(' '); + SingleExpressionContext stsSuperExpr = stsConstructorCall.singleExpression(); if (stsSuperExpr != null) { stsSuperExpr.accept(this); sb.append('.'); } - TerminalNode term = stsConstructorCall.This(); + term = stsConstructorCall.This(); if (term == null) term = stsConstructorCall.Super(); assert(term != null); @@ -629,8 +645,8 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { PackageDeclarationContext stsPackageDecl = stsCompilationUnit.packageDeclaration(); if (stsPackageDecl != null) visitPackageDeclaration(stsPackageDecl); - for (ImportStatementContext stsImportStatement : stsCompilationUnit.importStatement()) { - visitImportStatement(stsImportStatement); + for (ImportDeclarationContext stsImportDeclaration : stsCompilationUnit.importDeclaration()) { + visitImportDeclaration(stsImportDeclaration); } for (TopDeclarationContext stsTopDeclaration : stsCompilationUnit.topDeclaration()) { @@ -663,32 +679,20 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // statement - // : importStatement - // | exportStatement - // | emptyStatement_ - // | abstractDeclaration //ADDED - // | decoratorList - // | classDeclaration - // | interfaceDeclaration //ADDED - // | namespaceDeclaration //ADDED + // statement + // : block + // | assertStatement // | ifStatement // | iterationStatement // | continueStatement // | breakStatement // | returnStatement - // | yieldStatement // | labelledStatement // | switchStatement // | throwStatement - // | tryStatement - // | debuggerStatement - // | functionDeclaration - // | generatorFunctionDeclaration - // | variableStatement - // | enumDeclaration //ADDED + // | deferStatement + // | trapStatement // | expressionStatement - // | Export statement @Override public Void visitStatement(StatementContext stsStatement) { doNeededIndent(); @@ -698,7 +702,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // block: '{' statementList? '}' + // block: '{' statementOrLocalDeclaration* '}' @Override public Void visitBlock(BlockContext stsBlock) { doNeededIndent(); @@ -716,25 +720,24 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // importStatement: Import qualifiedName (Dot Multiply)? SemiColon - @Override - public Void visitImportStatement(ImportStatementContext stsImportStatement) { + // importDeclaration: Import qualifiedName (Dot Multiply)? SemiColon? + public Void visitImportDeclaration(ImportDeclarationContext stsImportDeclatation) { doNeededIndent(); - sb.append(stsImportStatement.Import().getText()).append(' '); + sb.append(stsImportDeclatation.Import().getText()).append(' '); - visitQualifiedName(stsImportStatement.qualifiedName()); + visitQualifiedName(stsImportDeclatation.qualifiedName()); - TerminalNode termDot = stsImportStatement.Dot(); - TerminalNode termAs = stsImportStatement.As(); + TerminalNode termDot = stsImportDeclatation.Dot(); + TerminalNode termAs = stsImportDeclatation.As(); if (termDot != null) { sb.append(termDot.getText()); - TerminalNode termMult = stsImportStatement.Multiply(); + TerminalNode termMult = stsImportDeclatation.Multiply(); assert(termMult != null); sb.append(termMult.getText()); } else if (termAs != null) { sb.append(termAs.getText()).append(' '); - TerminalNode termId = stsImportStatement.Identifier(); + TerminalNode termId = stsImportDeclatation.Identifier(); assert(termId != null); sb.append(termId.getText()); } @@ -881,7 +884,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { @Override public Void visitDoStatement(DoStatementContext stsDoStatement) { doNeededIndent(); - sb.append(stsDoStatement.Do().getText() + "\n"); + sb.append(stsDoStatement.Do().getText()).append("\n"); StatementContext stsStmt = stsDoStatement.statement(); assert(stsStmt != null); @@ -1193,50 +1196,52 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // tryStatement: Try block (catchProduction finallyProduction? | finallyProduction); + // trapStatement: Trap block catchOrRecoverClause+; @Override - public Void visitTryStatement(TryStatementContext stsTryStatement) { + public Void visitTrapStatement(TrapStatementContext stsTrapStatement) { doNeededIndent(); - sb.append(stsTryStatement.Try().getText()).append(' '); - - visitBlock(stsTryStatement.block()); + sb.append(stsTrapStatement.Trap().getText()).append(' '); - List stsCatches = stsTryStatement.catchClause(); - FinallyClauseContext stsFinally = stsTryStatement.finallyClause(); - if (stsCatches != null) { - for (CatchClauseContext stsCatch : stsCatches) { - visitCatchClause(stsCatch); - } - } - else assert(stsFinally != null); + visitBlock(stsTrapStatement.block()); - if (stsFinally != null) { - visitFinallyClause(stsFinally); + List stsCatchesOrRecovers = stsTrapStatement.catchOrRecoverClause(); + assert(stsCatchesOrRecovers != null && !stsCatchesOrRecovers.isEmpty()); + for (CatchOrRecoverClauseContext stsCatchOrRecover : stsCatchesOrRecovers) { + visitCatchOrRecoverClause(stsCatchOrRecover); } sb.append('\n'); return null; } - // catchClause: Catch '(' Identifier typeAnnotation ')' block - public Void visitCatchClause(CatchClauseContext stsCatchClause) { + // catchOrRecoverClause: (Catch|Recover) exceptionParameter? block + + @Override + public Void visitCatchOrRecoverClause(CatchOrRecoverClauseContext stsCatchOrRecoverClause) { doNeededIndent(); - sb.append(stsCatchClause.Catch().getText()).append(" ("); - sb.append(stsCatchClause.Identifier().getText()); - visitTypeAnnotation(stsCatchClause.typeAnnotation()); - sb.append(") "); + TerminalNode stsTerm = stsCatchOrRecoverClause.Catch(); + if (stsTerm == null) stsTerm = stsCatchOrRecoverClause.Recover(); + assert(stsTerm != null); + sb.append(stsTerm.getText()).append(' '); - visitBlock(stsCatchClause.block()); + ExceptionParameterContext stsExceptionParam = stsCatchOrRecoverClause.exceptionParameter(); + if (stsExceptionParam != null) { + visitExceptionParameter(stsExceptionParam); + } + + BlockContext stsBlock = stsCatchOrRecoverClause.block(); + assert(stsBlock != null); + visitBlock(stsBlock); return null; } - // finallyClause: Finally block - public Void visitFinallyClause(FinallyClauseContext stsFinally) { - doNeededIndent(); - sb.append(stsFinally.Finally().getText()).append(' '); - visitBlock(stsFinally.block()); + @Override + public Void visitExceptionParameter(ExceptionParameterContext stsExceptionParam) { + sb.append('(').append(stsExceptionParam.Identifier().getText()).append(' '); + visitTypeAnnotation(stsExceptionParam.typeAnnotation()); + sb.append(") "); return null; } @@ -1857,12 +1862,22 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } + // deferStatement: Defer statement; @Override - public Void visitDeferStatement(DeferStatementContext stsDeferStmt) { + public Void visitDeferStatement(DeferStatementContext stsDeferStatement) { doNeededIndent(); - sb.append(stsDeferStmt.Defer().getText()).append(' '); - stsDeferStmt.statement().accept(this); + sb.append(stsDeferStatement.Defer().getText()).append(' '); + stsDeferStatement.statement().accept(this); + + return null; + } + + // Try singleExpression # TryExpression + @Override + public Void visitTryExpression(TryExpressionContext stsTryExpression) { + sb.append(stsTryExpression.Try()).append(' '); + stsTryExpression.singleExpression().accept(this); return null; } diff --git a/migrator/test/java/try_catch_finally.java b/migrator/test/java/try_catch_finally.java new file mode 100644 index 0000000000000000000000000000000000000000..5a381735604996eb4c7671eedf0ec3fb6d661be1 --- /dev/null +++ b/migrator/test/java/try_catch_finally.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +class BlewIt extends Exception { + BlewIt() { } + BlewIt(String s) { super(s); } +} + +public class try_catch_finally { + public try_catch_finally() throws Exception { } + + public try_catch_finally(int i) throws Exception { this(); } + + static void blowUp() throws BlewIt { } + + private static void foo() throws BlewIt { + try { + blowUp(); + } + finally { + System.out.println("In finally"); + } + } + + public static void main(String[] args) { + try { + blowUp(); + try_catch_finally t = new try_catch_finally(); + } + catch (NullPointerException n) { + System.out.println("Caught NullPointerException"); + } + catch (BlewIt | IllegalArgumentException b) { + System.out.println("Caught BlewIt or IllegalArgumentException"); + } + catch (RuntimeException r) { + System.out.println("Caught RuntimeException"); + } + catch (Exception e) { + System.out.println("Caught Exception"); + } + finally { + System.out.println("In finally"); + } + } +} diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts new file mode 100644 index 0000000000000000000000000000000000000000..c48f24f9766957135b3c9878bbd45d5f1c9699f5 --- /dev/null +++ b/migrator/test/java/try_catch_finally.java.sts @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +open class BlewIt extends Exception { + constructor() { + } + constructor(s : String) { + super(s); + } +} + +export open class try_catch_finally { + public constructor() { + } + + public constructor(i : int) { + try this(); + } + + static blowUp(): void { + } + + private static foo(): void { + { + defer { + System.out.println("In finally"); + } + + try blowUp(); + } + } + + public static main(args : String[]): void { + trap { + defer { + System.out.println("In finally"); + } + try blowUp(); + let t : try_catch_finally = try new try_catch_finally(); + } + recover (n : NullPointerException) { + System.out.println("Caught NullPointerException"); + } + catch (b : BlewIt) { + System.out.println("Caught BlewIt or IllegalArgumentException"); + } + recover (b : IllegalArgumentException) { + System.out.println("Caught BlewIt or IllegalArgumentException"); + } + recover (r : RuntimeException) { + System.out.println("Caught RuntimeException"); + } + catch (e : Exception) { + System.out.println("Caught Exception"); + } + } +}