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 org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation;
020    import org.jetbrains.kotlin.js.backend.ast.JsExpression;
021    import com.intellij.psi.tree.IElementType;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
024    import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
025    import org.jetbrains.kotlin.js.translate.context.TranslationContext;
026    import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
027    import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
028    import org.jetbrains.kotlin.lexer.KtTokens;
029    import org.jetbrains.kotlin.psi.KtConstantExpression;
030    import org.jetbrains.kotlin.psi.KtExpression;
031    import org.jetbrains.kotlin.psi.KtUnaryExpression;
032    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
033    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
034    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
035    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
036    
037    import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsExpression;
038    import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCompileTimeValue;
039    import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
040    import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getBaseExpression;
041    import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken;
042    import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.*;
043    
044    public final class UnaryOperationTranslator {
045        private UnaryOperationTranslator() {
046        }
047    
048        @NotNull
049        public static JsExpression translate(
050                @NotNull KtUnaryExpression expression,
051                @NotNull TranslationContext context
052        ) {
053            IElementType operationToken = expression.getOperationReference().getReferencedNameElementType();
054            if (operationToken == KtTokens.EXCLEXCL) {
055                KtExpression baseExpression = getBaseExpression(expression);
056                JsExpression translatedExpression = translateAsExpression(baseExpression, context);
057                return sure(translatedExpression, context);
058            }
059    
060            if (operationToken == KtTokens.MINUS) {
061                KtExpression baseExpression = getBaseExpression(expression);
062                if (baseExpression instanceof KtConstantExpression) {
063                    CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext());
064                    assert compileTimeValue != null : message(expression, "Expression is not compile time value: " + expression.getText() + " ");
065                    Object value = getCompileTimeValue(context.bindingContext(), expression, compileTimeValue);
066                    if (value instanceof Long) {
067                        return JsAstUtils.newLong((Long) value, context);
068                    }
069                }
070            }
071    
072            if (IncrementTranslator.isIncrement(operationToken)) {
073                return IncrementTranslator.translate(expression, context);
074            }
075    
076            JsExpression baseExpression = TranslationUtils.translateBaseExpression(context, expression);
077            if (isExclForBinaryEqualLikeExpr(expression, baseExpression)) {
078                return translateExclForBinaryEqualLikeExpr((JsBinaryOperation) baseExpression);
079            }
080    
081            ResolvedCall<? extends FunctionDescriptor> resolvedCall = CallUtilKt.getFunctionResolvedCallWithAssert(expression, context.bindingContext());
082            return CallTranslator.translate(context, resolvedCall, baseExpression);
083        }
084    
085        private static boolean isExclForBinaryEqualLikeExpr(@NotNull KtUnaryExpression expression, @NotNull JsExpression baseExpression) {
086            if (getOperationToken(expression).equals(KtTokens.EXCL)) {
087                if (baseExpression instanceof JsBinaryOperation) {
088                    return isEqualLikeOperator(((JsBinaryOperation) baseExpression).getOperator());
089                }
090            }
091            return false;
092        }
093    }