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.context;
018
019import org.jetbrains.asm4.Type;
020import org.jetbrains.jet.codegen.ExpressionCodegen;
021import org.jetbrains.jet.codegen.StackValue;
022import org.jetbrains.jet.codegen.binding.MutableClosure;
023import org.jetbrains.jet.codegen.state.GenerationState;
024import org.jetbrains.jet.lang.descriptors.*;
025import org.jetbrains.jet.lang.resolve.java.JvmClassName;
026import org.jetbrains.jet.lang.types.JetType;
027
028import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD;
029import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass;
030import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
031
032public interface LocalLookup {
033    boolean lookupLocal(DeclarationDescriptor descriptor);
034
035    enum LocalLookupCase {
036        VAR {
037            @Override
038            public boolean isCase(DeclarationDescriptor d, GenerationState state) {
039                return (d instanceof VariableDescriptor) && !(d instanceof PropertyDescriptor);
040            }
041
042            @Override
043            public StackValue innerValue(
044                    DeclarationDescriptor d,
045                    LocalLookup localLookup,
046                    GenerationState state,
047                    MutableClosure closure, JvmClassName className
048            ) {
049                VariableDescriptor vd = (VariableDescriptor) d;
050
051                boolean idx = localLookup != null && localLookup.lookupLocal(vd);
052                if (!idx) return null;
053
054                Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
055                Type localType = state.getTypeMapper().mapType(vd);
056                Type type = sharedVarType != null ? sharedVarType : localType;
057
058                String fieldName = "$" + vd.getName();
059                StackValue innerValue = sharedVarType != null
060                                        ? StackValue.fieldForSharedVar(localType, className, fieldName)
061                                        : StackValue.field(type, className, fieldName, false);
062
063                closure.recordField(fieldName, type);
064                closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, type));
065
066                return innerValue;
067            }
068        },
069
070        LOCAL_NAMED_FUNCTION {
071            @Override
072            public boolean isCase(DeclarationDescriptor d, GenerationState state) {
073                return isLocalNamedFun(d);
074            }
075
076            @Override
077            public StackValue innerValue(
078                    DeclarationDescriptor d,
079                    LocalLookup localLookup,
080                    GenerationState state,
081                    MutableClosure closure,
082                    JvmClassName className
083            ) {
084                FunctionDescriptor vd = (FunctionDescriptor) d;
085
086                boolean idx = localLookup != null && localLookup.lookupLocal(vd);
087                if (!idx) return null;
088
089                Type localType = classNameForAnonymousClass(state.getBindingContext(), vd).getAsmType();
090
091                String fieldName = "$" + vd.getName();
092                StackValue innerValue = StackValue.field(localType, className, fieldName, false);
093
094                closure.recordField(fieldName, localType);
095                closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, localType));
096
097                return innerValue;
098            }
099        },
100
101        RECEIVER {
102            @Override
103            public boolean isCase(DeclarationDescriptor d, GenerationState state) {
104                return d instanceof CallableDescriptor;
105            }
106
107            @Override
108            public StackValue innerValue(
109                    DeclarationDescriptor d,
110                    LocalLookup enclosingLocalLookup,
111                    GenerationState state,
112                    MutableClosure closure, JvmClassName className
113            ) {
114                if (closure.getEnclosingReceiverDescriptor() != d) return null;
115
116                JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType();
117                Type type = state.getTypeMapper().mapType(receiverType);
118                StackValue innerValue = StackValue.field(type, className, CAPTURED_RECEIVER_FIELD, false);
119                closure.setCaptureReceiver();
120
121                return innerValue;
122            }
123
124            @Override
125            public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
126                CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
127                return StackValue.local(descriptor.getExpectedThisObject() != null ? 1 : 0, d.getType());
128            }
129        };
130
131        public abstract boolean isCase(DeclarationDescriptor d, GenerationState state);
132
133        public abstract StackValue innerValue(
134                DeclarationDescriptor d,
135                LocalLookup localLookup,
136                GenerationState state,
137                MutableClosure closure,
138                JvmClassName className
139        );
140
141        public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
142            int idx = expressionCodegen.lookupLocalIndex(d.getDescriptor());
143            assert idx != -1;
144
145            return StackValue.local(idx, d.getType());
146        }
147    }
148}