JS backend: remove dangerous package, correct translation for call, assignments, binary operations, support try...catch as expression
#KT-5576 Fixed #KT-5594 Fixed #KT-3166 Fixed #KT-5545 Fixed #KT-5594 Fixed #KT-5258 Fixed JS backend: fix KT-4879: extra side effect when use when in default arguments #KT-4879 Fixed JS backend: improve and fix WhenTranslator, fix order of evaluation for condtitions, fix KT-5263 (JS: extra tmp when initialize val in when by expression with if) #KT-5263 Fixed
This commit is contained in:
@@ -8,10 +8,7 @@ import com.google.dart.compiler.common.Symbol;
|
|||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JavaScript <code>var</code> statement.
|
* A JavaScript <code>var</code> statement.
|
||||||
@@ -97,6 +94,14 @@ public class JsVars extends SourceInfoAwareJsNode implements JsStatement, Iterab
|
|||||||
vars.add(var);
|
vars.add(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addAll(Collection<? extends JsVars.JsVar> vars) {
|
||||||
|
this.vars.addAll(vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAll(JsVars otherVars) {
|
||||||
|
this.vars.addAll(otherVars.vars);
|
||||||
|
}
|
||||||
|
|
||||||
public void addIfHasInitializer(JsVar var) {
|
public void addIfHasInitializer(JsVar var) {
|
||||||
if (var.getInitExpression() != null) {
|
if (var.getInitExpression() != null) {
|
||||||
add(var);
|
add(var);
|
||||||
|
|||||||
@@ -1,54 +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.test.semantics;
|
|
||||||
|
|
||||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
|
||||||
|
|
||||||
public final class DangerousTest extends SingleFileTranslationTest {
|
|
||||||
|
|
||||||
public DangerousTest() {
|
|
||||||
super("dangerous/");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIfAsFunArgument() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIfAsPlusArgument() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testWhenAsMinusArgument() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testEvaluationOrder() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDangerousInsideDangerous() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void test2dangerousInExpression() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDangerousInline() throws Exception {
|
|
||||||
fooBoxTest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -68,6 +68,7 @@ public class DefaultArgumentsTest extends SingleFileTranslationTest {
|
|||||||
checkFooBoxIsOk();
|
checkFooBoxIsOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testComplexExpressionAsDefaultArgument() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.semantics;
|
||||||
|
|
||||||
|
public class EvaluationOrderTest extends AbstractExpressionTest {
|
||||||
|
public EvaluationOrderTest() {
|
||||||
|
super("evaluationOrder/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test2dangerousInExpression() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAndAndWithSideEffect() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOrOrWithSideEffect() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAssignToDotQualifiedWithSideEffect() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAssignToArrayElementWithSideEffect() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCallArgs() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCallVarargs() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCompareToIntrinsicWithSideEffect() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDangerousInsideDangerous() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDangerousInline() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testElvisComplex() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEvaluationOrder1() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEqualsIntrinsicWithSideEffect() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEvaluationOrder2() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfAsFunArgument() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfAsPlusArgument() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfWithComplex() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIntrinsicComplex() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWhenAsMinusArgument() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWhenWithComplexConditions() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,4 +33,8 @@ public final class ForeachTest extends AbstractExpressionTest {
|
|||||||
public void testLabeledFor() throws Exception {
|
public void testLabeledFor() throws Exception {
|
||||||
fooBoxTest();
|
fooBoxTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testForWithComplexOneStatement() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.semantics;
|
||||||
|
|
||||||
|
import org.mozilla.javascript.JavaScriptException;
|
||||||
|
|
||||||
|
public class IfExpressionTest extends AbstractExpressionTest {
|
||||||
|
|
||||||
|
public IfExpressionTest() {
|
||||||
|
super("if/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfElseAsExpressionWithThrow() throws Exception {
|
||||||
|
try {
|
||||||
|
fooBoxTest();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (JavaScriptException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfInsideLambda() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNestedIf() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,15 +45,6 @@ public final class MiscTest extends AbstractExpressionTest {
|
|||||||
runFunctionOutputTest("classWithoutPackage.kt", Namer.getRootPackageName(), TEST_FUNCTION, true);
|
runFunctionOutputTest("classWithoutPackage.kt", Namer.getRootPackageName(), TEST_FUNCTION, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIfElseAsExpressionWithThrow() throws Exception {
|
|
||||||
try {
|
|
||||||
fooBoxTest();
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch (JavaScriptException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testKt1052_2() throws Exception {
|
public void testKt1052_2() throws Exception {
|
||||||
checkFooBoxIsTrue("KT-1052-2.kt");
|
checkFooBoxIsTrue("KT-1052-2.kt");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.semantics;
|
||||||
|
|
||||||
|
public class TryCatchTest extends AbstractExpressionTest {
|
||||||
|
|
||||||
|
public TryCatchTest() {
|
||||||
|
super("try/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTryCatchExpr() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.semantics;
|
||||||
|
|
||||||
|
public class WhileTest extends AbstractExpressionTest {
|
||||||
|
|
||||||
|
public WhileTest() {
|
||||||
|
super("while/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWhileWithComplexOneStatement() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ import org.jetbrains.k2js.translate.reference.CallArgumentTranslator
|
|||||||
import org.jetbrains.k2js.translate.utils.TranslationUtils
|
import org.jetbrains.k2js.translate.utils.TranslationUtils
|
||||||
import com.google.dart.compiler.backend.js.ast.JsLiteral
|
import com.google.dart.compiler.backend.js.ast.JsLiteral
|
||||||
import com.google.dart.compiler.backend.js.ast.JsConditional
|
import com.google.dart.compiler.backend.js.ast.JsConditional
|
||||||
|
import com.google.dart.compiler.backend.js.ast.JsBlock
|
||||||
|
|
||||||
|
|
||||||
trait CallInfo {
|
trait CallInfo {
|
||||||
@@ -79,8 +80,25 @@ fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescri
|
|||||||
|
|
||||||
// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall
|
// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall
|
||||||
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, explicitReceivers: ExplicitReceivers): FunctionCallInfo {
|
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, explicitReceivers: ExplicitReceivers): FunctionCallInfo {
|
||||||
val callInfo = createCallInfo(resolvedCall, explicitReceivers)
|
val argsBlock = JsBlock()
|
||||||
val argumentsInfo = CallArgumentTranslator.translate(resolvedCall, explicitReceivers.receiverOrThisObject, this)
|
val argumentsInfo = CallArgumentTranslator.translate(resolvedCall, explicitReceivers.receiverOrThisObject, this, argsBlock)
|
||||||
|
val explicitReceiversCorrected =
|
||||||
|
if (!argsBlock.isEmpty() && explicitReceivers.receiverOrThisObject != null) {
|
||||||
|
val receiverOrThisRefVar = this.declareTemporary(explicitReceivers.receiverOrThisObject)
|
||||||
|
this.addStatementToCurrentBlock(receiverOrThisRefVar.assignmentExpression().makeStmt()!!)
|
||||||
|
|
||||||
|
var receiverRef = explicitReceivers.receiverObject
|
||||||
|
if (receiverRef != null) {
|
||||||
|
receiverRef = this.declareTemporary(null).reference()
|
||||||
|
this.addStatementToCurrentBlock(JsAstUtils.assignment(receiverRef!!, explicitReceivers.receiverObject!!).makeStmt()!!)
|
||||||
|
}
|
||||||
|
ExplicitReceivers(receiverOrThisRefVar.reference(), receiverRef)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
explicitReceivers
|
||||||
|
}
|
||||||
|
this.addStatementsToCurrentBlockFrom(argsBlock)
|
||||||
|
val callInfo = createCallInfo(resolvedCall, explicitReceiversCorrected)
|
||||||
return FunctionCallInfo(callInfo, argumentsInfo)
|
return FunctionCallInfo(callInfo, argumentsInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,19 @@ public final class DynamicContext {
|
|||||||
return TemporaryVariable.create(temporaryName, initExpression);
|
return TemporaryVariable.create(temporaryName, initExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void moveVarsFrom(@NotNull DynamicContext dynamicContext) {
|
||||||
|
if (dynamicContext.vars != null) {
|
||||||
|
if (vars == null) {
|
||||||
|
vars = dynamicContext.vars;
|
||||||
|
currentBlock.getStatements().add(vars);
|
||||||
|
} else {
|
||||||
|
vars.addAll(dynamicContext.vars);
|
||||||
|
}
|
||||||
|
dynamicContext.currentBlock.getStatements().remove(dynamicContext.vars);
|
||||||
|
dynamicContext.vars = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: replace return type to make it more readable
|
//TODO: replace return type to make it more readable
|
||||||
@NotNull
|
@NotNull
|
||||||
public Pair<JsVar, JsExpression> createTemporary(@Nullable JsExpression initExpression) {
|
public Pair<JsVar, JsExpression> createTemporary(@Nullable JsExpression initExpression) {
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ public class TranslationContext {
|
|||||||
return usageTracker;
|
return usageTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public DynamicContext dynamicContext() {
|
public DynamicContext dynamicContext() {
|
||||||
return dynamicContext;
|
return dynamicContext;
|
||||||
}
|
}
|
||||||
@@ -112,6 +113,11 @@ public class TranslationContext {
|
|||||||
return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null);
|
return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public TranslationContext innerBlock() {
|
||||||
|
return innerBlock(new JsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor, @Nullable DefinitionPlace place) {
|
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor, @Nullable DefinitionPlace place) {
|
||||||
DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor));
|
DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor));
|
||||||
@@ -259,6 +265,27 @@ public class TranslationContext {
|
|||||||
dynamicContext.jsBlock().getStatements().add(statement);
|
dynamicContext.jsBlock().getStatements().add(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addStatementsToCurrentBlockFrom(@NotNull TranslationContext context) {
|
||||||
|
addStatementsToCurrentBlockFrom(context.dynamicContext().jsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addStatementsToCurrentBlockFrom(@NotNull JsBlock block) {
|
||||||
|
dynamicContext.jsBlock().getStatements().addAll(block.getStatements());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean currentBlockIsEmpty() {
|
||||||
|
return dynamicContext.jsBlock().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveVarsFrom(@NotNull TranslationContext context) {
|
||||||
|
dynamicContext.moveVarsFrom(context.dynamicContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JsBlock getCurrentBlock() {
|
||||||
|
return dynamicContext.jsBlock();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||||
JsNameRef nameRef = captureIfNeedAndGetCapturedName(descriptor);
|
JsNameRef nameRef = captureIfNeedAndGetCapturedName(descriptor);
|
||||||
|
|||||||
+26
-27
@@ -29,7 +29,6 @@ import org.jetbrains.jet.lang.resolve.constants.NullValue;
|
|||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
|
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
|
||||||
import org.jetbrains.k2js.translate.expression.foreach.ForTranslator;
|
import org.jetbrains.k2js.translate.expression.foreach.ForTranslator;
|
||||||
@@ -39,7 +38,6 @@ import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator;
|
|||||||
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
|
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
|
||||||
import org.jetbrains.k2js.translate.reference.*;
|
import org.jetbrains.k2js.translate.reference.*;
|
||||||
import org.jetbrains.k2js.translate.utils.*;
|
import org.jetbrains.k2js.translate.utils.*;
|
||||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -52,7 +50,6 @@ import static org.jetbrains.k2js.translate.utils.ErrorReportingUtils.message;
|
|||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||||
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration;
|
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration;
|
||||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateInitializerForProperty;
|
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateInitializerForProperty;
|
||||||
import static org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression;
|
|
||||||
|
|
||||||
public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||||
@Override
|
@Override
|
||||||
@@ -179,29 +176,27 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public JsNode visitIfExpression(@NotNull JetIfExpression expression, @NotNull TranslationContext context) {
|
public JsNode visitIfExpression(@NotNull JetIfExpression expression, @NotNull TranslationContext context) {
|
||||||
JsExpression testExpression = translateConditionExpression(expression.getCondition(), context);
|
JsExpression testExpression = translateConditionExpression(expression.getCondition(), context);
|
||||||
|
|
||||||
|
boolean isKotlinExpression = BindingContextUtilPackage.isUsedAsExpression(expression, context.bindingContext());
|
||||||
|
|
||||||
JetExpression thenExpression = expression.getThen();
|
JetExpression thenExpression = expression.getThen();
|
||||||
|
assert thenExpression != null : "then expression should not be null: " + expression.getText();
|
||||||
JetExpression elseExpression = expression.getElse();
|
JetExpression elseExpression = expression.getElse();
|
||||||
assert thenExpression != null;
|
|
||||||
JsNode thenNode = thenExpression.accept(this, context);
|
|
||||||
JsNode elseNode = elseExpression == null ? null : elseExpression.accept(this, context);
|
|
||||||
|
|
||||||
boolean isKotlinStatement = BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext());
|
JsStatement thenStatement = Translation.translateAsStatement(thenExpression, context);
|
||||||
boolean canBeJsExpression = thenNode instanceof JsExpression && elseNode instanceof JsExpression;
|
JsStatement elseStatement = (elseExpression != null) ? Translation.translateAsStatement(elseExpression, context) : null;
|
||||||
if (!isKotlinStatement && canBeJsExpression) {
|
|
||||||
return new JsConditional(testExpression, convertToExpression(thenNode), convertToExpression(elseNode)).source(expression);
|
if (isKotlinExpression) {
|
||||||
}
|
JsExpression jsThenExpression = JsAstUtils.extractExpressionFromStatement(thenStatement);
|
||||||
else {
|
JsExpression jsElseExpression = JsAstUtils.extractExpressionFromStatement(elseStatement);
|
||||||
JsIf ifStatement = new JsIf(testExpression, convertToStatement(thenNode), elseNode == null ? null : convertToStatement(elseNode));
|
boolean canBeJsExpression = jsThenExpression != null && jsElseExpression != null;
|
||||||
ifStatement.source(expression);
|
if (canBeJsExpression) {
|
||||||
if (isKotlinStatement) {
|
return new JsConditional(testExpression, jsThenExpression, jsElseExpression).source(expression);
|
||||||
return ifStatement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TemporaryVariable result = context.declareTemporary(null);
|
|
||||||
AssignToExpressionMutator saveResultToTemporaryMutator = new AssignToExpressionMutator(result.reference());
|
|
||||||
context.addStatementToCurrentBlock(mutateLastExpression(ifStatement, saveResultToTemporaryMutator));
|
|
||||||
return result.reference();
|
|
||||||
}
|
}
|
||||||
|
JsIf ifStatement = new JsIf(testExpression, thenStatement, elseStatement);
|
||||||
|
ifStatement.source(expression);
|
||||||
|
return isKotlinExpression ? convertToExpression(ifStatement, context) : ifStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -212,12 +207,14 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsStatement translateNullableExpressionAsNotNullStatement(@Nullable JetExpression nullableExpression,
|
private static JsStatement translateNullableExpressionAsNotNullStatement(
|
||||||
@NotNull TranslationContext context) {
|
@Nullable JetExpression nullableExpression,
|
||||||
|
@NotNull TranslationContext context
|
||||||
|
) {
|
||||||
if (nullableExpression == null) {
|
if (nullableExpression == null) {
|
||||||
return context.program().getEmptyStatement();
|
return context.program().getEmptyStatement();
|
||||||
}
|
}
|
||||||
return convertToStatement(nullableExpression.accept(this, context));
|
return Translation.translateAsStatement(nullableExpression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -225,7 +222,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
JsExpression jsCondition = translateNullableExpression(expression, context);
|
JsExpression jsCondition = translateNullableExpression(expression, context);
|
||||||
assert (jsCondition != null) : "Condition should not be empty";
|
assert (jsCondition != null) : "Condition should not be empty";
|
||||||
return convertToExpression(jsCondition);
|
return convertToExpression(jsCondition, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -234,7 +231,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
if (expression == null) {
|
if (expression == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return convertToExpression(expression.accept(this, context));
|
return convertToExpression(expression.accept(this, context), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -251,7 +248,9 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
|
|
||||||
private JsNode createWhile(@NotNull JsWhile result, @NotNull JetWhileExpressionBase expression, @NotNull TranslationContext context) {
|
private JsNode createWhile(@NotNull JsWhile result, @NotNull JetWhileExpressionBase expression, @NotNull TranslationContext context) {
|
||||||
result.setCondition(translateConditionExpression(expression.getCondition(), context));
|
result.setCondition(translateConditionExpression(expression.getCondition(), context));
|
||||||
result.setBody(translateNullableExpressionAsNotNullStatement(expression.getBody(), context));
|
TranslationContext bodyContext = context.innerBlock();
|
||||||
|
JsStatement bodyStatement = translateNullableExpressionAsNotNullStatement(expression.getBody(), bodyContext);
|
||||||
|
result.setBody(bodyStatement);
|
||||||
return result.source(expression);
|
return result.source(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,18 @@
|
|||||||
package org.jetbrains.k2js.translate.expression;
|
package org.jetbrains.k2js.translate.expression;
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
import com.google.dart.compiler.backend.js.ast.*;
|
||||||
import com.intellij.openapi.util.Pair;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||||
|
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.k2js.translate.general.Translation;
|
import org.jetbrains.k2js.translate.general.Translation;
|
||||||
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
|
||||||
import org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator;
|
|
||||||
|
|
||||||
import java.util.List;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToExpression;
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToStatement;
|
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.negated;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.negated;
|
||||||
|
|
||||||
public final class WhenTranslator extends AbstractTranslator {
|
public final class WhenTranslator extends AbstractTranslator {
|
||||||
@@ -40,9 +37,7 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
WhenTranslator translator = new WhenTranslator(expression, context);
|
WhenTranslator translator = new WhenTranslator(expression, context);
|
||||||
|
|
||||||
if (BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())) {
|
if (BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())) {
|
||||||
JsBlock jsBlock = new JsBlock();
|
return translator.translateAsStatement();
|
||||||
translator.translateAsStatement(jsBlock.getStatements());
|
|
||||||
return jsBlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return translator.translateAsExpression();
|
return translator.translateAsExpression();
|
||||||
@@ -52,10 +47,7 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
private final JetWhenExpression whenExpression;
|
private final JetWhenExpression whenExpression;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Pair<JsVars.JsVar, JsExpression> expressionToMatch;
|
private final JsExpression expressionToMatch;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Pair<JsVars.JsVar, JsExpression> result;
|
|
||||||
|
|
||||||
private WhenTranslator(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
|
private WhenTranslator(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -64,7 +56,13 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
JetExpression subject = expression.getSubjectExpression();
|
JetExpression subject = expression.getSubjectExpression();
|
||||||
if (subject != null) {
|
if (subject != null) {
|
||||||
expressionToMatch = TranslationUtils.createTemporaryIfNeed(Translation.translateAsExpression(subject, context()), context);
|
JsExpression subjectExpression = Translation.translateAsExpression(subject, context);
|
||||||
|
if (TranslationUtils.isCacheNeeded(subjectExpression)) {
|
||||||
|
TemporaryVariable subjectVar = context.declareTemporary(null);
|
||||||
|
context.addStatementToCurrentBlock(JsAstUtils.assignment(subjectVar.reference(), subjectExpression).makeStmt());
|
||||||
|
subjectExpression = subjectVar.reference();
|
||||||
|
}
|
||||||
|
expressionToMatch = subjectExpression;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
expressionToMatch = null;
|
expressionToMatch = null;
|
||||||
@@ -73,95 +71,96 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private JsNode translateAsExpression() {
|
private JsNode translateAsExpression() {
|
||||||
result = context().dynamicContext().createTemporary(null);
|
return convertToExpression(translateAsStatement(), context());
|
||||||
translateAsStatement(context().dynamicContext().jsBlock().getStatements());
|
|
||||||
return result.second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void translateAsStatement(List<JsStatement> statements) {
|
private JsStatement translateAsStatement() {
|
||||||
addTempVarsStatement(statements);
|
JsIf currentIf = null;
|
||||||
|
JsIf resultIf = null;
|
||||||
JsIf prevIf = null;
|
|
||||||
for (JetWhenEntry entry : whenExpression.getEntries()) {
|
for (JetWhenEntry entry : whenExpression.getEntries()) {
|
||||||
JsBlock entryBody = new JsBlock();
|
JsBlock statementBlock = new JsBlock();
|
||||||
JsStatement statement = withReturnValueCaptured(translateEntryExpression(entry, context().innerBlock(entryBody)));
|
JsStatement statement = translateEntryExpression(entry, context(), statementBlock);
|
||||||
if (!entryBody.isEmpty()) {
|
|
||||||
entryBody.getStatements().add(statement);
|
|
||||||
statement = entryBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsStatement statementToAdd = entry.isElse() ? statement : new JsIf(translateConditions(entry), statement);
|
if (resultIf == null && entry.isElse()) {
|
||||||
if (prevIf == null) {
|
context().addStatementsToCurrentBlockFrom(statementBlock);
|
||||||
statements.add(statementToAdd);
|
return statement;
|
||||||
|
}
|
||||||
|
statement = JsAstUtils.mergeStatementInBlockIfNeeded(statement, statementBlock);
|
||||||
|
|
||||||
|
if (resultIf == null) {
|
||||||
|
currentIf = new JsIf(translateConditions(entry, context()), statement);
|
||||||
|
resultIf = currentIf;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
prevIf.setElseStatement(statementToAdd);
|
if (entry.isElse()) {
|
||||||
|
currentIf.setElseStatement(statement);
|
||||||
|
return resultIf;
|
||||||
|
}
|
||||||
|
JsBlock conditionsBlock = new JsBlock();
|
||||||
|
JsIf nextIf = new JsIf(translateConditions(entry, context().innerBlock(conditionsBlock)), statement);
|
||||||
|
JsStatement statementToAdd = JsAstUtils.mergeStatementInBlockIfNeeded(nextIf, conditionsBlock);
|
||||||
|
currentIf.setElseStatement(statementToAdd);
|
||||||
|
currentIf = nextIf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.isElse()) break;
|
|
||||||
|
|
||||||
assert statementToAdd instanceof JsIf : "Non-else entry expected: " + entry.getText();
|
|
||||||
prevIf = (JsIf) statementToAdd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTempVarsStatement(List<JsStatement> statements) {
|
|
||||||
JsVars vars = new JsVars();
|
|
||||||
if (expressionToMatch != null && expressionToMatch.first != null) {
|
|
||||||
vars.add(expressionToMatch.first);
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
vars.add(result.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vars.isEmpty()) {
|
|
||||||
statements.add(vars);
|
|
||||||
}
|
}
|
||||||
|
return resultIf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsStatement withReturnValueCaptured(@NotNull JsNode node) {
|
private static JsStatement translateEntryExpression(
|
||||||
return result == null
|
@NotNull JetWhenEntry entry,
|
||||||
? convertToStatement(node)
|
@NotNull TranslationContext context,
|
||||||
: LastExpressionMutator.mutateLastExpression(node, new AssignToExpressionMutator(result.second));
|
@NotNull JsBlock block) {
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private JsNode translateEntryExpression(@NotNull JetWhenEntry entry, @NotNull TranslationContext context) {
|
|
||||||
JetExpression expressionToExecute = entry.getExpression();
|
JetExpression expressionToExecute = entry.getExpression();
|
||||||
assert expressionToExecute != null : "WhenEntry should have whenExpression to execute.";
|
assert expressionToExecute != null : "WhenEntry should have whenExpression to execute.";
|
||||||
return Translation.translateExpression(expressionToExecute, context);
|
return Translation.translateAsStatement(expressionToExecute, context, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateConditions(@NotNull JetWhenEntry entry) {
|
private JsExpression translateConditions(@NotNull JetWhenEntry entry, @NotNull TranslationContext context) {
|
||||||
JetWhenCondition[] conditions = entry.getConditions();
|
JetWhenCondition[] conditions = entry.getConditions();
|
||||||
|
|
||||||
assert conditions.length > 0 : "When entry (not else) should have at least one condition";
|
assert conditions.length > 0 : "When entry (not else) should have at least one condition";
|
||||||
|
|
||||||
if (conditions.length == 1) {
|
if (conditions.length == 1) {
|
||||||
return translateCondition(conditions[0]);
|
return translateCondition(conditions[0], context);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsExpression result = translateCondition(conditions[0]);
|
JsExpression result = translateCondition(conditions[0], context);
|
||||||
for (int i = 1; i < conditions.length; i++) {
|
for (int i = 1; i < conditions.length; i++) {
|
||||||
result = new JsBinaryOperation(JsBinaryOperator.OR, translateCondition(conditions[i]), result);
|
result = translateOrCondition(result, conditions[i], context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateCondition(@NotNull JetWhenCondition condition) {
|
private JsExpression translateOrCondition(@NotNull JsExpression leftExpression, @NotNull JetWhenCondition condition, @NotNull TranslationContext context) {
|
||||||
|
TranslationContext rightContext = context.innerBlock();
|
||||||
|
JsExpression rightExpression = translateCondition(condition, rightContext);
|
||||||
|
context.moveVarsFrom(rightContext);
|
||||||
|
if (rightContext.currentBlockIsEmpty()) {
|
||||||
|
return new JsBinaryOperation(JsBinaryOperator.OR, leftExpression, rightExpression);
|
||||||
|
} else {
|
||||||
|
assert rightExpression instanceof JsNameRef : "expected JsNameRef, but: " + rightExpression;
|
||||||
|
JsNameRef result = (JsNameRef) rightExpression;
|
||||||
|
JsIf ifStatement = new JsIf(leftExpression, JsAstUtils.assignment(result, JsLiteral.TRUE).makeStmt(), rightContext.getCurrentBlock());
|
||||||
|
context.addStatementToCurrentBlock(ifStatement);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private JsExpression translateCondition(@NotNull JetWhenCondition condition, @NotNull TranslationContext context) {
|
||||||
if ((condition instanceof JetWhenConditionIsPattern) || (condition instanceof JetWhenConditionWithExpression)) {
|
if ((condition instanceof JetWhenConditionIsPattern) || (condition instanceof JetWhenConditionWithExpression)) {
|
||||||
return translatePatternCondition(condition);
|
return translatePatternCondition(condition, context);
|
||||||
}
|
}
|
||||||
throw new AssertionError("Unsupported when condition " + condition.getClass());
|
throw new AssertionError("Unsupported when condition " + condition.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translatePatternCondition(@NotNull JetWhenCondition condition) {
|
private JsExpression translatePatternCondition(@NotNull JetWhenCondition condition, @NotNull TranslationContext context) {
|
||||||
JsExpression patternMatchExpression = translateWhenConditionToBooleanExpression(condition);
|
JsExpression patternMatchExpression = translateWhenConditionToBooleanExpression(condition, context);
|
||||||
if (isNegated(condition)) {
|
if (isNegated(condition)) {
|
||||||
return negated(patternMatchExpression);
|
return negated(patternMatchExpression);
|
||||||
}
|
}
|
||||||
@@ -169,44 +168,44 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateWhenConditionToBooleanExpression(@NotNull JetWhenCondition condition) {
|
private JsExpression translateWhenConditionToBooleanExpression(@NotNull JetWhenCondition condition, @NotNull TranslationContext context) {
|
||||||
if (condition instanceof JetWhenConditionIsPattern) {
|
if (condition instanceof JetWhenConditionIsPattern) {
|
||||||
return translateIsCondition((JetWhenConditionIsPattern) condition);
|
return translateIsCondition((JetWhenConditionIsPattern) condition, context);
|
||||||
}
|
}
|
||||||
else if (condition instanceof JetWhenConditionWithExpression) {
|
else if (condition instanceof JetWhenConditionWithExpression) {
|
||||||
return translateExpressionCondition((JetWhenConditionWithExpression) condition);
|
return translateExpressionCondition((JetWhenConditionWithExpression) condition, context);
|
||||||
}
|
}
|
||||||
throw new AssertionError("Wrong type of JetWhenCondition");
|
throw new AssertionError("Wrong type of JetWhenCondition");
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateIsCondition(@NotNull JetWhenConditionIsPattern conditionIsPattern) {
|
private JsExpression translateIsCondition(@NotNull JetWhenConditionIsPattern conditionIsPattern, @NotNull TranslationContext context) {
|
||||||
JsExpression expressionToMatch = getExpressionToMatch();
|
JsExpression expressionToMatch = getExpressionToMatch();
|
||||||
assert expressionToMatch != null : "An is-check is not allowed in when() without subject.";
|
assert expressionToMatch != null : "An is-check is not allowed in when() without subject.";
|
||||||
|
|
||||||
JetTypeReference typeReference = conditionIsPattern.getTypeRef();
|
JetTypeReference typeReference = conditionIsPattern.getTypeRef();
|
||||||
assert typeReference != null : "An is-check must have a type reference.";
|
assert typeReference != null : "An is-check must have a type reference.";
|
||||||
|
|
||||||
return Translation.patternTranslator(context()).translateIsCheck(expressionToMatch, typeReference);
|
return Translation.patternTranslator(context).translateIsCheck(expressionToMatch, typeReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateExpressionCondition(@NotNull JetWhenConditionWithExpression condition) {
|
private JsExpression translateExpressionCondition(@NotNull JetWhenConditionWithExpression condition, @NotNull TranslationContext context) {
|
||||||
JetExpression patternExpression = condition.getExpression();
|
JetExpression patternExpression = condition.getExpression();
|
||||||
assert patternExpression != null : "Expression pattern should have an expression.";
|
assert patternExpression != null : "Expression pattern should have an expression.";
|
||||||
|
|
||||||
JsExpression expressionToMatch = getExpressionToMatch();
|
JsExpression expressionToMatch = getExpressionToMatch();
|
||||||
if (expressionToMatch == null) {
|
if (expressionToMatch == null) {
|
||||||
return Translation.patternTranslator(context()).translateExpressionForExpressionPattern(patternExpression);
|
return Translation.patternTranslator(context).translateExpressionForExpressionPattern(patternExpression);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Translation.patternTranslator(context()).translateExpressionPattern(expressionToMatch, patternExpression);
|
return Translation.patternTranslator(context).translateExpressionPattern(expressionToMatch, patternExpression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private JsExpression getExpressionToMatch() {
|
private JsExpression getExpressionToMatch() {
|
||||||
return expressionToMatch != null ? expressionToMatch.second : null;
|
return expressionToMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNegated(@NotNull JetWhenCondition condition) {
|
private static boolean isNegated(@NotNull JetWhenCondition condition) {
|
||||||
|
|||||||
+5
-8
@@ -29,6 +29,8 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
|
|||||||
import org.jetbrains.k2js.translate.expression.MultiDeclarationTranslator;
|
import org.jetbrains.k2js.translate.expression.MultiDeclarationTranslator;
|
||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.k2js.translate.general.Translation;
|
import org.jetbrains.k2js.translate.general.Translation;
|
||||||
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
|
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar;
|
||||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
|
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
|
||||||
@@ -95,14 +97,9 @@ public abstract class ForTranslator extends AbstractTranslator {
|
|||||||
return realBody;
|
return realBody;
|
||||||
} else {
|
} else {
|
||||||
JsStatement currentVarInit = makeCurrentVarInit(itemValue);
|
JsStatement currentVarInit = makeCurrentVarInit(itemValue);
|
||||||
if (realBody instanceof JsBlock) {
|
JsBlock block = JsAstUtils.convertToBlock(realBody);
|
||||||
JsBlock block = (JsBlock) realBody;
|
block.getStatements().add(0, currentVarInit);
|
||||||
block.getStatements().add(0, currentVarInit);
|
return block;
|
||||||
return block;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new JsBlock(currentVarInit, realBody);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
|||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||||
import org.jetbrains.jet.lang.reflect.ReflectionTypes;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.plugin.MainFunctionDetector;
|
import org.jetbrains.jet.plugin.MainFunctionDetector;
|
||||||
import org.jetbrains.k2js.config.Config;
|
import org.jetbrains.k2js.config.Config;
|
||||||
@@ -47,8 +46,6 @@ import org.jetbrains.k2js.translate.test.JSTestGenerator;
|
|||||||
import org.jetbrains.k2js.translate.test.JSTester;
|
import org.jetbrains.k2js.translate.test.JSTester;
|
||||||
import org.jetbrains.k2js.translate.test.QUnitTester;
|
import org.jetbrains.k2js.translate.test.QUnitTester;
|
||||||
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.dangerous.DangerousData;
|
|
||||||
import org.jetbrains.k2js.translate.utils.dangerous.DangerousTranslator;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -56,7 +53,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
|
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||||
import static org.jetbrains.k2js.translate.utils.dangerous.DangerousData.collect;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a interface which all translators use to interact with each other.
|
* This class provides a interface which all translators use to interact with each other.
|
||||||
@@ -80,15 +76,21 @@ public final class Translation {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
public static JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
||||||
|
return translateExpression(expression, context, context.dynamicContext().jsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context, @NotNull JsBlock block) {
|
||||||
JsExpression aliasForExpression = context.aliasingContext().getAliasForExpression(expression);
|
JsExpression aliasForExpression = context.aliasingContext().getAliasForExpression(expression);
|
||||||
if (aliasForExpression != null) {
|
if (aliasForExpression != null) {
|
||||||
return aliasForExpression;
|
return aliasForExpression;
|
||||||
}
|
}
|
||||||
DangerousData data = collect(expression, context);
|
|
||||||
if (data.shouldBeTranslated()) {
|
TranslationContext innerContext = context.innerBlock();
|
||||||
return DangerousTranslator.translate(data, context);
|
JsNode result = doTranslateExpression(expression, innerContext);
|
||||||
}
|
context.moveVarsFrom(innerContext);
|
||||||
return doTranslateExpression(expression, context);
|
block.getStatements().addAll(innerContext.dynamicContext().jsBlock().getStatements());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: use with care
|
//NOTE: use with care
|
||||||
@@ -98,15 +100,32 @@ public final class Translation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression translateAsExpression(@NotNull JetExpression expression,
|
public static JsExpression translateAsExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
||||||
@NotNull TranslationContext context) {
|
return convertToExpression(translateExpression(expression, context), context);
|
||||||
return convertToExpression(translateExpression(expression, context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsStatement translateAsStatement(@NotNull JetExpression expression,
|
public static JsExpression translateAsExpression(
|
||||||
@NotNull TranslationContext context) {
|
@NotNull JetExpression expression,
|
||||||
return convertToStatement(translateExpression(expression, context));
|
@NotNull TranslationContext context,
|
||||||
|
@NotNull JsBlock block
|
||||||
|
) {
|
||||||
|
return convertToExpression(translateExpression(expression, context, block), context, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsStatement translateAsStatement(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
||||||
|
JsBlock block = new JsBlock();
|
||||||
|
JsNode node = translateExpression(expression, context, block);
|
||||||
|
return JsAstUtils.mergeStatementInBlockIfNeeded(convertToStatement(node), block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsStatement translateAsStatement(
|
||||||
|
@NotNull JetExpression expression,
|
||||||
|
@NotNull TranslationContext context,
|
||||||
|
@NotNull JsBlock block) {
|
||||||
|
return convertToStatement(translateExpression(expression, context, block));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+7
-2
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.k2js.translate.operation;
|
package org.jetbrains.k2js.translate.operation;
|
||||||
|
|
||||||
|
import com.google.dart.compiler.backend.js.ast.JsBlock;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||||
@@ -64,7 +65,11 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
|
|||||||
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
|
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
|
||||||
JetExpression left = expression.getLeft();
|
JetExpression left = expression.getLeft();
|
||||||
assert left != null : "No left-hand side: " + expression.getText();
|
assert left != null : "No left-hand side: " + expression.getText();
|
||||||
this.accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context());
|
|
||||||
this.right = translateRightExpression(context(), expression);
|
JsBlock rightBlock = new JsBlock();
|
||||||
|
this.right = translateRightExpression(context, expression, rightBlock);
|
||||||
|
|
||||||
|
this.accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context(), !rightBlock.isEmpty());
|
||||||
|
context.addStatementsToCurrentBlockFrom(rightBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-20
@@ -33,15 +33,13 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
|
|||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.k2js.translate.general.Translation;
|
import org.jetbrains.k2js.translate.general.Translation;
|
||||||
import org.jetbrains.k2js.translate.intrinsic.operation.BinaryOperationIntrinsic;
|
import org.jetbrains.k2js.translate.intrinsic.operation.BinaryOperationIntrinsic;
|
||||||
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
|
||||||
import org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator;
|
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert;
|
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert;
|
||||||
import static org.jetbrains.k2js.translate.operation.AssignmentTranslator.isAssignmentOperator;
|
import static org.jetbrains.k2js.translate.operation.AssignmentTranslator.isAssignmentOperator;
|
||||||
import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompareToCall;
|
import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompareToCall;
|
||||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToStatement;
|
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.not;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.not;
|
||||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
||||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
|
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
|
||||||
@@ -84,7 +82,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
|||||||
return applyIntrinsic(intrinsic);
|
return applyIntrinsic(intrinsic);
|
||||||
}
|
}
|
||||||
if (getOperationToken(expression).equals(JetTokens.ELVIS)) {
|
if (getOperationToken(expression).equals(JetTokens.ELVIS)) {
|
||||||
return translateElvis(expression);
|
return translateElvis();
|
||||||
}
|
}
|
||||||
if (isAssignmentOperator(expression)) {
|
if (isAssignmentOperator(expression)) {
|
||||||
return AssignmentTranslator.translate(expression, context());
|
return AssignmentTranslator.translate(expression, context());
|
||||||
@@ -101,24 +99,26 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateElvis(JetBinaryExpression expression) {
|
private JsExpression translateElvis() {
|
||||||
JsExpression leftExpression = translateLeftExpression(context(), expression);
|
JsExpression leftExpression = translateLeftExpression(context(), expression);
|
||||||
|
|
||||||
JetExpression rightJetExpression = expression.getRight();
|
JetExpression rightJetExpression = expression.getRight();
|
||||||
assert rightJetExpression != null : "Binary expression should have a right expression";
|
assert rightJetExpression != null : "Binary expression should have a right expression";
|
||||||
JsNode rightNode = Translation.translateExpression(rightJetExpression, context());
|
JsBlock rightBlock = new JsBlock();
|
||||||
|
JsNode rightNode = Translation.translateExpression(rightJetExpression, context(), rightBlock);
|
||||||
|
|
||||||
if (rightNode instanceof JsExpression) {
|
if (rightNode instanceof JsExpression && rightBlock.isEmpty()) {
|
||||||
return TranslationUtils.notNullConditional(leftExpression, (JsExpression) rightNode, context());
|
return TranslationUtils.notNullConditional(leftExpression, (JsExpression) rightNode, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
TemporaryVariable result = context().declareTemporary(null);
|
TemporaryVariable result = context().declareTemporary(leftExpression);
|
||||||
AssignToExpressionMutator saveResultToTemporaryMutator = new AssignToExpressionMutator(result.reference());
|
context().addStatementToCurrentBlock(result.assignmentExpression().makeStmt());
|
||||||
context().addStatementToCurrentBlock(LastExpressionMutator.mutateLastExpression(leftExpression, saveResultToTemporaryMutator));
|
|
||||||
|
|
||||||
JsExpression testExpression = TranslationUtils.isNullCheck(result.reference());
|
JsExpression testExpression = TranslationUtils.isNullCheck(result.reference());
|
||||||
JsStatement thenStatement = convertToStatement(rightNode);
|
JsExpression rightExpression = JsAstUtils.convertToExpression(rightNode, context(), rightBlock);
|
||||||
JsIf ifStatement = new JsIf(testExpression, thenStatement);
|
rightBlock.getStatements().add(JsAstUtils.assignment(result.reference(), rightExpression).makeStmt());
|
||||||
|
|
||||||
|
JsIf ifStatement = new JsIf(testExpression, rightBlock);
|
||||||
context().addStatementToCurrentBlock(ifStatement);
|
context().addStatementToCurrentBlock(ifStatement);
|
||||||
|
|
||||||
return result.reference();
|
return result.reference();
|
||||||
@@ -131,10 +131,22 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression applyIntrinsic(@NotNull BinaryOperationIntrinsic intrinsic) {
|
private JsExpression applyIntrinsic(@NotNull BinaryOperationIntrinsic intrinsic) {
|
||||||
return intrinsic.apply(expression,
|
JsExpression leftExpression = translateLeftExpression(context(), expression);
|
||||||
translateLeftExpression(context(), expression),
|
JsBlock rightBlock = new JsBlock();
|
||||||
translateRightExpression(context(), expression),
|
JsExpression rightExpression = translateRightExpression(context(), expression, rightBlock);
|
||||||
context());
|
|
||||||
|
if (rightBlock.isEmpty()) {
|
||||||
|
return intrinsic.apply(expression, leftExpression, rightExpression, context());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TranslationUtils.isCacheNeeded(leftExpression)) {
|
||||||
|
TemporaryVariable temporaryVariable = context().declareTemporary(null);
|
||||||
|
context().addStatementToCurrentBlock(JsAstUtils.assignment(temporaryVariable.reference(), leftExpression).makeStmt());
|
||||||
|
leftExpression = temporaryVariable.reference();
|
||||||
|
}
|
||||||
|
context().addStatementsToCurrentBlockFrom(rightBlock);
|
||||||
|
|
||||||
|
return intrinsic.apply(expression, leftExpression, rightExpression, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNotOverloadable() {
|
private boolean isNotOverloadable() {
|
||||||
@@ -144,11 +156,32 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateAsUnOverloadableBinaryOperation() {
|
private JsExpression translateAsUnOverloadableBinaryOperation() {
|
||||||
JetToken token = getOperationToken(expression);
|
JetToken token = getOperationToken(expression);
|
||||||
JsBinaryOperator operator = OperatorTable.getBinaryOperator(token);
|
|
||||||
assert OperatorConventions.NOT_OVERLOADABLE.contains(token);
|
assert OperatorConventions.NOT_OVERLOADABLE.contains(token);
|
||||||
JsExpression left = translateLeftExpression(context(), expression);
|
JsBinaryOperator operator = OperatorTable.getBinaryOperator(token);
|
||||||
JsExpression right = translateRightExpression(context(), expression);
|
JsExpression leftExpression = translateLeftExpression(context(), expression);
|
||||||
return new JsBinaryOperation(operator, left, right);
|
JsBlock rightBlock = new JsBlock();
|
||||||
|
JsExpression rightExpression = translateRightExpression(context(), expression, rightBlock);
|
||||||
|
|
||||||
|
if (rightBlock.isEmpty()) {
|
||||||
|
return new JsBinaryOperation(operator, leftExpression, rightExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert rightExpression instanceof JsNameRef : "expected JsNameRef, but " + expression.getText();
|
||||||
|
JsNameRef result = (JsNameRef) rightExpression; // Reuse tmp variable
|
||||||
|
|
||||||
|
JsIf ifStatement;
|
||||||
|
if (token.equals(JetTokens.ANDAND)) {
|
||||||
|
ifStatement = new JsIf(leftExpression, rightBlock, JsAstUtils.assignment(result, JsLiteral.FALSE).makeStmt());
|
||||||
|
}
|
||||||
|
else if (token.equals(JetTokens.OROR)) {
|
||||||
|
ifStatement = new JsIf(leftExpression, JsAstUtils.assignment(result, JsLiteral.TRUE).makeStmt(), rightBlock);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("Unsupported binary operation: " + expression.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
context().addStatementToCurrentBlock(ifStatement);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+41
-2
@@ -19,7 +19,14 @@ package org.jetbrains.k2js.translate.reference;
|
|||||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
|
import org.jetbrains.k2js.translate.general.Translation;
|
||||||
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
|
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public final class AccessTranslationUtils {
|
public final class AccessTranslationUtils {
|
||||||
private AccessTranslationUtils() {
|
private AccessTranslationUtils() {
|
||||||
@@ -28,16 +35,48 @@ public final class AccessTranslationUtils {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
|
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
|
return getAccessTranslator(referenceExpression, context, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
|
||||||
|
@NotNull TranslationContext context, boolean forceOrderOfEvaluation) {
|
||||||
assert ((referenceExpression instanceof JetReferenceExpression) ||
|
assert ((referenceExpression instanceof JetReferenceExpression) ||
|
||||||
(referenceExpression instanceof JetQualifiedExpression));
|
(referenceExpression instanceof JetQualifiedExpression));
|
||||||
if (referenceExpression instanceof JetQualifiedExpression) {
|
if (referenceExpression instanceof JetQualifiedExpression) {
|
||||||
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context);
|
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context, forceOrderOfEvaluation);
|
||||||
}
|
}
|
||||||
if (referenceExpression instanceof JetSimpleNameExpression) {
|
if (referenceExpression instanceof JetSimpleNameExpression) {
|
||||||
return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) referenceExpression, context);
|
return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) referenceExpression, context);
|
||||||
}
|
}
|
||||||
assert referenceExpression instanceof JetArrayAccessExpression;
|
assert referenceExpression instanceof JetArrayAccessExpression;
|
||||||
return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context);
|
return getArrayAccessTranslator((JetArrayAccessExpression) referenceExpression, context, forceOrderOfEvaluation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static AccessTranslator getArrayAccessTranslator(
|
||||||
|
@NotNull JetArrayAccessExpression expression,
|
||||||
|
@NotNull TranslationContext context,
|
||||||
|
boolean forceOrderOfEvaluation
|
||||||
|
) {
|
||||||
|
TranslationContext accessArrayContext;
|
||||||
|
if (forceOrderOfEvaluation) {
|
||||||
|
Map<JetExpression, JsExpression> indexesMap = new LinkedHashMap<JetExpression, JsExpression>();
|
||||||
|
for(JetExpression indexExpression : expression.getIndexExpressions()) {
|
||||||
|
JsExpression jsIndexExpression = Translation.translateAsExpression(indexExpression, context);
|
||||||
|
if (TranslationUtils.isCacheNeeded(jsIndexExpression)) {
|
||||||
|
TemporaryVariable temporaryVariable = context.declareTemporary(null);
|
||||||
|
context.addStatementToCurrentBlock(JsAstUtils.assignment(temporaryVariable.reference(), jsIndexExpression).makeStmt());
|
||||||
|
jsIndexExpression = temporaryVariable.reference();
|
||||||
|
}
|
||||||
|
indexesMap.put(indexExpression, jsIndexExpression);
|
||||||
|
}
|
||||||
|
accessArrayContext = context.innerContextWithAliasesForExpressions(indexesMap);
|
||||||
|
} else {
|
||||||
|
accessArrayContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ArrayAccessTranslator.newInstance(expression, accessArrayContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+56
-4
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.psi.JetExpression;
|
|||||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||||
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
|
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
|
||||||
|
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.k2js.translate.general.Translation;
|
import org.jetbrains.k2js.translate.general.Translation;
|
||||||
@@ -42,8 +43,21 @@ public class CallArgumentTranslator extends AbstractTranslator {
|
|||||||
@Nullable JsExpression receiver,
|
@Nullable JsExpression receiver,
|
||||||
@NotNull TranslationContext context
|
@NotNull TranslationContext context
|
||||||
) {
|
) {
|
||||||
CallArgumentTranslator argumentTranslator = new CallArgumentTranslator(resolvedCall, receiver, context);
|
return translate(resolvedCall, receiver, context, context.dynamicContext().jsBlock());
|
||||||
return argumentTranslator.translate();
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static ArgumentsInfo translate(
|
||||||
|
@NotNull ResolvedCall<?> resolvedCall,
|
||||||
|
@Nullable JsExpression receiver,
|
||||||
|
@NotNull TranslationContext context,
|
||||||
|
@NotNull JsBlock block
|
||||||
|
) {
|
||||||
|
TranslationContext innerContext = context.innerBlock(block);
|
||||||
|
CallArgumentTranslator argumentTranslator = new CallArgumentTranslator(resolvedCall, receiver, innerContext);
|
||||||
|
ArgumentsInfo result = argumentTranslator.translate();
|
||||||
|
context.moveVarsFrom(innerContext);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ArgumentsInfo {
|
public static class ArgumentsInfo {
|
||||||
@@ -115,10 +129,38 @@ public class CallArgumentTranslator extends AbstractTranslator {
|
|||||||
else {
|
else {
|
||||||
list = result;
|
list = result;
|
||||||
}
|
}
|
||||||
|
List<TranslationContext> argContexts = new SmartList<TranslationContext>();
|
||||||
|
boolean argumentsShouldBeExtractedToTmpVars = false;
|
||||||
for (ValueArgument argument : arguments) {
|
for (ValueArgument argument : arguments) {
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||||
assert argumentExpression != null;
|
assert argumentExpression != null;
|
||||||
list.add(Translation.translateAsExpression(argumentExpression, context));
|
TranslationContext argContext = context.innerBlock();
|
||||||
|
JsExpression argExpression = Translation.translateAsExpression(argumentExpression, argContext);
|
||||||
|
list.add(argExpression);
|
||||||
|
context.moveVarsFrom(argContext);
|
||||||
|
argContexts.add(argContext);
|
||||||
|
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty();
|
||||||
|
}
|
||||||
|
if (argumentsShouldBeExtractedToTmpVars) {
|
||||||
|
extractArgumentsToTmpVars(list, argContexts, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractArgumentsToTmpVars(
|
||||||
|
@NotNull List<JsExpression> argExpressions,
|
||||||
|
@NotNull List<TranslationContext> argContexts,
|
||||||
|
@NotNull TranslationContext context
|
||||||
|
) {
|
||||||
|
for(int i=0; i<argExpressions.size(); i++) {
|
||||||
|
TranslationContext argContext = argContexts.get(i);
|
||||||
|
JsExpression jsArgExpression = argExpressions.get(i);
|
||||||
|
if (argContext.currentBlockIsEmpty()) {
|
||||||
|
TemporaryVariable temporaryVariable = context.declareTemporary(jsArgExpression);
|
||||||
|
context.addStatementToCurrentBlock(temporaryVariable.assignmentExpression().makeStmt());
|
||||||
|
argExpressions.set(i, temporaryVariable.reference());
|
||||||
|
} else {
|
||||||
|
context.addStatementsToCurrentBlockFrom(argContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +205,9 @@ public class CallArgumentTranslator extends AbstractTranslator {
|
|||||||
throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor());
|
throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor());
|
||||||
}
|
}
|
||||||
List<JsExpression> argsBeforeVararg = null;
|
List<JsExpression> argsBeforeVararg = null;
|
||||||
|
boolean argumentsShouldBeExtractedToTmpVars = false;
|
||||||
|
List<TranslationContext> argContexts = new SmartList<TranslationContext>();
|
||||||
|
|
||||||
for (ValueParameterDescriptor parameterDescriptor : valueParameters) {
|
for (ValueParameterDescriptor parameterDescriptor : valueParameters) {
|
||||||
ResolvedValueArgument actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex());
|
ResolvedValueArgument actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex());
|
||||||
|
|
||||||
@@ -177,8 +222,15 @@ public class CallArgumentTranslator extends AbstractTranslator {
|
|||||||
result = new SmartList<JsExpression>();
|
result = new SmartList<JsExpression>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TranslationContext argContext = context().innerBlock();
|
||||||
|
translateSingleArgument(actualArgument, result, argContext, !isNativeFunctionCall && !hasSpreadOperator);
|
||||||
|
context().moveVarsFrom(argContext);
|
||||||
|
argContexts.add(argContext);
|
||||||
|
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
translateSingleArgument(actualArgument, result, context(), !isNativeFunctionCall && !hasSpreadOperator);
|
if (argumentsShouldBeExtractedToTmpVars) {
|
||||||
|
extractArgumentsToTmpVars(result, argContexts, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNativeFunctionCall && hasSpreadOperator) {
|
if (isNativeFunctionCall && hasSpreadOperator) {
|
||||||
|
|||||||
+8
-1
@@ -22,8 +22,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.k2js.translate.utils.ErrorReportingUtils;
|
import org.jetbrains.k2js.translate.utils.ErrorReportingUtils;
|
||||||
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
|
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
|
||||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||||
@@ -37,8 +39,13 @@ public final class QualifiedExpressionTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static AccessTranslator getAccessTranslator(@NotNull JetQualifiedExpression expression,
|
public static AccessTranslator getAccessTranslator(@NotNull JetQualifiedExpression expression,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context, boolean forceOrderOfEvaluation) {
|
||||||
JsExpression receiver = translateReceiver(expression, context);
|
JsExpression receiver = translateReceiver(expression, context);
|
||||||
|
if (forceOrderOfEvaluation && receiver != null) {
|
||||||
|
TemporaryVariable temporaryVariable = context.declareTemporary(null);
|
||||||
|
context.addStatementToCurrentBlock(JsAstUtils.assignment(temporaryVariable.reference(), receiver).makeStmt());
|
||||||
|
receiver = temporaryVariable.reference();
|
||||||
|
}
|
||||||
return VariableAccessTranslator.newInstance(context, getNotNullSimpleNameSelector(expression), receiver);
|
return VariableAccessTranslator.newInstance(context, getNotNullSimpleNameSelector(expression), receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,10 +55,12 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
|||||||
if (valueParameter.hasDefaultValue()) {
|
if (valueParameter.hasDefaultValue()) {
|
||||||
JsNameRef jsNameRef = functionBodyContext.getNameForDescriptor(valueParameter).makeRef();
|
JsNameRef jsNameRef = functionBodyContext.getNameForDescriptor(valueParameter).makeRef();
|
||||||
JetExpression defaultArgument = getDefaultArgument(valueParameter);
|
JetExpression defaultArgument = getDefaultArgument(valueParameter);
|
||||||
JsExpression defaultValue = Translation.translateAsExpression(defaultArgument, functionBodyContext);
|
JsBlock defaultArgBlock = new JsBlock();
|
||||||
|
JsExpression defaultValue = Translation.translateAsExpression(defaultArgument, functionBodyContext, defaultArgBlock);
|
||||||
|
JsStatement assignStatement = assignment(jsNameRef, defaultValue).makeStmt();
|
||||||
|
JsStatement thenStatement = JsAstUtils.mergeStatementInBlockIfNeeded(assignStatement, defaultArgBlock);
|
||||||
JsBinaryOperation checkArgIsUndefined = equality(jsNameRef, functionBodyContext.namer().getUndefinedExpression());
|
JsBinaryOperation checkArgIsUndefined = equality(jsNameRef, functionBodyContext.namer().getUndefinedExpression());
|
||||||
JsIf jsIf = new JsIf(checkArgIsUndefined, assignment(jsNameRef, defaultValue).makeStmt());
|
JsIf jsIf = new JsIf(checkArgIsUndefined, thenStatement);
|
||||||
result.add(jsIf);
|
result.add(jsIf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,16 @@ import com.intellij.util.SmartList;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.k2js.translate.context.Namer;
|
import org.jetbrains.k2js.translate.context.Namer;
|
||||||
|
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
|
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression;
|
||||||
|
|
||||||
public final class JsAstUtils {
|
public final class JsAstUtils {
|
||||||
private static final JsNameRef DEFINE_PROPERTY = new JsNameRef("defineProperty");
|
private static final JsNameRef DEFINE_PROPERTY = new JsNameRef("defineProperty");
|
||||||
public static final JsNameRef CREATE_OBJECT = new JsNameRef("create");
|
public static final JsNameRef CREATE_OBJECT = new JsNameRef("create");
|
||||||
@@ -61,13 +65,43 @@ public final class JsAstUtils {
|
|||||||
if (jsNode instanceof JsBlock) {
|
if (jsNode instanceof JsBlock) {
|
||||||
return (JsBlock) jsNode;
|
return (JsBlock) jsNode;
|
||||||
}
|
}
|
||||||
return new JsBlock(convertToStatement(jsNode));
|
JsBlock block = new JsBlock();
|
||||||
|
block.getStatements().add(convertToStatement(jsNode));
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression convertToExpression(@NotNull JsNode jsNode) {
|
public static JsExpression convertToExpression(@NotNull JsNode jsNode, @NotNull TranslationContext context) {
|
||||||
assert jsNode instanceof JsExpression : "Unexpected node of type: " + jsNode.getClass().toString();
|
return convertToExpression(jsNode, context, context.dynamicContext().jsBlock());
|
||||||
return (JsExpression) jsNode;
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsExpression convertToExpression(@NotNull JsNode jsNode, @NotNull TranslationContext context, @NotNull JsBlock block) {
|
||||||
|
if (jsNode instanceof JsExpression) {
|
||||||
|
return (JsExpression) jsNode;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert jsNode instanceof JsStatement : "Unexpected node of type: " + jsNode.getClass().toString();
|
||||||
|
TemporaryVariable result = context.declareTemporary(null);
|
||||||
|
AssignToExpressionMutator saveResultToTemporaryMutator = new AssignToExpressionMutator(result.reference());
|
||||||
|
block.getStatements().add(mutateLastExpression(jsNode, saveResultToTemporaryMutator));
|
||||||
|
return result.reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static JsExpression extractExpressionFromStatement(@Nullable JsStatement statement) {
|
||||||
|
return statement instanceof JsExpressionStatement ? ((JsExpressionStatement) statement).getExpression() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsStatement mergeStatementInBlockIfNeeded(@NotNull JsStatement statement, @NotNull JsBlock block) {
|
||||||
|
if (block.isEmpty()) {
|
||||||
|
return statement;
|
||||||
|
} else {
|
||||||
|
block.getStatements().add(statement);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.k2js.translate.utils;
|
package org.jetbrains.k2js.translate.utils;
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
import com.google.dart.compiler.backend.js.ast.*;
|
||||||
import com.intellij.openapi.util.Pair;
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.util.Function;
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
@@ -40,8 +39,7 @@ import static com.google.dart.compiler.backend.js.ast.JsBinaryOperator.*;
|
|||||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
|
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
|
||||||
import static org.jetbrains.k2js.translate.context.Namer.getKotlinBackingFieldName;
|
import static org.jetbrains.k2js.translate.context.Namer.getKotlinBackingFieldName;
|
||||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor;
|
|
||||||
|
|
||||||
public final class TranslationUtils {
|
public final class TranslationUtils {
|
||||||
public static final Comparator<FunctionDescriptor> OVERLOADED_FUNCTION_COMPARATOR = new OverloadedFunctionComparator();
|
public static final Comparator<FunctionDescriptor> OVERLOADED_FUNCTION_COMPARATOR = new OverloadedFunctionComparator();
|
||||||
@@ -344,17 +342,34 @@ public final class TranslationUtils {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression translateLeftExpression(@NotNull TranslationContext context,
|
public static JsExpression translateLeftExpression(@NotNull TranslationContext context,
|
||||||
@NotNull JetBinaryExpression expression) {
|
@NotNull JetBinaryExpression expression) {
|
||||||
|
return translateLeftExpression(context, expression, context.dynamicContext().jsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsExpression translateLeftExpression(
|
||||||
|
@NotNull TranslationContext context,
|
||||||
|
@NotNull JetBinaryExpression expression,
|
||||||
|
@NotNull JsBlock block
|
||||||
|
) {
|
||||||
JetExpression left = expression.getLeft();
|
JetExpression left = expression.getLeft();
|
||||||
assert left != null : "Binary expression should have a left expression: " + expression.getText();
|
assert left != null : "Binary expression should have a left expression: " + expression.getText();
|
||||||
return Translation.translateAsExpression(left, context);
|
return Translation.translateAsExpression(left, context, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression translateRightExpression(@NotNull TranslationContext context,
|
public static JsExpression translateRightExpression(@NotNull TranslationContext context,
|
||||||
@NotNull JetBinaryExpression expression) {
|
@NotNull JetBinaryExpression expression) {
|
||||||
|
return translateRightExpression(context, expression, context.dynamicContext().jsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsExpression translateRightExpression(
|
||||||
|
@NotNull TranslationContext context,
|
||||||
|
@NotNull JetBinaryExpression expression,
|
||||||
|
@NotNull JsBlock block) {
|
||||||
JetExpression rightExpression = expression.getRight();
|
JetExpression rightExpression = expression.getRight();
|
||||||
assert rightExpression != null : "Binary expression should have a right expression";
|
assert rightExpression != null : "Binary expression should have a right expression";
|
||||||
return Translation.translateAsExpression(rightExpression, context);
|
return Translation.translateAsExpression(rightExpression, context, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasCorrespondingFunctionIntrinsic(@NotNull TranslationContext context,
|
public static boolean hasCorrespondingFunctionIntrinsic(@NotNull TranslationContext context,
|
||||||
@@ -384,20 +399,6 @@ public final class TranslationUtils {
|
|||||||
(!(expression instanceof JsNameRef) || ((JsNameRef) expression).getQualifier() != null);
|
(!(expression instanceof JsNameRef) || ((JsNameRef) expression).getQualifier() != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static Pair<JsVars.JsVar, JsExpression> createTemporaryIfNeed(
|
|
||||||
@NotNull JsExpression expression,
|
|
||||||
@NotNull TranslationContext context
|
|
||||||
) {
|
|
||||||
// don't create temp variable for simple expression
|
|
||||||
if (isCacheNeeded(expression)) {
|
|
||||||
return context.dynamicContext().createTemporary(expression);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Pair.create(null, expression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsConditional sure(@NotNull JsExpression expression, @NotNull TranslationContext context) {
|
public static JsConditional sure(@NotNull JsExpression expression, @NotNull TranslationContext context) {
|
||||||
JsInvocation throwNPE = new JsInvocation(context.namer().throwNPEFunctionRef());
|
JsInvocation throwNPE = new JsInvocation(context.namer().throwNPEFunctionRef());
|
||||||
|
|||||||
@@ -1,127 +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.utils.dangerous;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetBlockExpression;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module uses a methaphor for naming.
|
|
||||||
* <p/>
|
|
||||||
* Dangerous are the nodes that can be expressions in Kotlin but can't be expressions in JavaScript.
|
|
||||||
* These are: when, if, inlined functions.
|
|
||||||
* The issue with them is that we have to translate them to a list of statements. And also all the expressions which must be computed before
|
|
||||||
* the dangerous expressions.
|
|
||||||
* RootNode is a node which contains such an expression. For example, it may be a statement expression belongs to.
|
|
||||||
*/
|
|
||||||
public class DangerousData {
|
|
||||||
@NotNull
|
|
||||||
private final List<JetExpression> nodesToBeGeneratedBefore = Lists.newArrayList();
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static DangerousData collect(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
|
||||||
if (cantContainDangerousElements(expression)) {
|
|
||||||
return emptyData();
|
|
||||||
}
|
|
||||||
return doCollectData(expression, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean cantContainDangerousElements(@NotNull JetElement element) {
|
|
||||||
return element instanceof JetBlockExpression;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static DangerousData doCollectData(@NotNull JetExpression expression,
|
|
||||||
@NotNull TranslationContext context) {
|
|
||||||
DangerousData data = new DangerousData();
|
|
||||||
FindDangerousVisitor visitor = new FindDangerousVisitor(context);
|
|
||||||
expression.accept(visitor, data);
|
|
||||||
if (!data.exists()) {
|
|
||||||
return emptyData();
|
|
||||||
}
|
|
||||||
data.setRootNode(expression);
|
|
||||||
FindPreviousVisitor findPreviousVisitor = new FindPreviousVisitor(data);
|
|
||||||
expression.accept(findPreviousVisitor, data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final DangerousData EMPTY = new DangerousData() {
|
|
||||||
@Override
|
|
||||||
public boolean exists() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldBeTranslated() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static DangerousData emptyData() {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private JetExpression dangerousNode = null;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private JetExpression rootNode = null;
|
|
||||||
|
|
||||||
public void setDangerousNode(@NotNull JetExpression dangerousNode) {
|
|
||||||
assert this.dangerousNode == null : "Should be assigned only once";
|
|
||||||
this.dangerousNode = dangerousNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public List<JetExpression> getNodesToBeGeneratedBefore() {
|
|
||||||
return nodesToBeGeneratedBefore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean exists() {
|
|
||||||
return dangerousNode != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldBeTranslated() {
|
|
||||||
return exists() && !nodesToBeGeneratedBefore.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JetExpression getDangerousNode() {
|
|
||||||
assert dangerousNode != null;
|
|
||||||
return dangerousNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JetExpression getRootNode() {
|
|
||||||
assert rootNode != null;
|
|
||||||
return rootNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("NullableProblems")
|
|
||||||
public void setRootNode(@NotNull JetExpression rootNode) {
|
|
||||||
this.rootNode = rootNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-69
@@ -1,69 +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.utils.dangerous;
|
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsNode;
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsVars;
|
|
||||||
import gnu.trove.THashMap;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
|
||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
|
||||||
import org.jetbrains.k2js.translate.general.Translation;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class DangerousTranslator extends AbstractTranslator {
|
|
||||||
@NotNull
|
|
||||||
private final DangerousData data;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static JsNode translate(@NotNull DangerousData data, @NotNull TranslationContext context) {
|
|
||||||
assert data.exists();
|
|
||||||
return new DangerousTranslator(data, context).translate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private DangerousTranslator(@NotNull DangerousData data, @NotNull TranslationContext context) {
|
|
||||||
super(context);
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private JsNode translate() {
|
|
||||||
Map<JetExpression, JsExpression> aliasesForExpressions =
|
|
||||||
translateAllExpressionsAndCreateAliasesForThem(data.getNodesToBeGeneratedBefore());
|
|
||||||
TranslationContext contextWithAliases = context().innerContextWithAliasesForExpressions(aliasesForExpressions);
|
|
||||||
return Translation.doTranslateExpression(data.getRootNode(), contextWithAliases);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Map<JetExpression, JsExpression> translateAllExpressionsAndCreateAliasesForThem(@NotNull List<JetExpression> expressions) {
|
|
||||||
Map<JetExpression, JsExpression> aliasesForExpressions = new THashMap<JetExpression, JsExpression>(expressions.size());
|
|
||||||
List<JsVars.JsVar> vars = new ArrayList<JsVars.JsVar>(expressions.size());
|
|
||||||
for (JetExpression expression : expressions) {
|
|
||||||
JsExpression translatedExpression = Translation.translateAsExpression(expression, context());
|
|
||||||
JsVars.JsVar aliasForExpression = context().dynamicContext().createTemporaryVar(translatedExpression);
|
|
||||||
vars.add(aliasForExpression);
|
|
||||||
aliasesForExpressions.put(expression, aliasForExpression.getName().makeRef());
|
|
||||||
}
|
|
||||||
context().addStatementToCurrentBlock(new JsVars(vars, true));
|
|
||||||
return aliasesForExpressions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-90
@@ -1,90 +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.utils.dangerous;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
|
||||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
|
||||||
import org.jetbrains.k2js.translate.reference.InlinedCallExpressionTranslator;
|
|
||||||
|
|
||||||
public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final TranslationContext context;
|
|
||||||
|
|
||||||
public FindDangerousVisitor(@NotNull TranslationContext context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitDeclaration(@NotNull JetDeclaration dcl, DangerousData data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitJetElement(@NotNull JetElement element, DangerousData data) {
|
|
||||||
if (data.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return super.visitJetElement(element, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitWhenExpression(@NotNull JetWhenExpression expression, DangerousData data) {
|
|
||||||
if (expressionFound(expression, data)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return super.visitWhenExpression(expression, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitIfExpression(@NotNull JetIfExpression expression, DangerousData data) {
|
|
||||||
if (expressionFound(expression, data)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return super.visitIfExpression(expression, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitBlockExpression(@NotNull JetBlockExpression expression, DangerousData data) {
|
|
||||||
return BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())
|
|
||||||
? null
|
|
||||||
: super.visitBlockExpression(expression, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitCallExpression(@NotNull JetCallExpression expression, DangerousData data) {
|
|
||||||
if (InlinedCallExpressionTranslator.shouldBeInlined(expression, context)) {
|
|
||||||
if (expressionFound(expression, data)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.visitCallExpression(expression, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean expressionFound(@NotNull JetExpression expression, @NotNull DangerousData data) {
|
|
||||||
if (data.exists()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())) {
|
|
||||||
data.setDangerousNode(expression);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-129
@@ -1,129 +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.utils.dangerous;
|
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression;
|
|
||||||
|
|
||||||
//TODO: refactor
|
|
||||||
public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Map<JetElement, Void> hasDangerous = Maps.newHashMap();
|
|
||||||
|
|
||||||
public FindPreviousVisitor(@NotNull DangerousData data) {
|
|
||||||
JetElement node = data.getDangerousNode();
|
|
||||||
PsiElement last = data.getRootNode().getParent();
|
|
||||||
while (node != last) {
|
|
||||||
hasDangerous.put(node, null);
|
|
||||||
PsiElement parent = node.getParent();
|
|
||||||
assert parent instanceof JetElement;
|
|
||||||
node = (JetElement)parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitJetElement(@NotNull JetElement element, DangerousData data) {
|
|
||||||
if (data.getDangerousNode() == element) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!hasDangerous(element)) {
|
|
||||||
addElement(element, data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
acceptChildrenThatAreBeforeTheDangerousNode(element, data);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: return value not used, wtf?
|
|
||||||
private static boolean addElement(@NotNull JetElement element, @NotNull DangerousData data) {
|
|
||||||
if (element instanceof JetExpression) {
|
|
||||||
data.getNodesToBeGeneratedBefore().add((JetExpression)element);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void acceptChildrenThatAreBeforeTheDangerousNode(@NotNull JetElement element, @NotNull DangerousData data) {
|
|
||||||
PsiElement current = element.getFirstChild();
|
|
||||||
while (current != null) {
|
|
||||||
if (current instanceof JetElement) {
|
|
||||||
((JetElement)current).accept(this, data);
|
|
||||||
if (hasDangerous(element)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = current.getNextSibling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitPrefixExpression(@NotNull JetPrefixExpression expression, @NotNull DangerousData data) {
|
|
||||||
if (data.getDangerousNode() == expression) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!hasDangerous(expression)) {
|
|
||||||
addElement(expression, data);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (hasDangerous(getBaseExpression(expression))) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//TODO:
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitCallExpression(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
|
|
||||||
if (data.getDangerousNode() == expression) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!hasDangerous(expression)) {
|
|
||||||
data.getNodesToBeGeneratedBefore().add(expression);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
acceptArgumentsThatAreBeforeDangerousNode(expression, data);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void acceptArgumentsThatAreBeforeDangerousNode(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
|
|
||||||
for (ValueArgument argument : expression.getValueArguments()) {
|
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
|
||||||
assert argumentExpression != null;
|
|
||||||
argumentExpression.accept(this, data);
|
|
||||||
if (hasDangerous(argumentExpression)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasDangerous(@NotNull JetElement element) {
|
|
||||||
return hasDangerous.containsKey(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+12
@@ -45,6 +45,9 @@ public final class LastExpressionMutator {
|
|||||||
if (node instanceof JsIf) {
|
if (node instanceof JsIf) {
|
||||||
return applyToIf((JsIf) node);
|
return applyToIf((JsIf) node);
|
||||||
}
|
}
|
||||||
|
if (node instanceof JsTry) {
|
||||||
|
return applyToTry((JsTry) node);
|
||||||
|
}
|
||||||
if (node instanceof JsExpressionStatement) {
|
if (node instanceof JsExpressionStatement) {
|
||||||
return applyToStatement((JsExpressionStatement) node);
|
return applyToStatement((JsExpressionStatement) node);
|
||||||
}
|
}
|
||||||
@@ -66,6 +69,15 @@ public final class LastExpressionMutator {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private JsNode applyToTry(@NotNull JsTry node) {
|
||||||
|
applyToBlock(node.getTryBlock());
|
||||||
|
for(JsCatch jsCatch: node.getCatches()) {
|
||||||
|
applyToBlock(jsCatch.getBody());
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsNode applyToBlock(@NotNull JsBlock node) {
|
private JsNode applyToBlock(@NotNull JsBlock node) {
|
||||||
List<JsStatement> statements = node.getStatements();
|
List<JsStatement> statements = node.getStatements();
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
// http://youtrack.jetbrains.com/issue/KT-4879
|
||||||
|
// JS: extra side effect when use when in default arguments
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun bar(): Int {
|
||||||
|
global += ":bar:"
|
||||||
|
return 100
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(a: Int = when { else -> bar() }): Int = a + 1
|
||||||
|
|
||||||
|
fun bar0(x: String = try { global } finally {}): String {
|
||||||
|
return "bar: ${x}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
global = ""
|
||||||
|
assertEquals(101, foo(100))
|
||||||
|
assertEquals("", global)
|
||||||
|
|
||||||
|
assertEquals(101, foo())
|
||||||
|
assertEquals(":bar:", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun bar(s: String, value: Boolean): Boolean {
|
||||||
|
global += s
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
// Simple && Simple
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", true) && bar("B", true))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", true) && bar("B", false))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", false) && bar("B", true))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", false) && bar("B", false))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
// Simple && Complex
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", true) && try { bar("B", true) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", true) && try { bar("B", false) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", false) && try { bar("B", true) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", false) && try { bar("B", false) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
// Complex && Simple
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", true) } finally {} && bar("B", true))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", true) } finally {} && bar("B", false))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", false) } finally {} && bar("B", true))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", false) } finally {} && bar("B", false))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
// Complex && Complex
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", true) } finally {} && try { bar("B", true) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", true) } finally {} && try { bar("B", false) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", false) } finally {} && try { bar("B", true) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", false) } finally {} && try { bar("B", false) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
class A {
|
||||||
|
var prop: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(s: String, index: Int): Int {
|
||||||
|
global += s
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
val baz: Int
|
||||||
|
get() {
|
||||||
|
global += ":baz:"; return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = array(0,1,2,3)
|
||||||
|
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)] = try { global += "B"; 10 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(10, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)] += try { global += "B"; 10 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(20, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)] -= try { global += "B"; 10 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(10, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)] *= try { global += "B"; 2 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(20, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)] /= try { global += "B"; 5 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(4, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)] %= try { global += "B"; 3 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(1, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[bar("A", 1)]++
|
||||||
|
assertEquals("A", global)
|
||||||
|
assertEquals(2, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[try { bar("A", 1)} finally {}]++
|
||||||
|
assertEquals("A", global)
|
||||||
|
assertEquals(3, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
++a[bar("A", 1)]
|
||||||
|
assertEquals("A", global)
|
||||||
|
assertEquals(4, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
++a[try { bar("A", 1)} finally {}]
|
||||||
|
assertEquals("A", global)
|
||||||
|
assertEquals(5, a[1])
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
a[baz] = try { global += "right"; 100 } finally {}
|
||||||
|
assertEquals(":baz:right", global)
|
||||||
|
assertEquals(100, a[1])
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
class A {
|
||||||
|
var prop: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(s: String, a: A): A {
|
||||||
|
global += s
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
bar("A", a).prop = try { global += "B"; 10 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(10, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
bar("A", a).prop += try { global += "B"; 20 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(30, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
bar("A", a).prop -= try { global += "B"; 20 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(10, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
bar("A", a).prop *= try { global += "B"; 2 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(20, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
bar("A", a).prop /= try { global += "B"; 5 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(4, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
bar("A", a).prop %= try { global += "B"; 3 } finally {}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
assertEquals(1, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
(try { bar("A", a) } finally {}).prop++
|
||||||
|
assertEquals("A", global)
|
||||||
|
assertEquals(2, a.prop)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
++(try { bar("A", a) } finally {}).prop
|
||||||
|
assertEquals("A", global)
|
||||||
|
assertEquals(3, a.prop)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global = ""
|
||||||
|
|
||||||
|
fun addToGlobal(s: String): String {
|
||||||
|
global += s
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(s: String, u: Int) { global += ":bar:${s}" }
|
||||||
|
|
||||||
|
class A() {
|
||||||
|
fun memFun(s: String) { global += ":memFun:${s}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
class B() {
|
||||||
|
fun A.bExt(s: String) { global += ":bExt:${s}" }
|
||||||
|
|
||||||
|
fun baz(s: String, a: A) = a.bExt(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.extFun(s: String) { global += ":extFun:${s}" }
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
bar(addToGlobal("A"), try { global += "B"; 10 } finally {})
|
||||||
|
assertEquals("AB:bar:", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
val a = A()
|
||||||
|
a.memFun(try { "A" } finally {})
|
||||||
|
assertEquals(":memFun:A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
(try { global += "A"; a } finally {}).memFun("B")
|
||||||
|
assertEquals("A:memFun:B", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
(try { global += "A"; a } finally {}).memFun(try { global += "B"; "C" } finally {})
|
||||||
|
assertEquals("AB:memFun:C", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
val b = B()
|
||||||
|
b.baz("S", a)
|
||||||
|
assertEquals(":bExt:S", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun bar(s: String, value: Int): Int {
|
||||||
|
global += s
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun baz(vararg args: Int): String {
|
||||||
|
return "baz: ${args.size}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
baz(bar("A", 10), try { global += "B"; 20} finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
baz(bar("A", 10), 30, if (true) { while(false){}; global+= "B"; 20 } else { 50 })
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun bar(s: String): String {
|
||||||
|
global += s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A") < bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A") <= bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A") > bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A") >= bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A") < try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A") <= try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A") } finally {} > bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A") } finally {} >= bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A") } finally {} < try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A") } finally {} <= try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A") } finally {} > try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A") } finally {} >= try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var sideEffect: Int = 0;
|
||||||
|
|
||||||
|
class A(val x: Int)
|
||||||
|
|
||||||
|
val global_a = A(1)
|
||||||
|
val global_b = A(2)
|
||||||
|
|
||||||
|
fun nullFun(value: Boolean): Any? = if (value) null else global_a
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
nullFun(false) ?: global_b
|
||||||
|
assertEquals(global_a, nullFun(false) ?: try { ++sideEffect; global_b } finally {}, "false, global_b")
|
||||||
|
assertEquals(0, sideEffect, "false, global_b side effect")
|
||||||
|
|
||||||
|
assertEquals(global_b, nullFun(true) ?: try { ++sideEffect; global_b } finally {}, "true, global_b")
|
||||||
|
assertEquals(1, sideEffect, "true, global_b side effect")
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun bar(s: String): String {
|
||||||
|
global += s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A") == bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A") != bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A") == try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A") != try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A") } finally {} == bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A") } finally {} != bar("B"))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A") } finally {} == try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A") } finally {} != try { bar("B") } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Order of evaluation differs for JVM and Javascript backend
|
||||||
|
// http://youtrack.jetbrains.com/issue/KT-5254
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
var s = ""
|
||||||
|
|
||||||
|
fun a():String {
|
||||||
|
s += "A"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun b():String {
|
||||||
|
s += "B"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun c():String {
|
||||||
|
s += "C"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var res = (if(true) {a()} else "") + b() + (if (true) {c()} else "")
|
||||||
|
assertEquals("ABC", s)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var sideEffect: Int = 0;
|
||||||
|
|
||||||
|
fun id(value: Boolean): Boolean = value
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
assertEquals(if (id(true)) try { ++sideEffect; 10 } finally {} else 20, 10)
|
||||||
|
assertEquals(1, sideEffect)
|
||||||
|
|
||||||
|
assertEquals(if (id(false)) try { ++sideEffect; 10 } finally {} else 20, 20)
|
||||||
|
assertEquals(1, sideEffect)
|
||||||
|
|
||||||
|
assertEquals(if (id(true)) 100 else try { ++sideEffect; 200 } finally {}, 100)
|
||||||
|
assertEquals(1, sideEffect)
|
||||||
|
|
||||||
|
assertEquals(if (id(false)) 100 else try { ++sideEffect; 200 } finally {}, 200)
|
||||||
|
assertEquals(2, sideEffect)
|
||||||
|
|
||||||
|
assertEquals(if (id(true)) try { ++sideEffect; 1000 } finally {} else try { ++sideEffect; 2000 } finally {}, 1000)
|
||||||
|
assertEquals(3, sideEffect)
|
||||||
|
|
||||||
|
assertEquals(if (id(false)) try { ++sideEffect; 1000 } finally {} else try { ++sideEffect; 2000 } finally {}, 2000)
|
||||||
|
assertEquals(4, sideEffect)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var x = 0
|
||||||
|
assertEquals(false, ++x > x)
|
||||||
|
assertEquals(false, ++x > try {x} finally {})
|
||||||
|
|
||||||
|
assertEquals(false, x++ > x)
|
||||||
|
assertEquals(false, x++ > try {x} finally {})
|
||||||
|
|
||||||
|
assertEquals(true, ++x == x)
|
||||||
|
assertEquals(true, ++x == try {x} finally {})
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun bar(s: String, value: Boolean): Boolean {
|
||||||
|
global += s
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
// Simple || Simple
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", true) || bar("B", true))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", true) || bar("B", false))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", false) || bar("B", true))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", false) || bar("B", false))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
// Simple || Complex
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", true) || try { bar("B", true) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", true) || try { bar("B", false) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, bar("A", false) || try { bar("B", true) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, bar("A", false) || try { bar("B", false) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
// Complex || Simple
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", true) } finally {} || bar("B", true))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", true) } finally {} || bar("B", false))
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", false) } finally {} || bar("B", true))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", false) } finally {} || bar("B", false))
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
// Complex || Complex
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", true) } finally {} || try { bar("B", true) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", true) } finally {} || try { bar("B", false) } finally {})
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(true, try { bar("A", false) } finally {} || try { bar("B", true) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
assertEquals(false, try { bar("A", false) } finally {} || try { bar("B", false) } finally {})
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
var global: String = ""
|
||||||
|
|
||||||
|
fun id(s: String, value: Boolean): Boolean {
|
||||||
|
global += s
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
when {
|
||||||
|
id("A", true), id("B", true) -> 10
|
||||||
|
}
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
when {
|
||||||
|
id("A", false), id("B", true), id("C", true) -> 10
|
||||||
|
}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
var b = true
|
||||||
|
when {
|
||||||
|
try { global += "A"; b } finally {} -> 10
|
||||||
|
try { global += "B"; !b } finally {} -> 20
|
||||||
|
}
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
b = false
|
||||||
|
when {
|
||||||
|
try { global += "A"; b } finally {} -> 10
|
||||||
|
try { global += "B"; !b } finally {} -> 20
|
||||||
|
}
|
||||||
|
assertEquals("AB", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
b = true
|
||||||
|
when {
|
||||||
|
b, try { global += "A"; !b } finally {} -> 10
|
||||||
|
}
|
||||||
|
assertEquals("", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
b = false
|
||||||
|
when {
|
||||||
|
b, try { global += "A"; !b } finally {} -> 10
|
||||||
|
}
|
||||||
|
assertEquals("A", global)
|
||||||
|
|
||||||
|
global = ""
|
||||||
|
when {
|
||||||
|
false -> {
|
||||||
|
global += "A"
|
||||||
|
}
|
||||||
|
try { global += "B"; false } finally {} -> {
|
||||||
|
global += "D"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
global += "C"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals("BC", global)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var s: String = ""
|
||||||
|
|
||||||
|
s = ""
|
||||||
|
for(i in 0..2)
|
||||||
|
try { s += "A"} finally {}
|
||||||
|
assertEquals("AAA", s)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// http://youtrack.jetbrains.com/issue/KT-5594
|
||||||
|
// JS: compiler crashes
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
fun bar(f: () -> Unit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
bar {
|
||||||
|
// val actionId: Any = 1
|
||||||
|
val item: Any? = 1
|
||||||
|
if (item != null) {
|
||||||
|
// In original version, as I remember, `when` was an important to reproduce, but now it is not.
|
||||||
|
// when(actionId){
|
||||||
|
// 1 -> { 1 }
|
||||||
|
// "2" -> { "2"}
|
||||||
|
// else -> {}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bar {
|
||||||
|
val actionId: Any = 1
|
||||||
|
val item: Any? = 1
|
||||||
|
if (item != null) {
|
||||||
|
when (actionId) {
|
||||||
|
1 -> {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
"2" -> {
|
||||||
|
"2"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// JS: generate wrong code for nested if
|
||||||
|
// http://youtrack.jetbrains.com/issue/KT-5576
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
fun test2(a: Boolean, b: Boolean, c: Boolean) {
|
||||||
|
val a =
|
||||||
|
if (a) {
|
||||||
|
if (b) {
|
||||||
|
"1"
|
||||||
|
} else if (c) {
|
||||||
|
"2"
|
||||||
|
} else {
|
||||||
|
throw Exception("Rest parameter must be array types")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
|
||||||
|
test2(true, true, false)
|
||||||
|
var wasException = false
|
||||||
|
try {
|
||||||
|
test2(true, false, false)
|
||||||
|
}
|
||||||
|
catch(e: Exception) {
|
||||||
|
wasException = true
|
||||||
|
}
|
||||||
|
assertEquals(true, wasException)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var res = try { 10 } catch(e: Exception) { 20 }
|
||||||
|
assertEquals(10, res)
|
||||||
|
|
||||||
|
res = try { 10 } catch(e: Exception) { 20 } finally { 80 }
|
||||||
|
assertEquals(10, res)
|
||||||
|
|
||||||
|
res = try { 10; throw RuntimeException() } catch(e: Exception) { 20 }
|
||||||
|
assertEquals(20, res)
|
||||||
|
|
||||||
|
res = try { 10; throw RuntimeException() } catch(e: Exception) { 20 } finally { 100 }
|
||||||
|
assertEquals(20, res)
|
||||||
|
|
||||||
|
res = 50 + try { 10 } catch(e: Exception) { 20 }
|
||||||
|
assertEquals(60, res)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var s: String = ""
|
||||||
|
|
||||||
|
var i:Int = 0
|
||||||
|
while(i<2)
|
||||||
|
try { s += "A"; i++} finally {}
|
||||||
|
assertEquals("AA", s)
|
||||||
|
|
||||||
|
s = ""
|
||||||
|
i = 0
|
||||||
|
do
|
||||||
|
try { s += "A"; i++} finally {}
|
||||||
|
while(i<2)
|
||||||
|
assertEquals("AA", s)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user