001 /*
002 * Copyright 2010-2016 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.kotlin.js.translate.intrinsic.functions.factories;
018
019 import org.jetbrains.kotlin.js.backend.ast.JsExpression;
020 import org.jetbrains.kotlin.js.backend.ast.JsInvocation;
021 import org.jetbrains.kotlin.js.backend.ast.JsNameRef;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.descriptors.*;
025 import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
026 import org.jetbrains.kotlin.js.patterns.NamePredicate;
027 import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo;
028 import org.jetbrains.kotlin.js.translate.callTranslator.CallInfoExtensionsKt;
029 import org.jetbrains.kotlin.js.translate.context.TranslationContext;
030 import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic;
031 import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed;
032 import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
033 import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
034 import org.jetbrains.kotlin.resolve.DescriptorFactory;
035 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
036 import org.jetbrains.kotlin.types.KotlinType;
037
038 import java.util.List;
039 import java.util.Map;
040
041 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES;
042 import static org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern;
043
044 public final class TopLevelFIF extends CompositeFIF {
045 public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals");
046 @NotNull
047 private static final KotlinFunctionIntrinsic KOTLIN_ANY_EQUALS = new KotlinFunctionIntrinsic("equals") {
048 @NotNull
049 @Override
050 public JsExpression apply(
051 @NotNull CallInfo callInfo,
052 @NotNull List<? extends JsExpression> arguments, @NotNull TranslationContext context
053 ) {
054 if (CallInfoExtensionsKt.isSuperInvocation(callInfo)) {
055 JsExpression dispatchReceiver = callInfo.getDispatchReceiver();
056 assert arguments.size() == 1 && dispatchReceiver != null;
057 return JsAstUtils.equality(dispatchReceiver, arguments.get(0));
058 }
059
060 return super.apply(callInfo, arguments, context);
061 }
062 };
063
064 @NotNull
065 public static final KotlinFunctionIntrinsic KOTLIN_EQUALS = new KotlinFunctionIntrinsic("equals");
066
067 @NotNull
068 private static final KotlinFunctionIntrinsic KOTLIN_SUBSEQUENCE = new KotlinFunctionIntrinsic("subSequence");
069
070 @NotNull
071 private static final DescriptorPredicate HASH_CODE_IN_ANY = pattern("kotlin", "Any", "hashCode");
072 @NotNull
073 private static final KotlinFunctionIntrinsic KOTLIN_HASH_CODE = new KotlinFunctionIntrinsic("hashCode");
074
075 @NotNull
076 private static final FunctionIntrinsic RETURN_RECEIVER_INTRINSIC = new FunctionIntrinsicWithReceiverComputed() {
077 @NotNull
078 @Override
079 public JsExpression apply(
080 @Nullable JsExpression receiver,
081 @NotNull List<? extends JsExpression> arguments,
082 @NotNull TranslationContext context
083 ) {
084 assert receiver != null;
085 return receiver;
086 }
087 };
088
089
090 private static JsExpression getReferenceToOnlyTypeParameter(
091 @NotNull CallInfo callInfo, @NotNull TranslationContext context
092 ) {
093 ResolvedCall<? extends CallableDescriptor> resolvedCall = callInfo.getResolvedCall();
094 Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
095
096 assert typeArguments.size() == 1;
097 KotlinType type = typeArguments.values().iterator().next();
098
099 return UtilsKt.getReferenceToJsClass(type, context);
100 }
101
102 private static final FunctionIntrinsic JS_CLASS_FUN_INTRINSIC = new FunctionIntrinsic() {
103 @NotNull
104 @Override
105 public JsExpression apply(
106 @NotNull CallInfo callInfo,
107 @NotNull List<? extends JsExpression> arguments,
108 @NotNull TranslationContext context
109 ) {
110 return getReferenceToOnlyTypeParameter(callInfo, context);
111 }
112 };
113
114
115 private static final FunctionIntrinsic ENUM_VALUES_INTRINSIC = new FunctionIntrinsic() {
116 @NotNull
117 @Override
118 public JsExpression apply(
119 @NotNull CallInfo callInfo,
120 @NotNull List<? extends JsExpression> arguments,
121 @NotNull TranslationContext context
122 ) {
123 JsExpression enumClassRef = getReferenceToOnlyTypeParameter(callInfo, context);
124
125 FunctionDescriptor fd = DescriptorFactory.createEnumValuesMethod(context.getCurrentModule().getBuiltIns().getEnum());
126
127 return new JsInvocation(new JsNameRef(context.getNameForDescriptor(fd), enumClassRef));
128 }
129 };
130
131
132 private static final FunctionIntrinsic ENUM_VALUE_OF_INTRINSIC = new FunctionIntrinsic() {
133 @NotNull
134 @Override
135 public JsExpression apply(
136 @NotNull CallInfo callInfo,
137 @NotNull List<? extends JsExpression> arguments,
138 @NotNull TranslationContext context
139 ) {
140 JsExpression arg = arguments.get(2); // The first two are reified parameters
141
142 JsExpression enumClassRef = getReferenceToOnlyTypeParameter(callInfo, context);
143
144 FunctionDescriptor fd = DescriptorFactory.createEnumValueOfMethod(context.getCurrentModule().getBuiltIns().getEnum());
145
146 return new JsInvocation(new JsNameRef(context.getNameForDescriptor(fd), enumClassRef), arg);
147 }
148 };
149
150 private static final FunctionIntrinsic STRING_SUBSTRING = new FunctionIntrinsicWithReceiverComputed() {
151 @NotNull
152 @Override
153 public JsExpression apply(
154 @Nullable JsExpression receiver,
155 @NotNull List<? extends JsExpression> arguments,
156 @NotNull TranslationContext context
157 ) {
158 return new JsInvocation(new JsNameRef("substring", receiver), arguments);
159 }
160 };
161
162
163 @NotNull
164 public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString");
165
166 @NotNull
167 public static final FunctionIntrinsic CHAR_TO_STRING = new FunctionIntrinsic() {
168 @NotNull
169 @Override
170 public JsExpression apply(
171 @NotNull CallInfo callInfo, @NotNull List<? extends JsExpression> arguments, @NotNull TranslationContext context
172 ) {
173 return JsAstUtils.charToString(callInfo.getDispatchReceiver());
174 }
175 };
176
177
178 @NotNull
179 public static final FunctionIntrinsicFactory INSTANCE = new TopLevelFIF();
180
181 private TopLevelFIF() {
182 add(EQUALS_IN_ANY, KOTLIN_ANY_EQUALS);
183 add(pattern("Char.toString"), CHAR_TO_STRING);
184 add(pattern("kotlin", "toString").isExtensionOf(FQ_NAMES.any.asString()), TO_STRING);
185 add(pattern("kotlin", "equals").isExtensionOf(FQ_NAMES.any.asString()), KOTLIN_EQUALS);
186 add(HASH_CODE_IN_ANY, KOTLIN_HASH_CODE);
187 add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), KOTLIN_EQUALS);
188 add(pattern("String|Boolean|Char|Number.equals"), KOTLIN_EQUALS);
189 add(pattern("String.subSequence"), STRING_SUBSTRING);
190 add(pattern("CharSequence.subSequence"), KOTLIN_SUBSEQUENCE);
191 add(pattern("kotlin", "iterator").isExtensionOf(FQ_NAMES.iterator.asString()), RETURN_RECEIVER_INTRINSIC);
192
193 add(pattern("kotlin.js", "Json", "get"), ArrayFIF.GET_INTRINSIC);
194 add(pattern("kotlin.js", "Json", "set"), ArrayFIF.SET_INTRINSIC);
195
196 add(pattern("kotlin.js", "jsClass"), JS_CLASS_FUN_INTRINSIC);
197
198 add(pattern("kotlin", "enumValues"), ENUM_VALUES_INTRINSIC);
199 add(pattern("kotlin", "enumValueOf"), ENUM_VALUE_OF_INTRINSIC);
200 }
201
202 }