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.jet.codegen.inline;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.codegen.state.GenerationState;
022    
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.Map;
026    
027    public class InliningContext {
028    
029        @Nullable
030        private final InliningContext parent;
031    
032        public final Map<Integer, LambdaInfo> expressionMap;
033    
034        public final GenerationState state;
035    
036        public final NameGenerator nameGenerator;
037    
038        public final Map<String, String> typeMapping;
039    
040        public final boolean isInliningLambda;
041    
042        public final boolean classRegeneration;
043    
044        protected InliningContext(
045                @Nullable InliningContext parent,
046                @NotNull Map<Integer, LambdaInfo> map,
047                @NotNull GenerationState state,
048                @NotNull NameGenerator nameGenerator,
049                @NotNull Map<String, String> typeMapping,
050                boolean isInliningLambda,
051                boolean classRegeneration
052        ) {
053            this.parent = parent;
054            expressionMap = map;
055            this.state = state;
056            this.nameGenerator = nameGenerator;
057            this.typeMapping = typeMapping;
058            this.isInliningLambda = isInliningLambda;
059            this.classRegeneration = classRegeneration;
060        }
061    
062        public InliningContext subInline(NameGenerator generator) {
063            return subInline(generator, Collections.<String, String>emptyMap());
064        }
065    
066        public InliningContext subInlineLambda(LambdaInfo lambdaInfo) {
067            Map<String, String> map = new HashMap<String, String>();
068            map.put(lambdaInfo.getLambdaClassType().getInternalName(), null); //mark lambda inlined
069            return subInline(nameGenerator.subGenerator("lambda"), map, true);
070        }
071    
072        public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
073            return subInline(generator, additionalTypeMappings, isInliningLambda);
074        }
075    
076        public InliningContext subInlineWithClassRegeneration(@NotNull NameGenerator generator,
077                @NotNull Map<String, String> additionalTypeMappings,
078                @NotNull ConstructorInvocation constructorInvocation) {
079            Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
080            newTypeMappings.putAll(additionalTypeMappings);
081            return new RegenetedClassContext(this, expressionMap, state, generator,
082                                       newTypeMappings, isInliningLambda, constructorInvocation);
083    
084        }
085    
086        public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings, boolean isInliningLambda) {
087            return subInline(generator, additionalTypeMappings, isInliningLambda, classRegeneration);
088        }
089    
090        private InliningContext subInline(
091                NameGenerator generator,
092                Map<String, String> additionalTypeMappings,
093                boolean isInliningLambda,
094                boolean isRegeneration
095        ) {
096            Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
097            newTypeMappings.putAll(additionalTypeMappings);
098            return new InliningContext(this, expressionMap, state, generator,
099                                       newTypeMappings, isInliningLambda, isRegeneration);
100        }
101    
102        public boolean isRoot() {
103            return parent == null;
104        }
105    
106        @NotNull
107        public RootInliningContext getRoot() {
108            if (isRoot()) {
109                return (RootInliningContext) this;
110            }
111            else {
112                return parent.getRoot();
113            }
114        }
115    
116        @Nullable
117        public InliningContext getParent() {
118            return parent;
119        }
120    
121        public boolean isInliningLambdaRootContext() {
122            //noinspection ConstantConditions
123            return isInliningLambda && !getParent().isInliningLambda;
124        }
125    
126        public String getClassNameToInline() {
127            assert parent != null : "At least root context should return proper value";
128            return parent.getClassNameToInline();
129        }
130    }