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.*; 020import com.intellij.openapi.util.Pair; 021import com.intellij.util.SmartList; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.annotations.Nullable; 024import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 025import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; 026import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; 027import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor; 028import org.jetbrains.jet.lang.psi.*; 029import org.jetbrains.k2js.translate.context.TranslationContext; 030import org.jetbrains.k2js.translate.general.Translation; 031 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.List; 035 036import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; 037import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment; 038 039public final class TranslationUtils { 040 private TranslationUtils() { 041 } 042 043 @NotNull 044 public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(@NotNull JsFunction function, 045 @NotNull FunctionDescriptor descriptor, 046 @NotNull TranslationContext context) { 047 if (JsDescriptorUtils.isExtension(descriptor)) { 048 return translateExtensionFunctionAsEcma5DataDescriptor(function, descriptor, context); 049 } 050 else { 051 JsStringLiteral getOrSet = context.program().getStringLiteral(descriptor instanceof PropertyGetterDescriptor ? "get" : "set"); 052 return new JsPropertyInitializer(getOrSet, function); 053 } 054 } 055 056 @NotNull 057 private static JsPropertyInitializer translateExtensionFunctionAsEcma5DataDescriptor(@NotNull JsFunction function, 058 @NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context) { 059 JsObjectLiteral meta = JsAstUtils.createDataDescriptor(function, descriptor.getModality().isOverridable()); 060 return new JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), meta); 061 } 062 063 @NotNull 064 public static JsBinaryOperation isNullCheck(@NotNull JsExpression expressionToCheck) { 065 return nullCheck(expressionToCheck, false); 066 } 067 068 @NotNull 069 public static JsBinaryOperation isNotNullCheck(@NotNull JsExpression expressionToCheck) { 070 return nullCheck(expressionToCheck, true); 071 } 072 073 @NotNull 074 public static JsBinaryOperation nullCheck(@NotNull JsExpression expressionToCheck, boolean isNegated) { 075 JsBinaryOperator operator = isNegated ? JsBinaryOperator.NEQ : JsBinaryOperator.EQ; 076 return new JsBinaryOperation(operator, expressionToCheck, JsLiteral.NULL); 077 } 078 079 @NotNull 080 public static List<JsExpression> translateArgumentList(@NotNull TranslationContext context, 081 @NotNull List<? extends ValueArgument> jetArguments) { 082 if (jetArguments.isEmpty()) { 083 return Collections.emptyList(); 084 } 085 086 List<JsExpression> jsArguments = new SmartList<JsExpression>(); 087 for (ValueArgument argument : jetArguments) { 088 jsArguments.add(translateArgument(context, argument)); 089 } 090 return jsArguments; 091 } 092 093 @NotNull 094 private static JsExpression translateArgument(@NotNull TranslationContext context, @NotNull ValueArgument argument) { 095 JetExpression jetExpression = argument.getArgumentExpression(); 096 assert jetExpression != null : "Argument with no expression"; 097 return Translation.translateAsExpression(jetExpression, context); 098 } 099 100 @NotNull 101 public static JsNameRef backingFieldReference(@NotNull TranslationContext context, 102 @NotNull PropertyDescriptor descriptor) { 103 JsName backingFieldName = context.getNameForDescriptor(descriptor); 104 return new JsNameRef(backingFieldName, JsLiteral.THIS); 105 } 106 107 @NotNull 108 public static JsExpression assignmentToBackingField(@NotNull TranslationContext context, 109 @NotNull PropertyDescriptor descriptor, 110 @NotNull JsExpression assignTo) { 111 JsNameRef backingFieldReference = backingFieldReference(context, descriptor); 112 return assignment(backingFieldReference, assignTo); 113 } 114 115 @Nullable 116 public static JsExpression translateInitializerForProperty(@NotNull JetProperty declaration, 117 @NotNull TranslationContext context) { 118 JsExpression jsInitExpression = null; 119 JetExpression initializer = declaration.getInitializer(); 120 if (initializer != null) { 121 jsInitExpression = Translation.translateAsExpression(initializer, context); 122 } 123 return jsInitExpression; 124 } 125 126 @NotNull 127 public static JsNameRef getQualifiedReference(@NotNull TranslationContext context, @NotNull DeclarationDescriptor descriptor) { 128 return new JsNameRef(context.getNameForDescriptor(descriptor), context.getQualifierForDescriptor(descriptor)); 129 } 130 131 @NotNull 132 public static List<JsExpression> translateExpressionList(@NotNull TranslationContext context, 133 @NotNull List<JetExpression> expressions) { 134 List<JsExpression> result = new ArrayList<JsExpression>(); 135 for (JetExpression expression : expressions) { 136 result.add(Translation.translateAsExpression(expression, context)); 137 } 138 return result; 139 } 140 141 @NotNull 142 public static JsExpression translateBaseExpression(@NotNull TranslationContext context, 143 @NotNull JetUnaryExpression expression) { 144 JetExpression baseExpression = PsiUtils.getBaseExpression(expression); 145 return Translation.translateAsExpression(baseExpression, context); 146 } 147 148 @NotNull 149 public static JsExpression translateLeftExpression(@NotNull TranslationContext context, 150 @NotNull JetBinaryExpression expression) { 151 JetExpression left = expression.getLeft(); 152 assert left != null : "Binary expression should have a left expression: " + expression.getText(); 153 return Translation.translateAsExpression(left, context); 154 } 155 156 @NotNull 157 public static JsExpression translateRightExpression(@NotNull TranslationContext context, 158 @NotNull JetBinaryExpression expression) { 159 JetExpression rightExpression = expression.getRight(); 160 assert rightExpression != null : "Binary expression should have a right expression"; 161 return Translation.translateAsExpression(rightExpression, context); 162 } 163 164 public static boolean hasCorrespondingFunctionIntrinsic(@NotNull TranslationContext context, 165 @NotNull JetOperationExpression expression) { 166 FunctionDescriptor operationDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); 167 168 if (operationDescriptor == null) return true; 169 if (context.intrinsics().getFunctionIntrinsics().getIntrinsic(operationDescriptor).exists()) return true; 170 171 return false; 172 } 173 174 public static boolean isCacheNeeded(@NotNull JsExpression expression) { 175 return !(expression instanceof JsLiteral) && 176 (!(expression instanceof JsNameRef) || ((JsNameRef) expression).getQualifier() != null); 177 } 178 179 @NotNull 180 public static Pair<JsVars.JsVar, JsExpression> createTemporaryIfNeed( 181 @NotNull JsExpression expression, 182 @NotNull TranslationContext context 183 ) { 184 // don't create temp variable for simple expression 185 if (isCacheNeeded(expression)) { 186 return context.dynamicContext().createTemporary(expression); 187 } 188 else { 189 return Pair.create(null, expression); 190 } 191 } 192}