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.k2js.translate.utils; 018 019import com.google.dart.compiler.backend.js.ast.JsBlock; 020import com.google.dart.compiler.backend.js.ast.JsExpression; 021import com.google.dart.compiler.backend.js.ast.JsNode; 022import com.google.dart.compiler.backend.js.ast.JsReturn; 023import org.jetbrains.annotations.NotNull; 024import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; 025import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; 026import org.jetbrains.jet.lang.psi.JetExpression; 027import org.jetbrains.jet.lang.types.JetType; 028import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 029import org.jetbrains.k2js.translate.context.TranslationContext; 030import org.jetbrains.k2js.translate.general.AbstractTranslator; 031import org.jetbrains.k2js.translate.general.Translation; 032import org.jetbrains.k2js.translate.utils.mutator.Mutator; 033 034import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToBlock; 035import static org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression; 036 037public final class FunctionBodyTranslator extends AbstractTranslator { 038 039 @NotNull 040 public static JsBlock translateFunctionBody(@NotNull FunctionDescriptor descriptor, 041 @NotNull JetDeclarationWithBody declarationWithBody, 042 @NotNull TranslationContext functionBodyContext) { 043 return (new FunctionBodyTranslator(descriptor, declarationWithBody, functionBodyContext)).translate(); 044 } 045 046 047 @NotNull 048 private final FunctionDescriptor descriptor; 049 @NotNull 050 private final JetDeclarationWithBody declaration; 051 052 private FunctionBodyTranslator(@NotNull FunctionDescriptor descriptor, 053 @NotNull JetDeclarationWithBody declaration, 054 @NotNull TranslationContext context) { 055 super(context); 056 this.descriptor = descriptor; 057 this.declaration = declaration; 058 } 059 060 @NotNull 061 private JsBlock translate() { 062 JetExpression jetBodyExpression = declaration.getBodyExpression(); 063 assert jetBodyExpression != null : "Cannot translate a body of an abstract function."; 064 return mayBeWrapWithReturn(Translation.translateExpression(jetBodyExpression, context())); 065 } 066 067 @NotNull 068 private JsBlock mayBeWrapWithReturn(@NotNull JsNode body) { 069 if (!mustAddReturnToGeneratedFunctionBody()) { 070 return convertToBlock(body); 071 } 072 return convertToBlock(lastExpressionReturned(body)); 073 } 074 075 private boolean mustAddReturnToGeneratedFunctionBody() { 076 JetType functionReturnType = descriptor.getReturnType(); 077 assert functionReturnType != null : "Function return typed type must be resolved."; 078 return (!declaration.hasBlockBody()) && (!KotlinBuiltIns.getInstance().isUnit(functionReturnType)); 079 } 080 081 @NotNull 082 private static JsNode lastExpressionReturned(@NotNull JsNode body) { 083 return mutateLastExpression(body, new Mutator() { 084 @Override 085 @NotNull 086 public JsNode mutate(@NotNull JsNode node) { 087 if (!(node instanceof JsExpression)) { 088 return node; 089 } 090 return new JsReturn((JsExpression)node); 091 } 092 }); 093 } 094}