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.k2js.translate.utils;
018
019 import com.google.dart.compiler.backend.js.ast.*;
020 import com.intellij.openapi.util.Pair;
021 import com.intellij.util.SmartList;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
026 import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
027 import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.k2js.translate.context.TranslationContext;
030 import org.jetbrains.k2js.translate.general.Translation;
031
032 import java.util.ArrayList;
033 import java.util.Collections;
034 import java.util.List;
035
036 import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
037 import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
038
039 public 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 }