001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.js.translate.operation;
018    
019    import com.google.dart.compiler.backend.js.ast.JsBlock;
020    import com.google.dart.compiler.backend.js.ast.JsExpression;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
023    import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
024    import org.jetbrains.kotlin.psi.JetBinaryExpression;
025    import org.jetbrains.kotlin.psi.JetExpression;
026    import org.jetbrains.kotlin.psi.JetSimpleNameExpression;
027    import org.jetbrains.kotlin.types.expressions.OperatorConventions;
028    import org.jetbrains.kotlin.lexer.JetToken;
029    import org.jetbrains.kotlin.js.translate.context.TranslationContext;
030    import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
031    import org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils;
032    import org.jetbrains.kotlin.js.translate.reference.AccessTranslator;
033    import org.jetbrains.kotlin.js.translate.reference.BackingFieldAccessTranslator;
034    
035    import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
036    import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.isVariableReassignment;
037    import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getSimpleName;
038    import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.isAssignment;
039    import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic;
040    import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateRightExpression;
041    
042    public abstract class AssignmentTranslator extends AbstractTranslator {
043    
044        public static boolean isAssignmentOperator(JetToken operationToken) {
045            return (OperatorConventions.ASSIGNMENT_OPERATIONS.keySet().contains(operationToken) || isAssignment(operationToken));
046        }
047    
048        @NotNull
049        public static JsExpression translate(@NotNull JetBinaryExpression expression,
050                                             @NotNull TranslationContext context) {
051            if (hasCorrespondingFunctionIntrinsic(context, expression)) {
052                return IntrinsicAssignmentTranslator.doTranslate(expression, context);
053            }
054            return OverloadedAssignmentTranslator.doTranslate(expression, context);
055        }
056    
057        @NotNull
058        protected final JetBinaryExpression expression;
059        protected final AccessTranslator accessTranslator;
060        protected final boolean isVariableReassignment;
061        @NotNull
062        protected final JsExpression right;
063    
064        protected AssignmentTranslator(@NotNull JetBinaryExpression expression,
065                                       @NotNull TranslationContext context) {
066            super(context);
067            this.expression = expression;
068            this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
069            JetExpression left = expression.getLeft();
070            assert left != null : "No left-hand side: " + expression.getText();
071    
072            JsBlock rightBlock = new JsBlock();
073            this.right = translateRightExpression(context, expression, rightBlock);
074    
075            if (isValProperty(left, context)) {
076                JetSimpleNameExpression simpleName = getSimpleName(left);
077                assert simpleName != null;
078                this.accessTranslator = BackingFieldAccessTranslator.newInstance(simpleName, context);
079            } else {
080                this.accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context(), !rightBlock.isEmpty());
081            }
082    
083            context.addStatementsToCurrentBlockFrom(rightBlock);
084        }
085    
086        private static boolean isValProperty(
087                @NotNull JetExpression expression,
088                @NotNull TranslationContext context
089        ) {
090            JetSimpleNameExpression simpleNameExpression = getSimpleName(expression);
091    
092            if (simpleNameExpression != null) {
093                DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), simpleNameExpression);
094                return descriptor instanceof PropertyDescriptor && !((PropertyDescriptor) descriptor).isVar();
095            }
096    
097            return false;
098        }
099    }