From faf121bf5aa4afb4e6f6843bdd986e04e7fe1f7b Mon Sep 17 00:00:00 2001 From: Igor Rossinski Date: Wed, 15 Mar 2023 16:50:39 +0300 Subject: [PATCH] [TS linter] add README file and scripts to launch Signed-off-by: Igor Rossinski 1. Translation of TS try and throw statements. 2. Tests to cover the above functionalities. 3. Changes to STS grammar (removing panic statement and recover clause, adding default catch clause, adding throws/rethrows marks to lambdas and function types), and corresponding changes to Java translation. Change-Id: Idd895ac414c4bc90a025ec9881805a6f3478a359 Signed-off-by: Mikhail Velikanov [TS linter] fix minor errors Signed-off-by: Igor Rossinski --- migrator/TSLinter.README.md | 58 +++++++++ .../ohos/migrator/java/JavaTransformer.java | 84 ++++++------- .../migrator/staticTS/NodeBuilderBase.java | 7 ++ .../ohos/migrator/staticTS/NodeClonner.java | 72 +++++------ .../staticTS/parser/StaticTSParser.g4 | 31 +++-- .../staticTS/writer/StaticTSWriter.java | 119 ++++++++++-------- migrator/test/java/method_invocation.java.sts | 6 +- migrator/test/java/method_references.java.sts | 4 +- migrator/test/java/throw_statement.java.sts | 2 +- migrator/test/java/throws_test.java | 6 +- migrator/test/java/throws_test.java.sts | 10 +- migrator/test/java/try_catch_finally.java.sts | 6 +- .../test/java/try_with_resources.java.sts | 98 --------------- migrator/test/ts/throw_statement.ts | 33 +++++ migrator/test/ts/throw_statement.ts.sts | 31 +++++ migrator/test/ts/try_statement.ts | 43 +++++++ migrator/test/ts/try_statement.ts.sts | 43 +++++++ migrator/test/ts/unsupported_types.ts.sts | 2 +- migrator/tslinter.cmd | 19 +++ migrator/tslinter.sh | 22 ++++ .../typescript/src/staticts/NodeCloner.ts | 15 ++- .../typescript/src/transpiler/NodeBuilder.ts | 22 ++++ .../src/transpiler/TranslationUtils.ts | 5 +- .../src/transpiler/TypeScriptTransformer.ts | 112 +++++++++++++++-- 24 files changed, 570 insertions(+), 280 deletions(-) create mode 100644 migrator/TSLinter.README.md create mode 100644 migrator/test/ts/throw_statement.ts create mode 100755 migrator/test/ts/throw_statement.ts.sts create mode 100644 migrator/test/ts/try_statement.ts create mode 100755 migrator/test/ts/try_statement.ts.sts create mode 100644 migrator/tslinter.cmd create mode 100644 migrator/tslinter.sh diff --git a/migrator/TSLinter.README.md b/migrator/TSLinter.README.md new file mode 100644 index 000000000..1d4a3a350 --- /dev/null +++ b/migrator/TSLinter.README.md @@ -0,0 +1,58 @@ +# TypeScript linter +Typescript linter ( further mentioned as 'linter' ) is a tool to check typescript sources and find language elements +and constructions which are deprecated to use in a purpose to migrate sources to STS. +The linter is currently under development. + +## Building +To build linter download from gitee (https://gitee.com/openharmony-sig/arkcompiler_ets_frontend/tree/master/migrator), + +### Requirements +This project is using the **Apache Ant** tool for building. You can download binaries from [here](https://ant.apache.org/bindownload.cgi) (it's recommended to use the latest available version) and use the [official guide](https://ant.apache.org/manual/install.html) to install and setup the tool. + +You also need to use **Java 11** (or newer) to build the project. + +The linter is written on TypeScript and requires NodeJS to build the project and run. For details, see the [typescript](typescript) page. + +### Steps to build + +The build supports two main targets: **clean** and **build**: +- Use **ant clean build** to perform build with preliminary cleaning of previous build artifacts. +- Use **ant build** to do incremental build (does not re-build sources that didn't change). + +The result file is web packet **out/typescript/javascript/src/linter/dist/tslinter.ts**. + +## Running +To use linter after the build, run the following command from the top-level folder of +the repository: + +node ./out/typescript/javascript/src/linter/dist/tslinter.ts [options] [input files] + +or use command files tslinter.sh or tslinter.cmd with same arguments as for direct launch. + +Possible options are: + +**--deveco-plugin-mode** this options defines special mode to launch from IDE and shouldn't be used in command line work + +**--strict** defines 'strict' mode in which all problem TypeScript language elements are counted; + if this option is not set, linter works in 'relax' mode in which counts only elements that cannot be transpiled + by TypeSctipt migrator. + +**--project-folder ** defines path to folder with TypeScript sources and subfolders which linter walks recurscevely. + This option may be repeated in command line with different paths. + +All other command line arguments are considered as paths to TypeScript files. + +To prevent command line buffer overflow response file may be used. Its name is set by adding '@' prefix to file name +( for example: 'tslinter.sh @responce.file.txt' ). +Response file should contain TypeScript source paths (one at each line). +In case of using responce file no other arguments except options take effect. + +Work results are printed to stdout and may be redirected to file. + + + +## Running tests +All tests are located under the test folder in linter subfolder. + + +To run all tests, run **ant test_linter** on the command line. diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 62aedf7cd..56a4ac6bf 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -906,8 +906,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // if constructor already has 'throws' clause - do nothing // else check thrown exceptions set for init blocks - if ((stsCtorDecl.Identifier() == null) && !stsInitThrownExceptions.isEmpty()) - stsCtorDecl.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + if ((stsCtorDecl.throwsAnnotation() == null) && !stsInitThrownExceptions.isEmpty()) + stsCtorDecl.addChild(NodeBuilder.throwsAnnotation(true)); } } @@ -923,7 +923,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(new ConstructorBodyContext(stsCurrent, 0)).setParent(stsCurrent); if( !stsInitThrownExceptions.isEmpty() ) - stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + stsCurrent.addChild(NodeBuilder.throwsAnnotation(true)); popCurrent(); // stsDefaultCtor popCurrent(); // ClassMemberContext @@ -2067,9 +2067,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } if( !javaMethodExceptionSet.isEmpty() || !currentExceptionsSet(javaMethodDeclaration).isEmpty()) { if( javaMethodDeclaration.isConstructor() ) - stsConstructor.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + stsConstructor.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsConstructor); else if (stsSignature != null) - stsSignature.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + stsSignature.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsSignature); } popExceptionSet(); // remove thrown exception set for current method @@ -4290,6 +4290,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation()).setParent(stsCurrent); } + if (!currentExceptionsSet(javaLambdaExpr).isEmpty()) + stsCurrent.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); pushCurrent(new LambdaBodyContext(stsCurrent, 0)); @@ -4349,6 +4352,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { : javaMethodBinding.getReturnType(); translateTypeBinding(returnType, javaMethodRef); + if (javaMethodBinding.getExceptionTypes().length > 0) + stsCurrent.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); // Create lambda body. It consists of the method reference call. @@ -4774,16 +4780,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // // STS AST: // tryStatement - // : Try block catchOrRecoverClause+ + // : Try block (catchClause+ | catchClause* defaultCatch) // ; // - // catchOrRecoverClause - // : (Catch | Recover) exceptionParameter? block + // catchClause + // : Catch exceptionParameter block // ; // // exceptionParameter // : OpenParen Identifier typeAnnotation CloseParen // ; + // + // defaultCatch + // : Catch (OpenParen Identifier CloseParen)? block + // @Override public boolean visit(TryStatement javaTryStatement) { List javaCatchClauses = javaTryStatement.catchClauses(); @@ -4853,11 +4863,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (javaExceptionType.isUnionType()) { List javaExcTypes = ((UnionType)javaExceptionType).types(); for (Type javaExcType : javaExcTypes) { - createCatchOrRecoverClause(javaExcType, javaExceptionName, javaCatchBody); + createCatchClause(javaExcType, javaExceptionName, javaCatchBody); } } else { - createCatchOrRecoverClause(javaExceptionType, javaExceptionName, javaCatchBody); + createCatchClause(javaExceptionType, javaExceptionName, javaCatchBody); } } @@ -4876,17 +4886,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - private void createCatchOrRecoverClause(Type javaExceptionType, - SimpleName javaExceptionName, - Block javaClauseBody) { - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); + private void createCatchClause(Type javaExceptionType, + SimpleName javaExceptionName, + Block javaClauseBody) { + pushCurrent(new CatchClauseContext(stsCurrent,0)); - // Emit 'recover' keyword instead of 'catch' if - // exception type is a subtype of RuntimeException. ITypeBinding javaExcTypeBinding = NodeBuilder.getTypeBinding(javaExceptionType); - String stsKeyword = isRuntimeExceptionType(javaExcTypeBinding) ? - StaticTSParser.RECOVER : StaticTSParser.CATCH; - stsCurrent.addChild(NodeBuilder.terminalIdentifier(stsKeyword)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.CATCH)); pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaExceptionName)); @@ -4911,7 +4917,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { translateBlockStatements(javaClauseBody); popCurrent(); // BlockContext - popCurrent(); // CatchOrRecoverClauseContext + popCurrent(); // CatchClauseContext } private boolean isRuntimeExceptionType(ITypeBinding javaExcType) { return isValidExceptionType(javaExcType) && @@ -5088,21 +5094,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // DeferStatementContext popCurrent(); // BlockContext - emitCatchOrRecoverClauseForResourceAllocation(primaryExceptionVarName, true); - emitCatchOrRecoverClauseForResourceAllocation(primaryExceptionVarName, false); + emitCatchClauseForResourceAllocation(primaryExceptionVarName); popStatement(); // TryStatementContext stsCurrentTryStatement.push(stsTryStmt); } - private void emitCatchOrRecoverClauseForResourceAllocation(String primaryExceptionVarName, boolean isCatchClause) { + private void emitCatchClauseForResourceAllocation(String primaryExceptionVarName) { // catch (Throwable #t) { // #primaryExc = #t; // throw #t; // } - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent, 0)); - String stsKeyword = isCatchClause ? StaticTSParser.CATCH : StaticTSParser.RECOVER; - stsCurrent.addChild(NodeBuilder.terminalIdentifier(stsKeyword)); + pushCurrent(new CatchClauseContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.CATCH)); pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier("t")); stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); @@ -5123,7 +5127,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // ThrowStatementContext popCurrent(); // BlockContext - popCurrent(); // CatchOrRecoverClauseContext + popCurrent(); // CatchClauseContext } private void emitTryStmtForResourceDisposal(Expression javaResourceName, String primaryExceptionVarName) { // try { #resource.close(); } catch {..} @@ -5142,16 +5146,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CallExpressionContext popStatement(); // ExpressionStatementContext popCurrent(); // BlockContext - emitCatchOrRecoverClauseForResourceDisposal(primaryExceptionVarName, true); - emitCatchOrRecoverClauseForResourceDisposal(primaryExceptionVarName, false); + emitCatchClauseForResourceDisposal(primaryExceptionVarName); popStatement(); // TryStatementContext } - private void emitCatchOrRecoverClauseForResourceDisposal(String primaryExceptionVarName, boolean isCatchClause) { + private void emitCatchClauseForResourceDisposal(String primaryExceptionVarName) { // catch (Throwable #suppressedExc) { #primaryExc.addSuppressed(#suppressedExc); } - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent, 0)); - String stsKeyword = isCatchClause ? StaticTSParser.CATCH : StaticTSParser.RECOVER; - stsCurrent.addChild(NodeBuilder.terminalIdentifier(stsKeyword)); + pushCurrent(new CatchClauseContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.CATCH)); pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier("suppressedExc")); stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); @@ -5172,22 +5174,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CallExpressionContext popStatement(); // ExpressionStatementContext popCurrent(); // BlockContext - popCurrent(); // CatchOrRecoverClauseContext + popCurrent(); // CatchClauseContext } @Override public boolean visit(ThrowStatement javaThrowStatement) { Expression exceptionExpr = javaThrowStatement.getExpression(); - if( isRuntimeExceptionType(exceptionExpr.resolveTypeBinding()) ) { - pushStatement(new PanicStatementContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Panic)); - } else { - pushStatement(new ThrowStatementContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throw)); - if(checkThrownExceptionSet(javaThrowStatement)) - addThrownException(exceptionExpr.resolveTypeBinding()); - } + pushStatement(new ThrowStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throw)); + if(checkThrownExceptionSet(javaThrowStatement)) + addThrownException(exceptionExpr.resolveTypeBinding()); + exceptionExpr.accept(this); popStatement(); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java index 698cfcabd..557f91f32 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java @@ -304,6 +304,13 @@ public class NodeBuilderBase { return typeAnnotation(stsTypeRef); } + public static ThrowsAnnotationContext throwsAnnotation(boolean isThrows) { + ThrowsAnnotationContext stsThrowsAnno = new ThrowsAnnotationContext(null, 0); + stsThrowsAnno.addChild(terminalIdentifier(isThrows ? StaticTSParser.THROWS : StaticTSParser.RETHROWS)); + + return stsThrowsAnno; + } + public static ParameterContext parameter(String stsParamName, String stsParamType) { ParameterContext stsParam = new ParameterContext(null, 0); stsParam.addChild(terminalIdentifier(stsParamName)); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java b/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java index ba254fbac..ce85006fe 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java @@ -171,14 +171,20 @@ public class NodeClonner { TypeAnnotationContext srcTypeAnnot = srcFunType.typeAnnotation(); cloneFunType.addChild(clone(srcTypeAnnot)).setParent(cloneFunType); - TerminalNode srcIdentifier = srcFunType.Identifier(); - if (srcIdentifier != null) { - cloneFunType.addChild(NodeBuilder.terminalIdentifier(srcIdentifier.getText())); - } + ThrowsAnnotationContext srcThrowsAnno = srcFunType.throwsAnnotation(); + if (srcThrowsAnno != null) cloneFunType.addChild(clone(srcThrowsAnno)).setParent(cloneFunType); return cloneFunType; } + static public ThrowsAnnotationContext clone(ThrowsAnnotationContext srcThowsAnno) { + ThrowsAnnotationContext cloneThrowsAnno = new ThrowsAnnotationContext(null, 0); + + TerminalNode srcIdentifier = srcThowsAnno.Identifier(); + cloneThrowsAnno.addChild(NodeBuilder.terminalIdentifier(srcIdentifier.getText())); + + return cloneThrowsAnno; + } // primaryType // : predefinedType @@ -531,15 +537,7 @@ public class NodeClonner { cloneSwitch.addChild(clone(srcSwitch.caseBlock())).setParent(cloneSwitch); return cloneSwitch; } - - // panicStatement: Panic {this.notLineTerminator()}? singleExpression SemiColon - static public PanicStatementContext clone(PanicStatementContext srcPanic) { - PanicStatementContext clonePanic = new PanicStatementContext(null, 0); - clonePanic.addChild(NodeBuilder.terminalNode(Panic)); - clonePanic.addChild(clone(srcPanic.singleExpression())).setParent(clonePanic); - return clonePanic; - } - + // throwStatement: Throw {this.notLineTerminator()}? singleExpression SemiColon static public ThrowStatementContext clone(ThrowStatementContext srcThrow) { ThrowStatementContext cloneThrow = new ThrowStatementContext(null, 0); @@ -566,31 +564,30 @@ public class NodeClonner { return cloneExceptionParam; } - // catchOrRecoverClause: { CATCH || RECOVER }? Identifier exceptionParameter? block - static public CatchOrRecoverClauseContext clone(CatchOrRecoverClauseContext srcCatchOrRecover) { - CatchOrRecoverClauseContext cloneCatchOrRecover = new CatchOrRecoverClauseContext(null, 0); + // catchClause: CATCH exceptionParameter block + static public CatchClauseContext clone(CatchClauseContext srcCatch) { + CatchClauseContext cloneCatch = new CatchClauseContext(null, 0); - cloneCatchOrRecover.addChild(NodeBuilder.terminalIdentifier(srcCatchOrRecover.Identifier().getText())); + cloneCatch.addChild(NodeBuilder.terminalIdentifier(srcCatch.Identifier().getText())); - ExceptionParameterContext srcExeptionParam = srcCatchOrRecover.exceptionParameter(); + ExceptionParameterContext srcExeptionParam = srcCatch.exceptionParameter(); if (srcExeptionParam != null) { - cloneCatchOrRecover.addChild(clone(srcExeptionParam)).setParent(cloneCatchOrRecover); + cloneCatch.addChild(clone(srcExeptionParam)).setParent(cloneCatch); } - cloneCatchOrRecover.addChild(clone(srcCatchOrRecover.block())).setParent(cloneCatchOrRecover); + cloneCatch.addChild(clone(srcCatch.block())).setParent(cloneCatch); - return cloneCatchOrRecover; + return cloneCatch; } - // trapStatement: Trap block catchOrRecoverClause+ - // tryStatement: Try block catchOrRecoverClause+ + // tryStatement: Try block (catchClause+ | catchClause* defaultCatch) static public TryStatementContext clone(TryStatementContext srcTry) { TryStatementContext cloneTry = new TryStatementContext(null, 0); cloneTry.addChild(NodeBuilder.terminalNode(Try)); cloneTry.addChild(clone(srcTry.block())).setParent(cloneTry); - for (CatchOrRecoverClauseContext srcCatchOrRecover : srcTry.catchOrRecoverClause()) { - cloneTry.addChild(clone(srcCatchOrRecover)).setParent(cloneTry); + for (CatchClauseContext srcCatch : srcTry.catchClause()) { + cloneTry.addChild(clone(srcCatch)).setParent(cloneTry); } return cloneTry; @@ -613,10 +610,9 @@ public class NodeClonner { // | returnStatement // | labelledStatement // | switchStatement - // | panicStatement // | throwStatement // | deferStatement - // | trapStatement + // | tryStatement // | expressionStatement static public StatementContext clone(StatementContext srcStmt) { StatementContext cloneStmt = new StatementContext(null, 0); @@ -675,12 +671,6 @@ public class NodeClonner { return cloneStmt; } - PanicStatementContext srcPanic = srcStmt.panicStatement(); - if (srcPanic != null) { - cloneStmt.addChild(clone(srcPanic)).setParent(cloneStmt); - return cloneStmt; - } - ThrowStatementContext srcThrow = srcStmt.throwStatement(); if (srcThrow != null) { cloneStmt.addChild(clone(srcThrow)).setParent(cloneStmt); @@ -963,9 +953,9 @@ public class NodeClonner { cloneConstructor.addChild(clone(srcParamsList)).setParent(cloneConstructor); } - TerminalNode srcThrows = srcConstructor.Identifier(); - if (srcThrows != null) { - cloneConstructor.addChild(NodeBuilder.terminalIdentifier(srcThrows.getText())); + ThrowsAnnotationContext srcThrowsAnno = srcConstructor.throwsAnnotation(); + if (srcThrowsAnno != null) { + cloneConstructor.addChild(clone(srcThrowsAnno)).setParent(cloneConstructor); } ConstructorBodyContext srcConstBody = srcConstructor.constructorBody(); @@ -1063,9 +1053,9 @@ public class NodeClonner { cloneSignature.addChild(clone(srcSignature.typeAnnotation())).setParent(cloneSignature); - TerminalNode srcIdentifier = srcSignature.Identifier(); - if (srcIdentifier != null) { - cloneSignature.addChild(NodeBuilder.terminalIdentifier(srcIdentifier.getText())); + ThrowsAnnotationContext srcThrowsAnno = srcSignature.throwsAnnotation(); + if (srcThrowsAnno != null) { + cloneSignature.addChild(clone(srcThrowsAnno)).setParent(cloneSignature); } return cloneSignature; @@ -1532,6 +1522,10 @@ public class NodeClonner { } cloneLambda.addChild(clone(srcLambda.typeAnnotation())).setParent(cloneLambda); + + ThrowsAnnotationContext srcThrowsAnno = srcLambda.throwsAnnotation(); + if (srcThrowsAnno != null) cloneLambda.addChild(clone(srcThrowsAnno)).setParent(cloneLambda); + cloneLambda.addChild(clone(srcLambda.lambdaBody())).setParent(cloneLambda); return cloneLambda; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index 9365d52c5..2b62e1ee9 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -121,8 +121,7 @@ classMember ; constructorDeclaration - : Constructor typeParameters? OpenParen parameterList? CloseParen - ({ this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier)? constructorBody + : Constructor typeParameters? OpenParen parameterList? CloseParen throwsAnnotation? constructorBody ; parameterList @@ -178,8 +177,11 @@ classInitializer ; signature - : typeParameters? OpenParen parameterList? CloseParen typeAnnotation - ({ this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier)? + : typeParameters? OpenParen parameterList? CloseParen typeAnnotation throwsAnnotation? + ; + +throwsAnnotation + : { this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier ; // Interfaces @@ -283,8 +285,7 @@ typeReferencePart ; functionType - : OpenParen parameterList? CloseParen typeAnnotation - ({ this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier)? + : OpenParen parameterList? CloseParen typeAnnotation throwsAnnotation? ; // Generics @@ -335,7 +336,6 @@ statement | returnStatement | labelledStatement | switchStatement - | panicStatement | throwStatement | deferStatement | tryStatement @@ -402,27 +402,26 @@ defaultClause : { this.next(StaticTSParser.DEFAULT) }? Identifier ':' statement* ; -panicStatement - : Panic {this.notLineTerminator()}? singleExpression SemiColon? - ; - throwStatement : Throw {this.notLineTerminator()}? singleExpression SemiColon? ; tryStatement - : Try block catchOrRecoverClause+ + : Try block (catchClause+ | catchClause* defaultCatch) ; -catchOrRecoverClause - : { this.next(StaticTSParser.CATCH) || this.next(StaticTSParser.RECOVER) }? Identifier - exceptionParameter? block +catchClause + : { this.next(StaticTSParser.CATCH) }? Identifier exceptionParameter block ; exceptionParameter : OpenParen Identifier typeAnnotation CloseParen ; +defaultCatch + : { this.next(StaticTSParser.CATCH) }? Identifier (OpenParen Identifier CloseParen)? block + ; + deferStatement : Defer statement ; @@ -433,7 +432,7 @@ expressionStatement // Expressions singleExpression - : OpenParen parameterList? CloseParen typeAnnotation Arrow lambdaBody # LambdaExpression + : OpenParen parameterList? CloseParen typeAnnotation throwsAnnotation? Arrow lambdaBody # LambdaExpression | singleExpression indexExpression # ArrayAccessExpression | singleExpression Dot Identifier # MemberAccessExpression | New typeArguments? typeReference arguments? classBody? # NewClassInstanceExpression diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index c0c439c81..433579056 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -471,6 +471,9 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { TypeAnnotationContext stsTypeAnno = stsFunctionType.typeAnnotation(); visitTypeAnnotation(stsTypeAnno); + ThrowsAnnotationContext stsThrowsAnno = stsFunctionType.throwsAnnotation(); + if (stsThrowsAnno != null) visitThrowsAnnotation(stsThrowsAnno); + writeTrailingComments(stsFunctionType); return null; } @@ -513,24 +516,31 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitTypeAnnotation(stsSignature.typeAnnotation()); - TerminalNode stsThrowsIdentifier = stsSignature.Identifier(); - if (stsThrowsIdentifier != null) { - String stsThrowsIdText = stsThrowsIdentifier.getText(); - if (StaticTSParser.THROWS.equals(stsThrowsIdText) || - StaticTSParser.RETHROWS.equals(stsThrowsIdText)) { - sb.append(' ').append(stsThrowsIdText).append(' '); + ThrowsAnnotationContext stsThrowsAnno = stsSignature.throwsAnnotation(); + if (stsThrowsAnno != null) visitThrowsAnnotation(stsThrowsAnno); + + writeTrailingComments(stsSignature); + return null; + } + + @Override + public Void visitThrowsAnnotation(ThrowsAnnotationContext stsThrowsAnno) { + TerminalNode stsIdentifier = stsThrowsAnno.Identifier(); + if (stsIdentifier != null) { + String stsIdentifierText = stsIdentifier.getText(); + if (StaticTSParser.THROWS.equals(stsIdentifierText) || + StaticTSParser.RETHROWS.equals(stsIdentifierText)) { + sb.append(' ').append(stsIdentifierText).append(' '); } else { - reportError("Unexpected token " + stsThrowsIdText + - " in function or method signature", stsSignature); + reportError("Unexpected token " + stsIdentifierText + + " in throws/rethrows annotation", stsThrowsAnno); } } - writeTrailingComments(stsSignature); return null; } - // accessibilityModifier: Public | Private | Protected @Override public Void visitAccessibilityModifier(AccessibilityModifierContext stsAccessibilityModifier) { @@ -565,20 +575,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { sb.append(')'); - TerminalNode stsThrowsIdentifier = stsConstructorDeclaration.Identifier(); - if (stsThrowsIdentifier != null) { - String stsThrowsIdText = stsThrowsIdentifier.getText(); - if (StaticTSParser.THROWS.equals(stsThrowsIdText) || - StaticTSParser.RETHROWS.equals(stsThrowsIdText)) { - sb.append(' ').append(stsThrowsIdText); - } - else { - reportError("Unexpected token " + stsThrowsIdText + - " in constructor declaration", stsConstructorDeclaration); - } - } + ThrowsAnnotationContext stsThrowsAnno = stsConstructorDeclaration.throwsAnnotation(); + if (stsThrowsAnno != null) + visitThrowsAnnotation(stsThrowsAnno); + else + sb.append(' '); - sb.append(" {\n"); + sb.append("{\n"); indentIncrement(); visitConstructorBody(stsConstructorDeclaration.constructorBody()); @@ -1540,19 +1543,6 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - @Override - public Void visitPanicStatement(PanicStatementContext stsPanicStatement) { - doNeededIndent(); - writeLeadingComments(stsPanicStatement); - - sb.append(stsPanicStatement.Panic().getText()).append(' '); - stsPanicStatement.singleExpression().accept(this); - sb.append(";\n"); - - writeTrailingComments(stsPanicStatement); - return null; - } - // tryStatement: Try block catchOrRecoverClause+; @Override public Void visitTryStatement(TryStatementContext stsTryStatement) { @@ -1563,12 +1553,16 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitBlock(stsTryStatement.block()); - List stsCatchesOrRecovers = stsTryStatement.catchOrRecoverClause(); - assert(stsCatchesOrRecovers != null && !stsCatchesOrRecovers.isEmpty()); - for (CatchOrRecoverClauseContext stsCatchOrRecover : stsCatchesOrRecovers) { - visitCatchOrRecoverClause(stsCatchOrRecover); + List stsCatches = stsTryStatement.catchClause(); + if (stsCatches != null) { + for (CatchClauseContext stsCatch : stsCatches) { + visitCatchClause(stsCatch); + } } + DefaultCatchContext stsDefaultCatch = stsTryStatement.defaultCatch(); + if (stsDefaultCatch != null) visitDefaultCatch(stsDefaultCatch); + sb.append('\n'); writeTrailingComments(stsTryStatement); @@ -1578,28 +1572,27 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // catchOrRecoverClause: (Catch|Recover) exceptionParameter? block @Override - public Void visitCatchOrRecoverClause(CatchOrRecoverClauseContext stsCatchOrRecoverClause) { + public Void visitCatchClause(CatchClauseContext stsCatchClause) { doNeededIndent(); - writeLeadingComments(stsCatchOrRecoverClause); + writeLeadingComments(stsCatchClause); - String stsCatchOrRecoverKeyword = stsCatchOrRecoverClause.Identifier().getText(); - if (!StaticTSParser.CATCH.equals(stsCatchOrRecoverKeyword) && - !StaticTSParser.RECOVER.equals(stsCatchOrRecoverKeyword)) { - reportError("Unexpected keyword " + stsCatchOrRecoverKeyword + " in catch or recover clause", stsCatchOrRecoverClause); - stsCatchOrRecoverKeyword = StaticTSParser.CATCH; + String stsCatchKeyword = stsCatchClause.Identifier().getText(); + if (!StaticTSParser.CATCH.equals(stsCatchKeyword)) { + reportError("Unexpected keyword " + stsCatchKeyword + " in catch clause", stsCatchClause); + stsCatchKeyword = StaticTSParser.CATCH; } - sb.append(stsCatchOrRecoverKeyword).append(' '); + sb.append(stsCatchKeyword).append(' '); - ExceptionParameterContext stsExceptionParam = stsCatchOrRecoverClause.exceptionParameter(); + ExceptionParameterContext stsExceptionParam = stsCatchClause.exceptionParameter(); if (stsExceptionParam != null) { visitExceptionParameter(stsExceptionParam); } - BlockContext stsBlock = stsCatchOrRecoverClause.block(); + BlockContext stsBlock = stsCatchClause.block(); assert(stsBlock != null); visitBlock(stsBlock); - writeTrailingComments(stsCatchOrRecoverClause); + writeTrailingComments(stsCatchClause); return null; } @@ -1615,6 +1608,27 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } + @Override + public Void visitDefaultCatch(DefaultCatchContext stsDefaultCatch) { + doNeededIndent(); + writeLeadingComments(stsDefaultCatch); + + String stsCatchKeyword = stsDefaultCatch.Identifier(0).getText(); + if (!StaticTSParser.CATCH.equals(stsCatchKeyword)) { + reportError("Unexpected keyword " + stsCatchKeyword + " in default catch clause", stsDefaultCatch); + stsCatchKeyword = StaticTSParser.CATCH; + } + sb.append(stsCatchKeyword).append(' '); + + if (stsDefaultCatch.Identifier().size() > 1) + sb.append('(').append(stsDefaultCatch.Identifier(1).getText()).append(") "); + + visitBlock(stsDefaultCatch.block()); + + writeTrailingComments(stsDefaultCatch); + return null; + } + // functionDeclaration: Function Identifier signature block @Override public Void visitFunctionDeclaration(FunctionDeclarationContext stsFunctionDeclaration) { @@ -2407,6 +2421,9 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitTypeAnnotation(stsLambdaExpression.typeAnnotation()); + ThrowsAnnotationContext stsThrowsAnno = stsLambdaExpression.throwsAnnotation(); + if (stsThrowsAnno != null) visitThrowsAnnotation(stsThrowsAnno); + sb.append(stsLambdaExpression.Arrow().getText()); visitLambdaBody(stsLambdaExpression.lambdaBody()); diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index c89ba32e8..94ae246cd 100755 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -23,7 +23,7 @@ open class SuperClass { open class SubClass1 extends SuperClass { override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { @@ -40,7 +40,7 @@ interface SuperInterface { open class SubClass2 implements SuperInterface { public override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } open tweak(): void { SuperInterface.super.foo(); // Gets the 'println' behavior @@ -49,7 +49,7 @@ open class SubClass2 implements SuperInterface { open class SubClass3 implements SuperInterface { public override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { diff --git a/migrator/test/java/method_references.java.sts b/migrator/test/java/method_references.java.sts index 0113235e2..ffd88a63d 100644 --- a/migrator/test/java/method_references.java.sts +++ b/migrator/test/java/method_references.java.sts @@ -247,9 +247,9 @@ open class MethodReferencesExamples { public static methodReferencesWithExceptions(): void { try { - let createExceptions : TryFunction0 = (): com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions => new Exceptions(); + let createExceptions : TryFunction0 = (): com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions throws => new Exceptions(); let exceptions : Exceptions = createExceptions.apply(); - let getNameFun : TryFunction1 = (__migrator_lambda_param_1 : com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions): String => __migrator_lambda_param_1.getName(); + let getNameFun : TryFunction1 = (__migrator_lambda_param_1 : com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions): String throws => __migrator_lambda_param_1.getName(); let name : String = getNameFun.apply(exceptions); } catch (ex : MyException) { diff --git a/migrator/test/java/throw_statement.java.sts b/migrator/test/java/throw_statement.java.sts index 07c5d348a..2889cc5ce 100644 --- a/migrator/test/java/throw_statement.java.sts +++ b/migrator/test/java/throw_statement.java.sts @@ -25,7 +25,7 @@ export open class throw_statement { return i / j; } public open divide_test(l : long): int { - if (l > i) panic new Panic(); + if (l > i) throw new Panic(); return (i / l) as int; } } diff --git a/migrator/test/java/throws_test.java b/migrator/test/java/throws_test.java index baaaf0b45..b832b4564 100644 --- a/migrator/test/java/throws_test.java +++ b/migrator/test/java/throws_test.java @@ -80,7 +80,7 @@ class Test { catch( MyException e ) {} } - // no throws - all excepyions are catched + // no throws - all exceptions are catched public static void test3(String s) { try { SubClass1 sc1 = new SubClass1(s); @@ -88,7 +88,7 @@ class Test { catch( MyException | AnotherException e) {} } - // no throws - only panic + // no throws - only runtime exceptions public static void test4(String s) { try { SubClass2 sc2 = new SubClass2(s); @@ -96,7 +96,7 @@ class Test { catch( MyException | AnotherException e) {} } - // no throws - only panic + // no throws - only runtime exceptions public static void test5(String s) { try { SubClass2 sc2 = new SubClass2(s); diff --git a/migrator/test/java/throws_test.java.sts b/migrator/test/java/throws_test.java.sts index ebb49104d..36e494c5a 100644 --- a/migrator/test/java/throws_test.java.sts +++ b/migrator/test/java/throws_test.java.sts @@ -47,7 +47,7 @@ open class SubClass1 extends SuperClass { } override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } public open run(): void { foo(); @@ -60,7 +60,7 @@ open class SubClass1 extends SuperClass { open class SubClass2 extends SubClass1 { public constructor(s : String) throws { super(s); - if (s == "!") panic new UnsupportedOperationException(); + if (s == "!") throw new UnsupportedOperationException(); } public override foo(): void { @@ -90,7 +90,7 @@ open class Test { } } -// no throws - all excepyions are catched +// no throws - all exceptions are catched public static test3(s : String): void { try { let sc1 : SubClass1 = new SubClass1(s); @@ -101,7 +101,7 @@ open class Test { } } -// no throws - only panic +// no throws - only runtime exceptions public static test4(s : String): void { try { let sc2 : SubClass2 = new SubClass2(s); @@ -112,7 +112,7 @@ open class Test { } } -// no throws - only panic +// no throws - only runtime exceptions public static test5(s : String): void { try { let sc2 : SubClass2 = new SubClass2(s); diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts index cde0c182a..5a589a38e 100644 --- a/migrator/test/java/try_catch_finally.java.sts +++ b/migrator/test/java/try_catch_finally.java.sts @@ -51,16 +51,16 @@ export open class try_catch_finally { blowUp(); let t : try_catch_finally = new try_catch_finally(); } - recover (n : NullPointerException) { + catch (n : NullPointerException) { System.out.println("Caught NullPointerException"); } catch (b : BlewIt) { System.out.println("Caught BlewIt or IllegalArgumentException"); } - recover (b : IllegalArgumentException) { + catch (b : IllegalArgumentException) { System.out.println("Caught BlewIt or IllegalArgumentException"); } - recover (r : RuntimeException) { + catch (r : RuntimeException) { System.out.println("Caught RuntimeException"); } catch (e : Exception) { diff --git a/migrator/test/java/try_with_resources.java.sts b/migrator/test/java/try_with_resources.java.sts index f0fa4fb1c..e37cc96ec 100644 --- a/migrator/test/java/try_with_resources.java.sts +++ b/migrator/test/java/try_with_resources.java.sts @@ -40,10 +40,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { fr.close(); @@ -60,10 +56,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { br.close(); @@ -75,21 +67,11 @@ open class TryWithResources { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } } // with catch block @@ -107,10 +89,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { stmt.close(); @@ -126,11 +104,6 @@ open class TryWithResources { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } catch (e : SQLException) { System.err.println("SQLState: " + e.getSQLState()); @@ -158,10 +131,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { fr.close(); @@ -178,10 +147,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { br.close(); @@ -193,21 +158,11 @@ open class TryWithResources { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } } // with catch and finally block @@ -227,10 +182,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { scanner.close(); @@ -245,11 +196,6 @@ open class TryWithResources { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } catch (fnfe : FileNotFoundException) { fnfe.printStackTrace(); @@ -272,9 +218,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } } else { @@ -291,10 +234,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { writer.close(); @@ -310,21 +249,11 @@ open class TryWithResources { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } } catch (ex : Exception) { @@ -352,10 +281,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { this.y2.close(); @@ -371,10 +296,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { super.yz.close(); @@ -391,10 +312,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res2.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res2.addSuppressed(suppressedExc); - } - } else { z.yz.close(); @@ -406,32 +323,17 @@ open class TryWithResources { primaryExc_res2 = t; throw t; } - recover (t : Throwable) { - primaryExc_res2 = t; - throw t; - } - } } catch (t : Throwable) { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } catch (e : IOException) { System.err.println(e.getMessage()); diff --git a/migrator/test/ts/throw_statement.ts b/migrator/test/ts/throw_statement.ts new file mode 100644 index 000000000..e47a2a73f --- /dev/null +++ b/migrator/test/ts/throw_statement.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +class C {} + +function throwsNumber(): never { + throw 1; +} + +function throwsString(): never { + throw "string"; +} + +function throwsObject(): never { + let c = new C; + throw c; +} + +function throwsError(): never { + throw new Error("error"); +} diff --git a/migrator/test/ts/throw_statement.ts.sts b/migrator/test/ts/throw_statement.ts.sts new file mode 100755 index 000000000..bd825a9c8 --- /dev/null +++ b/migrator/test/ts/throw_statement.ts.sts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +open class C { +} + +function throwsNumber(): Never { + throw new Error("", 1); +} +function throwsString(): Never { + throw new Error("", "string"); +} +function throwsObject(): Never { + let c = new C(); + throw new Error("", c); +} +function throwsError(): Never { + throw new Error("", new __UnknownType__ /* Error */("error")); +} diff --git a/migrator/test/ts/try_statement.ts b/migrator/test/ts/try_statement.ts new file mode 100644 index 000000000..2d0b3c895 --- /dev/null +++ b/migrator/test/ts/try_statement.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +class C { } + +function foo() : never { + throw new C; +} + +function bar(): void { + try { + foo(); + } + catch { + } + + try { + foo(); + } + catch (e) { + console.log(e); + } + finally { + } + + try { + foo(); + } + finally { + } +} diff --git a/migrator/test/ts/try_statement.ts.sts b/migrator/test/ts/try_statement.ts.sts new file mode 100755 index 000000000..779ff4bc4 --- /dev/null +++ b/migrator/test/ts/try_statement.ts.sts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +open class C { +} + +function foo(): Never { + throw new Error("", new C()); +} +function bar(): void { + try { + foo(); + } + catch { + } + + try { + defer { + } + foo(); + } + catch (e) { + console.log(e); + } + + { + defer { + } + foo(); + } +} diff --git a/migrator/test/ts/unsupported_types.ts.sts b/migrator/test/ts/unsupported_types.ts.sts index 69613e2cd..da14a88d7 100755 --- a/migrator/test/ts/unsupported_types.ts.sts +++ b/migrator/test/ts/unsupported_types.ts.sts @@ -17,7 +17,7 @@ function foo(x : __UnknownType__ /* string|number */): __UnknownType__ /* [strin return null; } function nonreturning(x : __UnknownType__ /* "string" */): Never { - __untranslated_statement( /* throw 1; */); + throw new Error("", 1); } function bar(x : __UnknownType__ /* any */): __UnknownType__ /* undefined */ { return undefined; diff --git a/migrator/tslinter.cmd b/migrator/tslinter.cmd new file mode 100644 index 000000000..b40784b8d --- /dev/null +++ b/migrator/tslinter.cmd @@ -0,0 +1,19 @@ +:: +:: Copyright (c) 2022-2023 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. +:: +@echo off +@set MIGRATOR_HOME_PATH=%~dp0 + + +node %MIGRATOR_HOME_PATH%./out/typescript/javascript/src/linter/dist/tslinter.js %* diff --git a/migrator/tslinter.sh b/migrator/tslinter.sh new file mode 100644 index 000000000..9747f2a44 --- /dev/null +++ b/migrator/tslinter.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# +# Copyright (c) 2022-2023 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. +# + +# get absolute path to migrator folder +MIGRATOR_HOME_PATH=`cd $(dirname $0) && pwd` + +# use relative path due to node.js error under cygwin environment +node $(dirname $0)/./out/typescript/javascript/src/linter/dist/tslinter.js $@ diff --git a/migrator/typescript/src/staticts/NodeCloner.ts b/migrator/typescript/src/staticts/NodeCloner.ts index 22bdeed65..dd6653a9c 100755 --- a/migrator/typescript/src/staticts/NodeCloner.ts +++ b/migrator/typescript/src/staticts/NodeCloner.ts @@ -35,12 +35,19 @@ export function cloneSignature(stsSignature: sts.SignatureContext): sts.Signatur stsSignatureClone.addChild(cloneTypeAnnotation(stsTypeAnno)); // Clone throws/rethrows keyword, if exists. - let stsIdentifier = stsSignature.Identifier(); - if (stsIdentifier) stsSignatureClone.addAnyChild(NodeBuilder.terminalIdentifier(stsIdentifier.text)); + let stsThrowsAnno = stsSignature.throwsAnnotation(); + if (stsThrowsAnno) stsSignatureClone.addChild(cloneThrowsAnnotation(stsThrowsAnno)); return stsSignatureClone; } +export function cloneThrowsAnnotation(stsThrowsAnno: sts.ThrowsAnnotationContext): sts.ThrowsAnnotationContext { + let stsThrowsAnnoClone = new sts.ThrowsAnnotationContext(undefined, 0); + stsThrowsAnnoClone.addChild(NodeBuilder.terminalIdentifier(stsThrowsAnno.Identifier().text)); + + return stsThrowsAnnoClone; +} + export function cloneTypeParameters(stsTypeParams: sts.TypeParametersContext): sts.TypeParametersContext { let stsTypeParamsClone = new sts.TypeParametersContext(undefined, 0); @@ -297,8 +304,8 @@ export function cloneFunctionType(stsFunctionType: sts.FunctionTypeContext): sts stsFunctionTypeClone.addChild(cloneTypeAnnotation(stsTypeAnno)); // Clone throws/rethrows keyword, if exists. - let stsIdentifier = stsFunctionType.Identifier(); - if (stsIdentifier) stsFunctionTypeClone.addChild(NodeBuilder.terminalIdentifier(stsIdentifier.text)); + let stsThrowsAnno = stsFunctionType.throwsAnnotation(); + if (stsThrowsAnno) stsFunctionTypeClone.addChild(cloneThrowsAnnotation(stsThrowsAnno)); return stsFunctionTypeClone; } \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/NodeBuilder.ts b/migrator/typescript/src/transpiler/NodeBuilder.ts index d9499862d..ef6e52776 100644 --- a/migrator/typescript/src/transpiler/NodeBuilder.ts +++ b/migrator/typescript/src/transpiler/NodeBuilder.ts @@ -771,4 +771,26 @@ export function statementOrLocalDeclaration(stsStmt: StaticTSContextBase): sts.S let stsStmtOrLocalDecl = new sts.StatementOrLocalDeclarationContext(undefined, 0); stsStmtOrLocalDecl.addChild(stsStmt); return stsStmtOrLocalDecl; +} + +export function newClassInstanceExpression(stsType: string | sts.TypeReferenceContext, + ...args: sts.SingleExpressionContext[]): sts.SingleExpressionContext { + if (typeof stsType === 'string') stsType = typeReference(stsType); + + let stsSingeExpr = new sts.SingleExpressionContext(undefined, 0); + let stsNewClassInstExpr = new sts.NewClassInstanceExpressionContext(stsSingeExpr); + + // Add 'new' token and type reference. + stsNewClassInstExpr.addChild(terminalNode(sts.StaticTSParser.New)); + stsNewClassInstExpr.addChild(stsType); + + // Add arguments. + let stsArgs = new sts.ArgumentsContext(stsNewClassInstExpr, 0); + let stsArgList = new sts.ExpressionSequenceContext(stsArgs, 0); + for (let stsArg of args) stsArgList.addChild(stsArg); + stsArgs.addChild(stsArgList); + stsNewClassInstExpr.addChild(stsArgs); + + stsSingeExpr.addChild(stsNewClassInstExpr); + return stsSingeExpr; } \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/TranslationUtils.ts b/migrator/typescript/src/transpiler/TranslationUtils.ts index b49e616c6..092924e91 100644 --- a/migrator/typescript/src/transpiler/TranslationUtils.ts +++ b/migrator/typescript/src/transpiler/TranslationUtils.ts @@ -21,7 +21,10 @@ import * as NodeCloner from "../staticts/NodeCloner"; export function notStatementBlock(tsNode: ts.Node): boolean { return tsNode && tsNode.kind === ts.SyntaxKind.Block && - (ts.isFunctionLike(tsNode.parent) || ts.isClassStaticBlockDeclaration(tsNode.parent)); + (ts.isFunctionLike(tsNode.parent) || + ts.isClassStaticBlockDeclaration(tsNode.parent) || + ts.isTryStatement(tsNode.parent) || + ts.isCatchClause(tsNode.parent)); } export function isAssignmentOperator(tsBinaryOperator: ts.BinaryOperatorToken): boolean { diff --git a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts index 43c1895bd..a5ec6a77d 100644 --- a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts @@ -353,7 +353,10 @@ export class TypeScriptTransformer { [ts.SyntaxKind.ForOfStatement]: this.visitForOfStatement, [ts.SyntaxKind.WhileStatement]: this.visitWhileStatement, [ts.SyntaxKind.DoStatement]: this.visitDoStatement, - [ts.SyntaxKind.SwitchStatement]: this.visitSwitchStatement + [ts.SyntaxKind.SwitchStatement]: this.visitSwitchStatement, + [ts.SyntaxKind.ThrowStatement]: this.visitThrowStatement, + [ts.SyntaxKind.TryStatement]: this.visitTryStatement, + [ts.SyntaxKind.CatchClause]: this.visitCatchClause } visitNode(tsNode: ts.Node): StaticTSContextBase { @@ -614,9 +617,6 @@ export class TypeScriptTransformer { } visitMethodDeclaration(tsMethodDecl: ts.MethodDeclaration): sts.ClassMemberContext { - // TODO: process method's throws/rethrows clause! - let methodHasThrowsClause = false; - let stsClassMember = new sts.ClassMemberContext(undefined, 0); let tsMethodName = tsMethodDecl.name; @@ -666,6 +666,7 @@ export class TypeScriptTransformer { stsClassMethod.addChild(stsSignature); if (tsMethodDecl.body) { + // Translate method body. stsClassMethod.addChild(this.visitNode(tsMethodDecl.body)); } @@ -693,9 +694,6 @@ export class TypeScriptTransformer { return null; } - // TODO: process method's throws/rethrows clause! - let methodHasThrowsClause = false; - let stsClassMember = new sts.ClassMemberContext(undefined, 0); // Set access modifier. In case of no modifier set 'public'. @@ -1052,9 +1050,12 @@ export class TypeScriptTransformer { stsFunDecl.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Function)); stsFunDecl.addChild(NodeBuilder.terminalIdentifier(tsFunName)); - stsFunDecl.addChild(this.translateSignature(tsFunDecl)); + + let stsSignature = this.translateSignature(tsFunDecl); + stsFunDecl.addChild(stsSignature); if (tsFunDecl.body) { + // Translate function body. stsFunDecl.addChild(this.visitNode(tsFunDecl.body)); } else { @@ -2732,11 +2733,12 @@ export class TypeScriptTransformer { let stsSignatureParams = stsSignature.parameterList(); if (stsSignatureParams) stsLambdaExpr.addChild(stsSignatureParams); stsLambdaExpr.addChild(stsSignature.typeAnnotation()); - stsLambdaExpr.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Arrow)); - // Translate body. + // Translate lambda body. let stsLambdaBody = new sts.LambdaBodyContext(stsLambdaExpr, 0); stsLambdaBody.addChild(this.visitNode(tsFunctionExpr.body)); + + stsLambdaExpr.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Arrow)); stsLambdaExpr.addChild(stsLambdaBody); return stsExpr; @@ -2823,6 +2825,96 @@ export class TypeScriptTransformer { this.reportError("Failed to translate class static block: Multiple static blocks", tsClassStaticBlock); return null; } + + visitThrowStatement(tsThrowStmt: ts.ThrowStatement): sts.StatementContext { + let stsThrowStmt = new sts.ThrowStatementContext(undefined, 0); + stsThrowStmt.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Throw)); + + // Translate expression being thrown. + let stsExpr = this.visitNode(tsThrowStmt.expression); + if (!stsExpr) stsExpr = this.reportUntranslatedExpression(tsThrowStmt.expression); + + // Wrap expression in Error object, i.e.: + // throw expr --> throw new Error("", expr) + let stsError = NodeBuilder.newClassInstanceExpression("Error", + NodeBuilder.stringLiteral("''"), stsExpr); + stsThrowStmt.addChild(stsError); + + this.stmtTransformed.add(tsThrowStmt); + return NodeBuilder.statement(stsThrowStmt); + } + + visitTryStatement(tsTryStmt: ts.TryStatement): sts.StatementContext { + // Translate try block first as we may have to emit it alone + // in case there are no catch clauses in this try statement. + let stsTryBlock = this.visitNode(tsTryStmt.tryBlock); + + let stsResultStmt: StaticTSContextBase; + if (tsTryStmt.catchClause) { + stsResultStmt = new sts.TryStatementContext(undefined, 0); + stsResultStmt.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Try)); + stsResultStmt.addChild(stsTryBlock); + + // Translate catch clause. + let stsCatch = this.visitNode(tsTryStmt.catchClause); + stsResultStmt.addChild(stsCatch); + } + else { + // If there are no catch clauses, emit the try block alone. + // The finally clause must be present in this case - it will be + // translated as defer statement and added to the try block below. + stsResultStmt = stsTryBlock; + } + + // Translate finally block, if exists. + // Add it as defer statement to try block. + if (tsTryStmt.finallyBlock) { + let stsDeferStmt = new sts.DeferStatementContext(stsTryBlock, 0); + stsDeferStmt.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Defer)); + + let stsFinallyBlock = this.visitNode(tsTryStmt.finallyBlock); + stsDeferStmt.addChild(NodeBuilder.statement(stsFinallyBlock)); + + let stsDeferStmtOrLocalDecl = NodeBuilder.statementOrLocalDeclaration( + NodeBuilder.statement(stsDeferStmt)); + stsDeferStmtOrLocalDecl.setParent(stsTryBlock); + stsTryBlock.children.splice(0, 0, stsDeferStmtOrLocalDecl); + } + + this.stmtTransformed.add(tsTryStmt); + return NodeBuilder.statement(stsResultStmt); + } + + visitCatchClause(tsCatch: ts.CatchClause): sts.DefaultCatchContext { + let stsCatch = new sts.DefaultCatchContext(undefined, 0); + stsCatch.addChild(NodeBuilder.terminalIdentifier(sts.StaticTSParser.CATCH)); + + // Translate block first, in case we'll need + // to add a comment to it later (see below). + let stsCatchBlock = this.visitNode(tsCatch.block); + + // Translate exception name. + if (tsCatch.variableDeclaration) { + let tsExceptionName = tsCatch.variableDeclaration.name; + + if (ts.isIdentifier(tsExceptionName)) { + stsCatch.addChild(NodeBuilder.terminalIdentifier(tsExceptionName)); + } + else { + // Warn and emit __InvalidName__. + this.reportError("Failed to translate exception name in catch clause", tsCatch); + stsCatch.addChild(NodeBuilder.invalidIdentifier()); + + // Add comment with original syntax to catch block. + let stsComment = NodeBuilder.multiLineComment("/* Original exception name: " + + tsExceptionName.getText() + " */"); + stsCatchBlock.addLeadingComment(stsComment); + } + } + + stsCatch.addChild(stsCatchBlock); + return stsCatch; + } reportUntranslatedType(tsTypeNode: ts.TypeNode | ts.Expression, typeKind?: string): sts.TypeReferenceContext { // Warn and emit __UnknownType__. -- Gitee