001 /*
002 * Copyright 2010-2015 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.context;
018
019 import com.google.dart.compiler.backend.js.ast.*;
020 import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck;
021 import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
022 import com.intellij.openapi.util.text.StringUtil;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.descriptors.CallableDescriptor;
026 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
027 import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
028 import org.jetbrains.kotlin.idea.JetLanguage;
029 import org.jetbrains.kotlin.name.FqName;
030 import org.jetbrains.kotlin.name.FqNameUnsafe;
031 import org.jetbrains.kotlin.resolve.DescriptorUtils;
032
033 import java.util.Arrays;
034
035 import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope;
036 import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName;
037 import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
038 import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
039
040 /**
041 * Encapsulates different types of constants and naming conventions.
042 */
043 public final class Namer {
044 public static final String KOTLIN_NAME = JetLanguage.NAME;
045 public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase();
046 public static final JsNameRef KOTLIN_OBJECT_REF = new JsNameRef(KOTLIN_NAME);
047 public static final JsNameRef KOTLIN_LONG_NAME_REF = new JsNameRef("Long", KOTLIN_OBJECT_REF);
048
049 public static final String EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getAny(), "equals");
050 public static final String COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getComparable(), "compareTo");
051 public static final String NUMBER_RANGE = "NumberRange";
052 public static final String CHAR_RANGE = "CharRange";
053 public static final String LONG_FROM_NUMBER = "fromNumber";
054 public static final String LONG_TO_NUMBER = "toNumber";
055 public static final String LONG_FROM_INT = "fromInt";
056 public static final String LONG_ZERO = "ZERO";
057 public static final String LONG_ONE = "ONE";
058 public static final String LONG_NEG_ONE = "NEG_ONE";
059 public static final String PRIMITIVE_COMPARE_TO = "primitiveCompareTo";
060 public static final String IS_CHAR = "isChar";
061 public static final String IS_NUMBER = "isNumber";
062
063 public static final String CALLEE_NAME = "$fun";
064
065 public static final String CALL_FUNCTION = "call";
066 private static final String APPLY_FUNCTION = "apply";
067
068 private static final String CLASS_OBJECT_NAME = "createClass";
069 private static final String ENUM_CLASS_OBJECT_NAME = "createEnumClass";
070 private static final String TRAIT_OBJECT_NAME = "createTrait";
071 private static final String OBJECT_OBJECT_NAME = "createObject";
072 private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
073 private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
074 private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
075 private static final String CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty";
076 private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty";
077 private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty";
078
079 private static final String SETTER_PREFIX = "set_";
080 private static final String GETTER_PREFIX = "get_";
081 private static final String BACKING_FIELD_PREFIX = "$";
082 private static final String DELEGATE = "$delegate";
083
084 private static final String SUPER_METHOD_NAME = "baseInitializer";
085
086 private static final String ROOT_PACKAGE = "_";
087
088 private static final String RECEIVER_PARAMETER_NAME = "$receiver";
089 public static final String ANOTHER_THIS_PARAMETER_NAME = "$this";
090
091 private static final String THROW_NPE_FUN_NAME = "throwNPE";
092 private static final String COMPANION_OBJECT_GETTER = "object";
093 private static final String COMPANION_OBJECT_INITIALIZER = "object_initializer$";
094 private static final String PROTOTYPE_NAME = "prototype";
095 public static final String CAPTURED_VAR_FIELD = "v";
096
097 public static final JsNameRef CREATE_INLINE_FUNCTION = new JsNameRef("defineInlineFunction", KOTLIN_OBJECT_REF);
098
099 @NotNull
100 public static final JsExpression UNDEFINED_EXPRESSION = new JsPrefixOperation(JsUnaryOperator.VOID, JsNumberLiteral.ZERO);
101
102 private static final JsNameRef JS_OBJECT = new JsNameRef("Object");
103 private static final JsNameRef JS_OBJECT_CREATE_FUNCTION = new JsNameRef("create", JS_OBJECT);
104
105 public static boolean isUndefined(@NotNull JsExpression expr) {
106 if (expr instanceof JsPrefixOperation) {
107 JsUnaryOperator op = ((JsPrefixOperation) expr).getOperator();
108
109 return op == JsUnaryOperator.VOID;
110 }
111
112 return false;
113 }
114
115 @NotNull
116 public static String getFunctionTag(@NotNull CallableDescriptor functionDescriptor) {
117 String moduleName = getModuleName(functionDescriptor);
118 FqNameUnsafe fqNameParent = DescriptorUtils.getFqName(functionDescriptor).parent();
119 String qualifier = null;
120
121 if (!fqNameParent.isRoot()) {
122 qualifier = fqNameParent.asString();
123 }
124
125 String mangledName = getSuggestedName(functionDescriptor);
126 return StringUtil.join(Arrays.asList(moduleName, qualifier, mangledName), ".");
127 }
128
129 @NotNull
130 public static String getReceiverParameterName() {
131 return RECEIVER_PARAMETER_NAME;
132 }
133
134 @NotNull
135 public static String getRootPackageName() {
136 return ROOT_PACKAGE;
137 }
138
139 @NotNull
140 public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) {
141 return new JsNameRef(SUPER_METHOD_NAME, superClassJsName.makeRef());
142 }
143
144 @NotNull
145 public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter, boolean useNativeAccessor) {
146 if (useNativeAccessor) {
147 return propertyName;
148 }
149
150 if (isGetter) {
151 return getNameForGetter(propertyName);
152 }
153 else {
154 return getNameForSetter(propertyName);
155 }
156 }
157
158 @NotNull
159 public static String getKotlinBackingFieldName(@NotNull String propertyName) {
160 return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX);
161 }
162
163 @NotNull
164 private static String getNameForGetter(@NotNull String propertyName) {
165 return getNameWithPrefix(propertyName, GETTER_PREFIX);
166 }
167
168 @NotNull
169 private static String getNameForSetter(@NotNull String propertyName) {
170 return getNameWithPrefix(propertyName, SETTER_PREFIX);
171 }
172
173 @NotNull
174 public static JsExpression getCompanionObjectAccessor(@NotNull JsExpression referenceToClass) {
175 return new JsNameRef(COMPANION_OBJECT_GETTER, referenceToClass);
176 }
177
178 @NotNull
179 public static String getNameForCompanionObjectInitializer() {
180 return COMPANION_OBJECT_INITIALIZER;
181 }
182
183 @NotNull
184 public static String getPrototypeName() {
185 return PROTOTYPE_NAME;
186 }
187
188 @NotNull
189 public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
190 return new JsNameRef(getPrototypeName(), classOrTraitExpression);
191 }
192
193 @NotNull
194 public static String getDelegatePrefix() {
195 return DELEGATE;
196 }
197
198 @NotNull
199 public static String getDelegateName(@NotNull String propertyName) {
200 return propertyName + DELEGATE;
201 }
202
203 @NotNull
204 public static JsNameRef getDelegateNameRef(String propertyName) {
205 return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS);
206 }
207
208 @NotNull
209 private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) {
210 return prefix + name;
211 }
212
213 @NotNull
214 public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
215 return new JsNameRef(CALL_FUNCTION, functionExpression);
216 }
217
218 @NotNull
219 public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) {
220 return new JsNameRef(APPLY_FUNCTION, functionExpression);
221 }
222
223 @NotNull
224 public static JsInvocation createObjectWithPrototypeFrom(JsNameRef referenceToClass) {
225 return new JsInvocation(JS_OBJECT_CREATE_FUNCTION, getRefToPrototype(referenceToClass));
226 }
227
228 @NotNull
229 public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) {
230 return new JsNameRef(CAPTURED_VAR_FIELD, ref);
231 }
232
233 @NotNull
234 public static String isInstanceSuggestedName(@NotNull TypeParameterDescriptor descriptor) {
235 return "is" + descriptor.getName().getIdentifier();
236 }
237
238 @NotNull
239 public static Namer newInstance(@NotNull JsScope rootScope) {
240 return new Namer(rootScope);
241 }
242
243 @NotNull
244 private final JsName kotlinName;
245 @NotNull
246 private final JsObjectScope kotlinScope;
247 @NotNull
248 private final JsName className;
249 @NotNull
250 private final JsName enumClassName;
251 @NotNull
252 private final JsName traitName;
253 @NotNull
254 private final JsExpression definePackage;
255 @NotNull
256 private final JsExpression defineRootPackage;
257 @NotNull
258 private final JsName objectName;
259 @NotNull
260 private final JsName callableRefForMemberFunctionName;
261 @NotNull
262 private final JsName callableRefForExtensionFunctionName;
263 @NotNull
264 private final JsName callableRefForConstructorName;
265 @NotNull
266 private final JsName callableRefForTopLevelProperty;
267 @NotNull
268 private final JsName callableRefForMemberProperty;
269 @NotNull
270 private final JsName callableRefForExtensionProperty;
271 @NotNull
272 private final JsExpression callGetProperty;
273 @NotNull
274 private final JsExpression callSetProperty;
275
276 @NotNull
277 private final JsName isTypeName;
278
279 @NotNull
280 private final JsExpression modulesMap;
281
282 private Namer(@NotNull JsScope rootScope) {
283 kotlinName = rootScope.declareName(KOTLIN_NAME);
284 kotlinScope = JsObjectScope(rootScope, "Kotlin standard object");
285 traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME);
286
287 definePackage = kotlin("definePackage");
288 defineRootPackage = kotlin("defineRootPackage");
289
290 callGetProperty = kotlin("callGetter");
291 callSetProperty = kotlin("callSetter");
292
293 className = kotlinScope.declareName(CLASS_OBJECT_NAME);
294 enumClassName = kotlinScope.declareName(ENUM_CLASS_OBJECT_NAME);
295 objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
296 callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
297 callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
298 callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
299 callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY);
300 callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY);
301 callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY);
302
303 isTypeName = kotlinScope.declareName("isType");
304 modulesMap = kotlin("modules");
305 }
306
307 @NotNull
308 public JsExpression classCreationMethodReference() {
309 return kotlin(className);
310 }
311
312 @NotNull
313 public JsExpression enumClassCreationMethodReference() {
314 return kotlin(enumClassName);
315 }
316
317 @NotNull
318 public JsExpression traitCreationMethodReference() {
319 return kotlin(traitName);
320 }
321
322 @NotNull
323 public JsExpression packageDefinitionMethodReference() {
324 return definePackage;
325 }
326
327 @NotNull
328 public JsExpression rootPackageDefinitionMethodReference() {
329 return defineRootPackage;
330 }
331
332 @NotNull
333 public JsExpression objectCreationMethodReference() {
334 return kotlin(objectName);
335 }
336
337 @NotNull
338 public JsExpression callableRefForMemberFunctionReference() {
339 return kotlin(callableRefForMemberFunctionName);
340 }
341
342 @NotNull
343 public JsExpression callableRefForExtensionFunctionReference() {
344 return kotlin(callableRefForExtensionFunctionName);
345 }
346
347 @NotNull
348 public JsExpression callableRefForConstructorReference() {
349 return kotlin(callableRefForConstructorName);
350 }
351
352 @NotNull
353 public JsExpression callableRefForTopLevelPropertyReference() {
354 return kotlin(callableRefForTopLevelProperty);
355 }
356
357 @NotNull
358 public JsExpression callableRefForMemberPropertyReference() {
359 return kotlin(callableRefForMemberProperty);
360 }
361
362 @NotNull
363 public JsExpression callableRefForExtensionPropertyReference() {
364 return kotlin(callableRefForExtensionProperty);
365 }
366
367 @NotNull
368 public JsExpression throwNPEFunctionRef() {
369 return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
370 }
371
372 @NotNull
373 private JsNameRef kotlin(@NotNull JsName name) {
374 return new JsNameRef(name, kotlinObject());
375 }
376
377 @NotNull
378 public JsExpression kotlin(@NotNull String name) {
379 return kotlin(kotlinScope.declareName(name));
380 }
381
382 @NotNull
383 public JsNameRef kotlinObject() {
384 return kotlinName.makeRef();
385 }
386
387 @NotNull
388 public JsExpression isTypeOf(@NotNull JsExpression type) {
389 JsInvocation invocation = new JsInvocation(kotlin("isTypeOf"), type);
390 MetadataPackage.setTypeCheck(invocation, TypeCheck.TYPEOF);
391 return invocation;
392 }
393
394 @NotNull
395 public JsExpression isInstanceOf(@NotNull JsExpression type) {
396 JsInvocation invocation = new JsInvocation(kotlin("isInstanceOf"), type);
397 MetadataPackage.setTypeCheck(invocation, TypeCheck.INSTANCEOF);
398 return invocation;
399 }
400
401 @NotNull
402 public JsExpression isInstanceOf(@NotNull JsExpression instance, @NotNull JsExpression type) {
403 return new JsInvocation(kotlin(isTypeName), instance, type);
404 }
405
406 @NotNull
407 /*package*/ JsObjectScope getKotlinScope() {
408 return kotlinScope;
409 }
410
411 @NotNull
412 static String generatePackageName(@NotNull FqName packageFqName) {
413 return packageFqName.isRoot() ? getRootPackageName() : packageFqName.shortName().asString();
414 }
415
416 @NotNull
417 public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) {
418 switch (descriptor.getKind()) {
419 case INTERFACE:
420 return traitCreationMethodReference();
421 case ENUM_CLASS:
422 return enumClassCreationMethodReference();
423 case ENUM_ENTRY:
424 case OBJECT:
425 return objectCreationMethodReference();
426 case ANNOTATION_CLASS:
427 case CLASS:
428 return DescriptorUtils.isAnonymousObject(descriptor)
429 ? objectCreationMethodReference()
430 : classCreationMethodReference();
431 default:
432 throw new UnsupportedOperationException("Unsupported class kind: " + descriptor);
433 }
434 }
435
436 @NotNull
437 public JsExpression getUndefinedExpression() {
438 return UNDEFINED_EXPRESSION;
439 }
440
441 @NotNull
442 public JsExpression getCallGetProperty() {
443 return callGetProperty;
444 }
445
446 @NotNull
447 public JsExpression getCallSetProperty() {
448 return callSetProperty;
449 }
450
451 @NotNull
452 public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) {
453 return new JsArrayAccess(modulesMap, moduleName);
454 }
455 }