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
017package org.jetbrains.jet.codegen.binding;
018
019import com.intellij.openapi.util.Pair;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.asm4.Type;
023import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
024import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
025import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
026import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
027import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
028import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
029
030import java.util.*;
031
032public final class MutableClosure implements CalculatedClosure {
033    private final JetDelegatorToSuperCall superCall;
034
035    private final ClassDescriptor enclosingClass;
036    private final CallableDescriptor enclosingReceiverDescriptor;
037
038    private boolean captureThis;
039    private boolean captureReceiver;
040
041    private Map<DeclarationDescriptor, EnclosedValueDescriptor> captureVariables;
042    private List<Pair<String, Type>> recordedFields;
043
044    MutableClosure(
045            JetDelegatorToSuperCall superCall,
046            ClassDescriptor enclosingClass,
047            CallableDescriptor enclosingReceiverDescriptor
048    ) {
049        this.superCall = superCall;
050        this.enclosingClass = enclosingClass;
051        this.enclosingReceiverDescriptor = enclosingReceiverDescriptor;
052    }
053
054    @Nullable
055    @Override
056    public ClassDescriptor getEnclosingClass() {
057        return enclosingClass;
058    }
059
060    @Override
061    public JetDelegatorToSuperCall getSuperCall() {
062        return superCall;
063    }
064
065    @Override
066    public ClassDescriptor getCaptureThis() {
067        return captureThis ? enclosingClass : null;
068    }
069
070    public void setCaptureThis() {
071        this.captureThis = true;
072    }
073
074    @Override
075    public ClassifierDescriptor getCaptureReceiver() {
076        return captureReceiver
077               ? enclosingReceiverDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor()
078               : null;
079    }
080
081    public void setCaptureReceiver() {
082        if (enclosingReceiverDescriptor == null) {
083            throw new IllegalStateException();
084        }
085        this.captureReceiver = true;
086    }
087
088    @NotNull
089    @Override
090    public Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables() {
091        return captureVariables != null ? captureVariables : Collections.<DeclarationDescriptor, EnclosedValueDescriptor>emptyMap();
092    }
093
094    @NotNull
095    @Override
096    public List<Pair<String, Type>> getRecordedFields() {
097        return recordedFields != null ? recordedFields : Collections.<Pair<String, Type>>emptyList();
098    }
099
100    public void recordField(String name, Type type) {
101        if (recordedFields == null) {
102            recordedFields = new LinkedList<Pair<String, Type>>();
103        }
104        recordedFields.add(new Pair<String, Type>(name, type));
105    }
106
107    public void captureVariable(EnclosedValueDescriptor value) {
108        if (captureVariables == null) {
109            captureVariables = new HashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
110        }
111        captureVariables.put(value.getDescriptor(), value);
112    }
113
114    public CallableDescriptor getEnclosingReceiverDescriptor() {
115        return enclosingReceiverDescriptor;
116    }
117}