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;
018
019import org.jetbrains.annotations.NotNull;
020import org.jetbrains.asm4.MethodVisitor;
021import org.jetbrains.asm4.Type;
022import org.jetbrains.jet.codegen.context.MethodContext;
023import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
024import org.jetbrains.jet.codegen.state.GenerationState;
025import org.jetbrains.jet.codegen.state.JetTypeMapper;
026import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
027import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
028
029import java.util.ArrayList;
030import java.util.Collection;
031
032public abstract class FunctionGenerationStrategy {
033
034    private final Collection<String> localVariableNames = new ArrayList<String>();
035
036    private FrameMap frameMap;
037
038    public abstract void generateBody(
039            @NotNull MethodVisitor mv,
040            @NotNull JvmMethodSignature signature,
041            @NotNull MethodContext context
042    );
043
044    protected void addLocalVariableName(@NotNull String name) {
045        localVariableNames.add(name);
046    }
047
048    @NotNull
049    public Collection<String> getLocalVariableNames() {
050        return localVariableNames;
051    }
052
053    @NotNull
054    protected FrameMap createFrameMap(@NotNull JetTypeMapper typeMapper, @NotNull MethodContext context) {
055        return context.prepareFrame(typeMapper);
056    }
057
058    @NotNull
059    public FrameMap getFrameMap(@NotNull JetTypeMapper typeMapper, @NotNull MethodContext context) {
060        if (frameMap == null) {
061            frameMap = createFrameMap(typeMapper, context);
062        }
063        return frameMap;
064    }
065
066    public static class FunctionDefault extends CodegenBased<CallableDescriptor> {
067
068        private final JetDeclarationWithBody declaration;
069
070        public FunctionDefault(
071                @NotNull GenerationState state,
072                @NotNull CallableDescriptor descriptor,
073                @NotNull JetDeclarationWithBody declaration
074        ) {
075            super(state, descriptor);
076            this.declaration = declaration;
077        }
078
079        @Override
080        public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
081            codegen.returnExpression(declaration.getBodyExpression());
082        }
083    }
084
085    public abstract static class CodegenBased<T extends CallableDescriptor> extends FunctionGenerationStrategy {
086
087        protected final GenerationState state;
088
089        protected final T callableDescriptor;
090
091        public CodegenBased(@NotNull GenerationState state, T callableDescriptor) {
092            this.state = state;
093            this.callableDescriptor = callableDescriptor;
094        }
095
096        @Override
097        public void generateBody(
098                @NotNull MethodVisitor mv,
099                @NotNull JvmMethodSignature signature,
100                @NotNull MethodContext context
101        ) {
102            ExpressionCodegen codegen = initializeExpressionCodegen(signature, context, mv, signature.getAsmMethod().getReturnType());
103            doGenerateBody(codegen, signature);
104            generateLocalVarNames(codegen);
105        }
106
107        abstract public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature);
108
109        @NotNull
110        public ExpressionCodegen initializeExpressionCodegen(
111                JvmMethodSignature signature,
112                MethodContext context,
113                MethodVisitor mv,
114                Type returnType
115        ) {
116            return new ExpressionCodegen(mv, getFrameMap(state.getTypeMapper(), context), returnType, context, state);
117        }
118
119        public void generateLocalVarNames(@NotNull ExpressionCodegen codegen) {
120            for (String name : codegen.getLocalVariableNamesForExpression()) {
121                addLocalVariableName(name);
122            }
123        }
124    }
125}