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