KT-740: Make sure that assign and increment operations compute receiver only once:
- Increment operation on property.
This commit is contained in:
@@ -53,11 +53,15 @@ public final class MiscTest extends AbstractExpressionTest {
|
||||
checkFooBoxIsTrue("ifAsExpressionWithThrow.kt");
|
||||
fail();
|
||||
} catch (JavaScriptException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testKt1052() throws Exception {
|
||||
checkFooBoxIsTrue("KT1052.kt");
|
||||
}
|
||||
|
||||
|
||||
public void testKt740() throws Exception {
|
||||
checkFooBoxIsTrue("KT-740.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
@NotNull
|
||||
public JsNode visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return AccessTranslator.translateAsGet(expression, context);
|
||||
return AccessTranslationUtils.translateAsGet(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.expression.foreach;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -34,6 +35,7 @@ import java.util.List;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getClassDescriptorForType;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
@@ -78,7 +80,8 @@ public final class ArrayForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
List<JsStatement> blockStatements = temporariesInitialization(loopRange, end);
|
||||
List<JsStatement> blockStatements = Lists.newArrayList();
|
||||
blockStatements.add(temporariesInitialization(loopRange, end).makeStmt());
|
||||
blockStatements.add(generateForExpression(getInitExpression(), getCondition(), getIncrExpression(), getBody()));
|
||||
return newBlock(blockStatements);
|
||||
}
|
||||
|
||||
+4
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.expression.foreach;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -32,6 +33,7 @@ import java.util.List;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getClassDescriptorForType;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
@@ -76,7 +78,8 @@ public final class RangeForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
List<JsStatement> blockStatements = temporariesInitialization(rangeExpression, incrVar, start, end);
|
||||
List<JsStatement> blockStatements = Lists.newArrayList();
|
||||
blockStatements.add(temporariesInitialization(rangeExpression, incrVar, start, end).makeStmt());
|
||||
blockStatements.add(generateForExpression());
|
||||
return newBlock(blockStatements);
|
||||
}
|
||||
|
||||
+4
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.expression.foreach;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
@@ -29,6 +30,7 @@ import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
|
||||
|
||||
@@ -78,7 +80,8 @@ public final class RangeLiteralForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
List<JsStatement> blockStatements = temporariesInitialization(rangeEnd);
|
||||
List<JsStatement> blockStatements = Lists.newArrayList();
|
||||
blockStatements.add(temporariesInitialization(rangeEnd).makeStmt());
|
||||
blockStatements.add(generateForExpression(initExpression(),
|
||||
getCondition(),
|
||||
getIncrExpression(),
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.AccessTranslationUtils;
|
||||
import org.jetbrains.k2js.translate.reference.AccessTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
|
||||
@@ -63,7 +64,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
|
||||
this.accessTranslator = AccessTranslator.getAccessTranslator(expression.getLeft(), context());
|
||||
this.accessTranslator = AccessTranslationUtils.getAccessTranslator(expression.getLeft(), context());
|
||||
this.right = translateRightExpression(context(), expression);
|
||||
}
|
||||
}
|
||||
|
||||
+22
-3
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.operation;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -25,11 +26,16 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.AccessTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.CachedAccessTranslator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.reference.AccessTranslationUtils.getCachedAccessTranslator;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation;
|
||||
|
||||
/**
|
||||
@@ -54,7 +60,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
@NotNull
|
||||
protected final JetUnaryExpression expression;
|
||||
@NotNull
|
||||
protected final AccessTranslator accessTranslator;
|
||||
protected final CachedAccessTranslator accessTranslator;
|
||||
private final boolean isVariableReassignment;
|
||||
|
||||
protected IncrementTranslator(@NotNull JetUnaryExpression expression,
|
||||
@@ -63,11 +69,16 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
this.expression = expression;
|
||||
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
|
||||
JetExpression baseExpression = getBaseExpression(expression);
|
||||
this.accessTranslator = AccessTranslator.getAccessTranslator(baseExpression, context());
|
||||
this.accessTranslator = getCachedAccessTranslator(baseExpression, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translateAsMethodCall() {
|
||||
return withTemporariesInitialized(doTranslateAsMethodCall());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression doTranslateAsMethodCall() {
|
||||
if (returnValueIgnored() || isPrefix(expression)) {
|
||||
return asPrefix();
|
||||
}
|
||||
@@ -122,6 +133,14 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
return accessTranslator.translateAsSet(overloadedMethodCallOnPropertyGetter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression withTemporariesInitialized(@NotNull JsExpression expression) {
|
||||
List<TemporaryVariable> temporaries = accessTranslator.declaredTemporaries();
|
||||
List<JsExpression> expressions = Lists.newArrayList(temporariesInitialization(temporaries));
|
||||
expressions.add(expression);
|
||||
return newSequence(expressions);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class AccessTranslationUtils {
|
||||
private AccessTranslationUtils() {
|
||||
}
|
||||
|
||||
//TODO: this piece of code represents dangerously convoluted logic, think of the ways it can be improved
|
||||
@NotNull
|
||||
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
assert ((referenceExpression instanceof JetReferenceExpression) ||
|
||||
(referenceExpression instanceof JetQualifiedExpression));
|
||||
if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) {
|
||||
if (referenceExpression instanceof JetQualifiedExpression) {
|
||||
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context);
|
||||
}
|
||||
assert referenceExpression instanceof JetSimpleNameExpression;
|
||||
return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression,
|
||||
null, CallType.NORMAL, context);
|
||||
}
|
||||
if (referenceExpression instanceof JetArrayAccessExpression) {
|
||||
return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context);
|
||||
}
|
||||
return ReferenceAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CachedAccessTranslator getCachedAccessTranslator(@NotNull JetExpression referenceExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
return getAccessTranslator(referenceExpression, context).getCached();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsGet(@NotNull JetReferenceExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (getAccessTranslator(expression, context)).translateAsGet();
|
||||
}
|
||||
}
|
||||
@@ -18,51 +18,20 @@ package org.jetbrains.k2js.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Abstract entity for language constructs that you can get/set. Also dispatches to the real implemntation.
|
||||
*/
|
||||
public abstract class AccessTranslator extends AbstractTranslator {
|
||||
|
||||
//TODO: this piece of code represents dangerously convoluted logic, think of the ways it can be improved
|
||||
@NotNull
|
||||
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
assert ((referenceExpression instanceof JetReferenceExpression) ||
|
||||
(referenceExpression instanceof JetQualifiedExpression));
|
||||
if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) {
|
||||
if (referenceExpression instanceof JetQualifiedExpression) {
|
||||
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context);
|
||||
}
|
||||
assert referenceExpression instanceof JetSimpleNameExpression;
|
||||
return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression,
|
||||
null, CallType.NORMAL, context);
|
||||
}
|
||||
if (referenceExpression instanceof JetArrayAccessExpression) {
|
||||
return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context);
|
||||
}
|
||||
return ReferenceAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, context);
|
||||
}
|
||||
|
||||
public interface AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsGet(@NotNull JetReferenceExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (getAccessTranslator(expression, context)).translateAsGet();
|
||||
}
|
||||
JsExpression translateAsGet();
|
||||
|
||||
@NotNull
|
||||
JsExpression translateAsSet(@NotNull JsExpression setTo);
|
||||
|
||||
protected AccessTranslator(@Deprecated TranslationContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public abstract JsExpression translateAsGet();
|
||||
|
||||
public abstract JsExpression translateAsSet(@NotNull JsExpression setTo);
|
||||
|
||||
@NotNull
|
||||
CachedAccessTranslator getCached();
|
||||
}
|
||||
|
||||
+34
-19
@@ -16,25 +16,27 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.reference;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
|
||||
//TODO: inspect not clear how the class handles set and get operations differently
|
||||
public final class ArrayAccessTranslator extends AccessTranslator {
|
||||
public class ArrayAccessTranslator extends AbstractTranslator implements AccessTranslator {
|
||||
|
||||
/*package*/
|
||||
static ArrayAccessTranslator newInstance(@NotNull JetArrayAccessExpression expression,
|
||||
@@ -47,8 +49,8 @@ public final class ArrayAccessTranslator extends AccessTranslator {
|
||||
@NotNull
|
||||
private final FunctionDescriptor methodDescriptor;
|
||||
|
||||
private ArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
protected ArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
//TODO: that is strange
|
||||
@@ -56,41 +58,54 @@ public final class ArrayAccessTranslator extends AccessTranslator {
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsGet() {
|
||||
List<JsExpression> arguments = translateIndexExpressions();
|
||||
return translateAsMethodCall(arguments);
|
||||
return translateAsGet(translateArrayExpression(), translateIndexExpressions());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translateAsGet(@NotNull JsExpression arrayExpression,
|
||||
@NotNull List<JsExpression> indexExpression) {
|
||||
return translateAsMethodCall(arrayExpression, indexExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsSet(@NotNull JsExpression expression) {
|
||||
|
||||
List<JsExpression> arguments = translateIndexExpressions();
|
||||
arguments.add(expression);
|
||||
return translateAsMethodCall(arguments);
|
||||
public JsExpression translateAsSet(@NotNull JsExpression setTo) {
|
||||
return translateAsSet(translateArrayExpression(), translateIndexExpressions(), setTo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsMethodCall(@NotNull List<JsExpression> arguments) {
|
||||
protected JsExpression translateAsSet(@NotNull JsExpression arrayExpression, @NotNull List<JsExpression> indexExpressions, @NotNull JsExpression toSetTo) {
|
||||
List<JsExpression> arguments = Lists.newArrayList(indexExpressions);
|
||||
arguments.add(toSetTo);
|
||||
return translateAsMethodCall(arrayExpression, arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsMethodCall(@NotNull JsExpression arrayExpression, @NotNull List<JsExpression> arguments) {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(translateArrayExpression())
|
||||
.receiver(arrayExpression)
|
||||
.args(arguments)
|
||||
.resolvedCall(BindingUtils.getResolvedCall(bindingContext(), expression))
|
||||
.resolvedCall(getResolvedCall(bindingContext(), expression))
|
||||
.descriptor(methodDescriptor)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateIndexExpressions() {
|
||||
protected List<JsExpression> translateIndexExpressions() {
|
||||
return TranslationUtils.translateExpressionList(context(), expression.getIndexExpressions());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateArrayExpression() {
|
||||
protected JsExpression translateArrayExpression() {
|
||||
return Translation.translateAsExpression(expression.getArrayExpression(), context());
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CachedAccessTranslator getCached() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.reference;
|
||||
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Represents a translator which guaranties that all expression will be computed only once.
|
||||
*/
|
||||
public interface CachedAccessTranslator extends AccessTranslator {
|
||||
List<TemporaryVariable> declaredTemporaries();
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.reference;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.fromExpressionList;
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.toExpressionList;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class CachedArrayAccessTranslator extends ArrayAccessTranslator implements CachedAccessTranslator {
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable arrayExpression;
|
||||
@NotNull
|
||||
private final List<TemporaryVariable> indexExpressions;
|
||||
|
||||
private CachedArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(expression, context);
|
||||
arrayExpression = context.declareTemporary(translateArrayExpression());
|
||||
indexExpressions = fromExpressionList(translateIndexExpressions(), context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsGet() {
|
||||
return translateAsGet(arrayExpression.reference(), toExpressionList(indexExpressions));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsSet(@NotNull JsExpression setTo) {
|
||||
return translateAsSet(arrayExpression.reference(), toExpressionList(indexExpressions), setTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemporaryVariable> declaredTemporaries() {
|
||||
List<TemporaryVariable> result = Lists.newArrayList();
|
||||
result.add(arrayExpression);
|
||||
result.addAll(indexExpressions);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class CachedPropertyAccessTranslator implements CachedAccessTranslator {
|
||||
|
||||
@NotNull
|
||||
private final PropertyAccessTranslator baseTranslator;
|
||||
@Nullable
|
||||
private final TemporaryVariable cachedReceiver;
|
||||
|
||||
/*package*/ CachedPropertyAccessTranslator(@Nullable JsExpression receiverExpression,
|
||||
@NotNull PropertyAccessTranslator baseTranslator,
|
||||
@NotNull TranslationContext context) {
|
||||
this.cachedReceiver = receiverExpression != null ? context.declareTemporary(receiverExpression) : null;
|
||||
this.baseTranslator = baseTranslator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsGet() {
|
||||
return baseTranslator.translateAsGet(receiverOrNull());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsSet(@NotNull JsExpression toSetTo) {
|
||||
return baseTranslator.translateAsSet(receiverOrNull(), toSetTo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JsNameRef receiverOrNull() {
|
||||
return cachedReceiver != null ? cachedReceiver.reference() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CachedAccessTranslator getCached() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemporaryVariable> declaredTemporaries() {
|
||||
return cachedReceiver != null ? singletonList(cachedReceiver) : Collections.<TemporaryVariable>emptyList();
|
||||
}
|
||||
}
|
||||
+29
-11
@@ -33,7 +33,7 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
public final class KotlinPropertyAccessTranslator extends PropertyAccessTranslator {
|
||||
|
||||
@Nullable
|
||||
private final JsExpression qualifier;
|
||||
private final JsExpression receiver;
|
||||
@NotNull
|
||||
private final PropertyDescriptor propertyDescriptor;
|
||||
@NotNull
|
||||
@@ -41,42 +41,60 @@ public final class KotlinPropertyAccessTranslator extends PropertyAccessTranslat
|
||||
|
||||
//TODO: too many params in constructor
|
||||
/*package*/ KotlinPropertyAccessTranslator(@NotNull PropertyDescriptor descriptor,
|
||||
@Nullable JsExpression qualifier,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.qualifier = qualifier;
|
||||
this.receiver = receiver;
|
||||
this.propertyDescriptor = descriptor.getOriginal();
|
||||
this.resolvedCall = resolvedCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsGet() {
|
||||
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
|
||||
assert getter != null : "Getter for kotlin properties should bot be null.";
|
||||
return callBuilderForAccessor()
|
||||
.descriptor(getter)
|
||||
.translate();
|
||||
return translateAsGet(receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsGet(@Nullable JsExpression receiver) {
|
||||
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
|
||||
assert getter != null : "Getter for kotlin properties should bot be null.";
|
||||
return callBuilderForAccessor(receiver)
|
||||
.descriptor(getter)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsSet(@NotNull JsExpression toSetTo) {
|
||||
return translateAsSet(receiver, toSetTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsSet(@Nullable JsExpression receiver, @NotNull JsExpression toSetTo) {
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
assert setter != null : "Getter for kotlin properties should bot be null.";
|
||||
return callBuilderForAccessor()
|
||||
return callBuilderForAccessor(receiver)
|
||||
.args(toSetTo)
|
||||
.descriptor(setter)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallBuilder callBuilderForAccessor() {
|
||||
private CallBuilder callBuilderForAccessor(@Nullable JsExpression qualifier) {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(qualifier)
|
||||
.resolvedCall(resolvedCall)
|
||||
.type(getCallType());
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CachedAccessTranslator getCached() {
|
||||
return new CachedPropertyAccessTranslator(receiver, this, context());
|
||||
}
|
||||
}
|
||||
|
||||
+28
-12
@@ -36,29 +36,32 @@ import static org.jetbrains.k2js.translate.utils.JsAstUtils.qualified;
|
||||
*/
|
||||
public final class NativePropertyAccessTranslator extends PropertyAccessTranslator {
|
||||
|
||||
|
||||
@Nullable
|
||||
private final JsExpression qualifier;
|
||||
private final JsExpression receiver;
|
||||
@NotNull
|
||||
private final PropertyDescriptor propertyDescriptor;
|
||||
|
||||
/*package*/
|
||||
NativePropertyAccessTranslator(@NotNull PropertyDescriptor descriptor,
|
||||
@Nullable JsExpression qualifier,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.qualifier = qualifier;
|
||||
this.receiver = receiver;
|
||||
this.propertyDescriptor = descriptor.getOriginal();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsGet() {
|
||||
return translateAsGet(getReceiver());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JsExpression translateAsGet(@Nullable JsExpression receiver) {
|
||||
JsName nativePropertyName = context().getNameForDescriptor(propertyDescriptor);
|
||||
JsExpression realQualifier = getQualifier();
|
||||
if (realQualifier != null) {
|
||||
return qualified(nativePropertyName, realQualifier);
|
||||
if (receiver != null) {
|
||||
return qualified(nativePropertyName, receiver);
|
||||
}
|
||||
else {
|
||||
return nativePropertyName.makeRef();
|
||||
@@ -67,14 +70,21 @@ public final class NativePropertyAccessTranslator extends PropertyAccessTranslat
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsExpression translateAsSet(@Nullable JsExpression receiver, @NotNull JsExpression setTo) {
|
||||
assert receiver != null;
|
||||
return assignment(translateAsGet(getReceiver()), setTo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression translateAsSet(@NotNull JsExpression setTo) {
|
||||
return assignment(translateAsGet(), setTo);
|
||||
return translateAsSet(getReceiver(), setTo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsExpression getQualifier() {
|
||||
if (qualifier != null) {
|
||||
return qualifier;
|
||||
public JsExpression getReceiver() {
|
||||
if (receiver != null) {
|
||||
return receiver;
|
||||
}
|
||||
assert !propertyDescriptor.getReceiverParameter().exists() : "Cant have native extension properties.";
|
||||
DeclarationDescriptor expectedThisDescriptor = getExpectedThisDescriptor(propertyDescriptor);
|
||||
@@ -83,4 +93,10 @@ public final class NativePropertyAccessTranslator extends PropertyAccessTranslat
|
||||
}
|
||||
return TranslationUtils.getThisObject(context(), expectedThisDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CachedAccessTranslator getCached() {
|
||||
return new CachedPropertyAccessTranslator(getReceiver(), this, context());
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isNativeObject;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
@@ -36,7 +37,7 @@ import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReferenc
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class PropertyAccessTranslator extends AccessTranslator {
|
||||
public abstract class PropertyAccessTranslator extends AbstractTranslator implements AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
private static PropertyAccessTranslator newInstance(@NotNull PropertyDescriptor descriptor,
|
||||
@@ -127,6 +128,7 @@ public abstract class PropertyAccessTranslator extends AccessTranslator {
|
||||
}
|
||||
|
||||
//TODO: we use normal by default but may cause bugs
|
||||
//TODO: inspect
|
||||
private /*var*/ CallType callType = CallType.NORMAL;
|
||||
|
||||
protected PropertyAccessTranslator(@NotNull TranslationContext context) {
|
||||
@@ -142,4 +144,10 @@ public abstract class PropertyAccessTranslator extends AccessTranslator {
|
||||
assert callType != null : "CallType not set";
|
||||
return callType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract JsExpression translateAsGet(@Nullable JsExpression receiver);
|
||||
|
||||
@NotNull
|
||||
protected abstract JsExpression translateAsSet(@Nullable JsExpression receiver, @NotNull JsExpression setTo);
|
||||
}
|
||||
+16
-1
@@ -21,12 +21,17 @@ import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ReferenceAccessTranslator extends AccessTranslator {
|
||||
public final class ReferenceAccessTranslator extends AbstractTranslator implements CachedAccessTranslator {
|
||||
|
||||
@NotNull
|
||||
/*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
|
||||
@@ -59,4 +64,14 @@ public final class ReferenceAccessTranslator extends AccessTranslator {
|
||||
return AstUtil.newAssignment((JsNameRef) reference, toSetTo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CachedAccessTranslator getCached() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemporaryVariable> declaredTemporaries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
@@ -254,10 +253,14 @@ public final class JsAstUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JsStatement> temporariesInitialization(@NotNull TemporaryVariable... temporaries) {
|
||||
List<JsStatement> result = Lists.newArrayList();
|
||||
for (TemporaryVariable temporary : temporaries) {
|
||||
result.add(temporary.assignmentExpression().makeStmt());
|
||||
public static JsExpression newSequence(@NotNull List<JsExpression> expressions) {
|
||||
assert !expressions.isEmpty();
|
||||
if (expressions.size() == 1) {
|
||||
return expressions.get(0);
|
||||
}
|
||||
JsExpression result = expressions.get(expressions.size() - 1);
|
||||
for (int i = expressions.size() - 2; i >= 0; i--) {
|
||||
result = new JsBinaryOperation(JsBinaryOperator.COMMA, expressions.get(i), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: look for what should go there
|
||||
public final class TemporariesUtils {
|
||||
private TemporariesUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<TemporaryVariable> fromExpressionList(@NotNull List<JsExpression> expressions,
|
||||
@NotNull TranslationContext context) {
|
||||
List<TemporaryVariable> result = Lists.newArrayList();
|
||||
for (JsExpression expression : expressions) {
|
||||
result.add(context.declareTemporary(expression));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JsExpression> toExpressionList(@NotNull List<TemporaryVariable> temporaries) {
|
||||
List<JsExpression> result = Lists.newArrayList();
|
||||
for (TemporaryVariable temp : temporaries) {
|
||||
result.add(temp.reference());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression temporariesInitialization(@NotNull TemporaryVariable... temporaries) {
|
||||
List<JsExpression> result = Lists.newArrayList();
|
||||
for (TemporaryVariable temporary : temporaries) {
|
||||
result.add(temporary.assignmentExpression());
|
||||
}
|
||||
return newSequence(result);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JsExpression> temporariesInitialization(@NotNull List<TemporaryVariable> temporaries) {
|
||||
List<JsExpression> result = Lists.newArrayList();
|
||||
for (TemporaryVariable temporary : temporaries) {
|
||||
result.add(temporary.assignmentExpression());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package foo
|
||||
|
||||
var c = 0
|
||||
|
||||
class A() {
|
||||
var p = 0;
|
||||
{
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
fun box() : Boolean {
|
||||
++A().p
|
||||
if (c != 1) {
|
||||
return false;
|
||||
}
|
||||
--A().p
|
||||
if (c != 2) {
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
Reference in New Issue
Block a user