KT-740: Make sure that assign and increment operations compute receiver only once:

- Increment operation on property.
This commit is contained in:
unknown
2012-03-09 16:13:21 +04:00
parent 3841227868
commit 295b38bf32
20 changed files with 505 additions and 95 deletions
@@ -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
@@ -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);
}
@@ -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);
}
@@ -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(),
@@ -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);
}
}
@@ -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);
}
@@ -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();
}
@@ -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.
}
}
@@ -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();
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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);
}
@@ -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())
}