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.reference;
018    
019    import com.google.dart.compiler.backend.js.ast.JsExpression;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
023    import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
024    import org.jetbrains.jet.lang.psi.*;
025    import org.jetbrains.k2js.translate.context.TranslationContext;
026    import org.jetbrains.k2js.translate.utils.ErrorReportingUtils;
027    
028    import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
029    import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
030    import static org.jetbrains.k2js.translate.utils.PsiUtils.getNotNullSimpleNameSelector;
031    import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelector;
032    
033    public final class QualifiedExpressionTranslator {
034    
035        private QualifiedExpressionTranslator() {
036        }
037    
038        @NotNull
039        public static AccessTranslator getAccessTranslator(@NotNull JetQualifiedExpression expression,
040                                                           @NotNull TranslationContext context) {
041            JsExpression receiver = translateReceiver(expression, context);
042            PropertyAccessTranslator result =
043                PropertyAccessTranslator.newInstance(getNotNullSimpleNameSelector(expression), receiver,
044                                                     CallType.getCallTypeForQualifiedExpression(expression), context);
045            result.setCallType(CallType.getCallTypeForQualifiedExpression(expression));
046            return result;
047        }
048    
049        @NotNull
050        public static JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression,
051                                                                @NotNull TranslationContext context) {
052            JsExpression receiver = translateReceiver(expression, context);
053            JetExpression selector = getSelector(expression);
054            CallType callType = CallType.getCallTypeForQualifiedExpression(expression);
055            return dispatchToCorrectTranslator(receiver, selector, callType, context);
056        }
057    
058        @NotNull
059        private static JsExpression dispatchToCorrectTranslator(@Nullable JsExpression receiver,
060                                                                @NotNull JetExpression selector,
061                                                                @NotNull CallType callType,
062                                                                @NotNull TranslationContext context) {
063            if (PropertyAccessTranslator.canBePropertyGetterCall(selector, context)) {
064                assert selector instanceof JetSimpleNameExpression : "Selectors for properties must be simple names.";
065                return PropertyAccessTranslator.translateAsPropertyGetterCall
066                    ((JetSimpleNameExpression)selector, receiver, callType, context);
067            }
068            if (selector instanceof JetCallExpression) {
069                return invokeCallExpressionTranslator(receiver, selector, callType, context);
070            }
071            //TODO: never get there
072            if (selector instanceof JetSimpleNameExpression) {
073                return ReferenceTranslator.translateSimpleName((JetSimpleNameExpression)selector, context);
074            }
075            throw new AssertionError("Unexpected qualified expression: " + selector.getText());
076        }
077    
078        @NotNull
079        private static JsExpression invokeCallExpressionTranslator(@Nullable JsExpression receiver,
080                @NotNull JetExpression selector,
081                @NotNull CallType callType,
082                @NotNull TranslationContext context) {
083            try {
084                return CallExpressionTranslator.translate((JetCallExpression) selector, receiver, callType, context);
085            } catch (RuntimeException e) {
086                throw  ErrorReportingUtils.reportErrorWithLocation(selector, e);
087            }
088        }
089    
090        @Nullable
091        private static JsExpression translateReceiver(@NotNull JetQualifiedExpression expression,
092                                                      @NotNull TranslationContext context) {
093            JetExpression receiverExpression = expression.getReceiverExpression();
094            if (isFullQualifierForExpression(receiverExpression, context)) {
095                return null;
096            }
097            return translateAsExpression(receiverExpression, context);
098        }
099    
100        //TODO: prove correctness
101        private static boolean isFullQualifierForExpression(@Nullable JetExpression receiverExpression, @NotNull TranslationContext context) {
102            if (receiverExpression == null) {
103                return false;
104            }
105            if (receiverExpression instanceof JetReferenceExpression) {
106                DeclarationDescriptor descriptorForReferenceExpression =
107                    getDescriptorForReferenceExpression(context.bindingContext(), (JetReferenceExpression)receiverExpression);
108                if (descriptorForReferenceExpression instanceof NamespaceDescriptor) {
109                    return true;
110                }
111            }
112            if (receiverExpression instanceof JetQualifiedExpression) {
113                return isFullQualifierForExpression(((JetQualifiedExpression)receiverExpression).getSelectorExpression(), context);
114            }
115            return false;
116        }
117    }