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.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.kotlin.descriptors.VariableDescriptor;
023    import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
024    import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
025    import org.jetbrains.kotlin.js.translate.context.TranslationContext;
026    import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
027    import org.jetbrains.kotlin.psi.JetReferenceExpression;
028    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
029    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
030    import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
031    
032    import java.util.Collections;
033    import java.util.List;
034    
035    public class VariableAccessTranslator extends AbstractTranslator implements AccessTranslator {
036        public static VariableAccessTranslator newInstance(
037                @NotNull TranslationContext context,
038                @NotNull JetReferenceExpression referenceExpression,
039                @Nullable JsExpression receiver
040        ) {
041            ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCallWithAssert(referenceExpression, context.bindingContext());
042            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
043                resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall();
044            }
045            assert resolvedCall.getResultingDescriptor() instanceof VariableDescriptor;
046            return new VariableAccessTranslator(context, (ResolvedCall<? extends VariableDescriptor>) resolvedCall, receiver);
047        }
048    
049    
050        private final ResolvedCall<? extends VariableDescriptor> resolvedCall;
051        private final JsExpression receiver;
052    
053        private VariableAccessTranslator(
054                @NotNull TranslationContext context,
055                @NotNull ResolvedCall<? extends VariableDescriptor> resolvedCall,
056                @Nullable JsExpression receiver
057        ) {
058            super(context);
059            this.receiver = receiver;
060            this.resolvedCall = resolvedCall;
061        }
062    
063        @NotNull
064        @Override
065        public JsExpression translateAsGet() {
066            return CallTranslator.INSTANCE$.translateGet(context(), resolvedCall, receiver);
067        }
068    
069        @NotNull
070        @Override
071        public JsExpression translateAsSet(@NotNull JsExpression setTo) {
072            return CallTranslator.INSTANCE$.translateSet(context(), resolvedCall, setTo, receiver);
073        }
074    
075        @NotNull
076        @Override
077        public CachedAccessTranslator getCached() {
078            TemporaryVariable temporaryVariable = receiver == null ? null : context().declareTemporary(receiver);
079            return new CachedVariableAccessTranslator(context(), resolvedCall, temporaryVariable);
080        }
081    
082        private static class CachedVariableAccessTranslator extends VariableAccessTranslator implements CachedAccessTranslator {
083            @Nullable
084            private final TemporaryVariable cachedReceiver;
085    
086            public CachedVariableAccessTranslator(
087                    @NotNull TranslationContext context,
088                    @NotNull  ResolvedCall<? extends VariableDescriptor> resolvedCall,
089                    @Nullable TemporaryVariable cachedReceiver
090            ) {
091                super(context, resolvedCall, cachedReceiver == null ? null : cachedReceiver.reference());
092                this.cachedReceiver = cachedReceiver;
093            }
094    
095            @NotNull
096            @Override
097            public List<TemporaryVariable> declaredTemporaries() {
098                return cachedReceiver == null ? Collections.<TemporaryVariable>emptyList() : Collections.singletonList(cachedReceiver);
099            }
100    
101            @NotNull
102            @Override
103            public CachedAccessTranslator getCached() {
104                return this;
105            }
106        }
107    
108    }