001    /*
002     * Copyright 2010-2013 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.k2js.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.jet.lang.descriptors.DeclarationDescriptor;
023    import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
024    import org.jetbrains.jet.lang.psi.JetBinaryExpression;
025    import org.jetbrains.jet.lang.psi.JetExpression;
026    import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
027    import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
028    import org.jetbrains.jet.lexer.JetToken;
029    import org.jetbrains.k2js.translate.context.TranslationContext;
030    import org.jetbrains.k2js.translate.general.AbstractTranslator;
031    import org.jetbrains.k2js.translate.reference.AccessTranslationUtils;
032    import org.jetbrains.k2js.translate.reference.AccessTranslator;
033    import org.jetbrains.k2js.translate.reference.BackingFieldAccessTranslator;
034    
035    import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
036    import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
037    import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
038    import static org.jetbrains.k2js.translate.utils.PsiUtils.getSimpleName;
039    import static org.jetbrains.k2js.translate.utils.PsiUtils.isAssignment;
040    import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic;
041    import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
042    
043    public abstract class AssignmentTranslator extends AbstractTranslator {
044    
045        public static boolean isAssignmentOperator(JetBinaryExpression expression) {
046            JetToken operationToken = getOperationToken(expression);
047            return (OperatorConventions.ASSIGNMENT_OPERATIONS.keySet().contains(operationToken)
048                    || isAssignment(operationToken));
049        }
050    
051        @NotNull
052        public static JsExpression translate(@NotNull JetBinaryExpression expression,
053                                             @NotNull TranslationContext context) {
054            if (hasCorrespondingFunctionIntrinsic(context, expression)) {
055                return IntrinsicAssignmentTranslator.doTranslate(expression, context);
056            }
057            return OverloadedAssignmentTranslator.doTranslate(expression, context);
058        }
059    
060        @NotNull
061        protected final JetBinaryExpression expression;
062        protected final AccessTranslator accessTranslator;
063        protected final boolean isVariableReassignment;
064        @NotNull
065        protected final JsExpression right;
066    
067        protected AssignmentTranslator(@NotNull JetBinaryExpression expression,
068                                       @NotNull TranslationContext context) {
069            super(context);
070            this.expression = expression;
071            this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
072            JetExpression left = expression.getLeft();
073            assert left != null : "No left-hand side: " + expression.getText();
074    
075            JsBlock rightBlock = new JsBlock();
076            this.right = translateRightExpression(context, expression, rightBlock);
077    
078            if (isValProperty(left, context)) {
079                JetSimpleNameExpression simpleName = getSimpleName(left);
080                assert simpleName != null;
081                this.accessTranslator = BackingFieldAccessTranslator.newInstance(simpleName, context);
082            } else {
083                this.accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context(), !rightBlock.isEmpty());
084            }
085    
086            context.addStatementsToCurrentBlockFrom(rightBlock);
087        }
088    
089        private static boolean isValProperty(
090                @NotNull JetExpression expression,
091                @NotNull TranslationContext context
092        ) {
093            JetSimpleNameExpression simpleNameExpression = getSimpleName(expression);
094    
095            if (simpleNameExpression != null) {
096                DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), simpleNameExpression);
097                return descriptor instanceof PropertyDescriptor && !((PropertyDescriptor) descriptor).isVar();
098            }
099    
100            return false;
101        }
102    }