From 787b8f72c5f184214b3c605d1e8076507c23a29f Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Sun, 5 Oct 2014 10:20:48 +0400 Subject: [PATCH] JS backend: fix KT-5603 (Multiple catch): support for multiply catch clauses --- .../dart/compiler/backend/js/ast/JsTry.java | 8 ++ .../expression/ExpressionVisitor.java | 3 +- .../translate/expression/TryTranslator.java | 100 ---------------- .../translate/expression/tryTranslator.kt | 111 ++++++++++++++++++ 4 files changed, 121 insertions(+), 101 deletions(-) delete mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/expression/TryTranslator.java create mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/expression/tryTranslator.kt diff --git a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsTry.java b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsTry.java index 7c9610304fa..c5cc847218b 100644 --- a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsTry.java +++ b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsTry.java @@ -29,6 +29,14 @@ public class JsTry extends SourceInfoAwareJsNode implements JsStatement { this.finallyBlock = finallyBlock; } + public JsTry(JsBlock tryBlock, @Nullable JsCatch jsCatch, @Nullable JsBlock finallyBlock) { + this(tryBlock, new SmartList(), finallyBlock); + + if (jsCatch != null) { + catches.add(jsCatch); + } + } + public List getCatches() { return catches; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index be76ca3f5d1..253bcead9a4 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -37,6 +37,7 @@ import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.declaration.ClassTranslator; import org.jetbrains.k2js.translate.expression.loopTranslator.LoopTranslatorPackage; +import org.jetbrains.k2js.translate.expression.tryTranslator.TryTranslatorPackage; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.TranslatorVisitor; import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator; @@ -446,7 +447,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitTryExpression(@NotNull JetTryExpression expression, @NotNull TranslationContext context) { - return TryTranslator.translate(expression, context).source(expression); + return TryTranslatorPackage.translateTryExpression(expression, context); } @Override diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/TryTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/TryTranslator.java deleted file mode 100644 index effaaf1846d..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/TryTranslator.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * 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 org.jetbrains.k2js.translate.expression; - -import com.google.dart.compiler.backend.js.ast.JsBlock; -import com.google.dart.compiler.backend.js.ast.JsCatch; -import com.google.dart.compiler.backend.js.ast.JsName; -import com.google.dart.compiler.backend.js.ast.JsTry; -import com.intellij.util.SmartList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.general.Translation; - -import java.util.List; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToBlock; - -//TODO: not tested at all -//TODO: not implemented catch logic -public final class TryTranslator extends AbstractTranslator { - - @NotNull - public static JsTry translate(@NotNull JetTryExpression expression, - @NotNull TranslationContext context) { - return (new TryTranslator(expression, context)).translate(); - } - - @NotNull - private final JetTryExpression expression; - - private TryTranslator(@NotNull JetTryExpression expression, - @NotNull TranslationContext context) { - super(context); - this.expression = expression; - } - - private JsTry translate() { - return new JsTry(translateTryBlock(), translateCatches(), translateFinallyBlock()); - } - - @Nullable - private JsBlock translateFinallyBlock() { - JetFinallySection finallyBlock = expression.getFinallyBlock(); - if (finallyBlock == null) return null; - - return convertToBlock(Translation.translateAsStatementAndMergeInBlockIfNeeded(finallyBlock.getFinalExpression(), context())); - } - - @NotNull - private JsBlock translateTryBlock() { - return convertToBlock(Translation.translateAsStatementAndMergeInBlockIfNeeded(expression.getTryBlock(), context())); - } - - @NotNull - private List translateCatches() { - List result = new SmartList(); - for (JetCatchClause catchClause : expression.getCatchClauses()) { - result.add(translateCatchClause(catchClause)); - } - return result; - } - - @NotNull - private JsCatch translateCatchClause(@NotNull JetCatchClause catchClause) { - JetParameter catchParameter = catchClause.getCatchParameter(); - assert catchParameter != null : "Valid catch must have a parameter."; - - JsName parameterName = context().getNameForElement(catchParameter); - JsCatch result = new JsCatch(context().scope(), parameterName.getIdent()); - result.setBody(translateCatchBody(catchClause)); - return result; - } - - @NotNull - private JsBlock translateCatchBody(@NotNull JetCatchClause catchClause) { - JetExpression catchBody = catchClause.getCatchBody(); - if (catchBody == null) { - return convertToBlock(context().getEmptyStatement()); - } - return convertToBlock(Translation.translateAsStatementAndMergeInBlockIfNeeded(catchBody, context())); - } - -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/tryTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/expression/tryTranslator.kt new file mode 100644 index 00000000000..0bc949a9a90 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/tryTranslator.kt @@ -0,0 +1,111 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * 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 org.jetbrains.k2js.translate.expression.tryTranslator + +import com.google.dart.compiler.backend.js.ast.* +import org.jetbrains.jet.lang.psi.JetCatchClause +import org.jetbrains.jet.lang.psi.JetTryExpression +import org.jetbrains.jet.lang.psi.JetTypeReference +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull +import org.jetbrains.jet.lang.resolve.DescriptorUtils +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.k2js.translate.context.TranslationContext +import org.jetbrains.k2js.translate.general.Translation +import org.jetbrains.k2js.translate.general.Translation.translateAsStatementAndMergeInBlockIfNeeded +import org.jetbrains.k2js.translate.utils.JsAstUtils +import org.jetbrains.k2js.translate.utils.JsAstUtils.convertToBlock +import org.jetbrains.k2js.translate.utils.TranslationUtils + + +val THROWABLE_CLASS_NAME = DescriptorUtils.getFqNameSafe(KotlinBuiltIns.getInstance().getThrowable()).asString() + +val JetCatchClause.parameterTypeReference: JetTypeReference + get() = this.getCatchParameter()?.getTypeReference()!! + +public fun translateTryExpression(expression: JetTryExpression, context: TranslationContext): JsTry { + + fun translateTryBlock() = convertToBlock(translateAsStatementAndMergeInBlockIfNeeded(expression.getTryBlock(), context)) + + fun JetCatchClause.getParameterName(): JsName = context.getNameForElement(this.getCatchParameter()!!) + + fun JetTypeReference.isThrowable(): Boolean { + val jetType = getNotNull(context.bindingContext(), BindingContext.TYPE, this) + return THROWABLE_CLASS_NAME == TranslationUtils.getJetTypeFqName(jetType, false) + } + + fun translateCatchBody(catchClause: JetCatchClause): JsBlock { + val catchBody = catchClause.getCatchBody() + if (catchBody == null) { + return convertToBlock(context.getEmptyStatement()) + } + return convertToBlock(translateAsStatementAndMergeInBlockIfNeeded(catchBody, context)) + } + + fun translateCatches(): JsCatch? { + val patternTranslator = Translation.patternTranslator(context) + val catchClausesStream = expression.getCatchClauses().stream() + if (catchClausesStream.none()) return null + + val firstCatchClause = catchClausesStream.first() + val firstParameterRef = JsNameRef(firstCatchClause.getParameterName()) + + fun jsCatch(body: JsBlock): JsCatch { + val result = JsCatch(context.scope(), firstParameterRef.getIdent()) + result.setBody(body) + return result + } + + fun ifIsCheckThen(typeReference: JetTypeReference, catchBlock: JsBlock): JsIf = + JsIf(patternTranslator.translateIsCheck(firstParameterRef, typeReference), catchBlock) + + if (firstCatchClause.parameterTypeReference.isThrowable()) { + return jsCatch(translateCatchBody(firstCatchClause)) + } + + val resultIf = ifIsCheckThen(firstCatchClause.parameterTypeReference, translateCatchBody(firstCatchClause)) + val currentIf = catchClausesStream.drop(1).fold(resultIf) { (currentIf, catchClause) -> + val typeReference = catchClause.parameterTypeReference + val catchBlock = translateCatchBody(catchClause) + if (typeReference.isThrowable()) { + currentIf.setElseStatement(catchBlock) + currentIf + } + else { + val nextIf = ifIsCheckThen(typeReference, catchBlock) + catchBlock.getStatements().add(0, JsAstUtils.newVar(catchClause.getParameterName(), firstParameterRef)) + currentIf.setElseStatement(nextIf) + nextIf + } + } + + if (currentIf.getElseStatement() == null) { + currentIf.setElseStatement(JsThrow(firstParameterRef)) + } + + return jsCatch(JsAstUtils.convertToBlock(resultIf)) + } + + fun translateFinallyBlock(): JsBlock? { + val finalExpression = expression.getFinallyBlock()?.getFinalExpression() + if (finalExpression == null) return null + + return convertToBlock(translateAsStatementAndMergeInBlockIfNeeded(finalExpression, context)) + } + + return JsTry(translateTryBlock(), translateCatches(), translateFinallyBlock()) +}