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    }