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