001    /*
002     * Copyright 2010-2013 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.k2js.translate.context;
018    
019    import com.google.dart.compiler.backend.js.ast.*;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
022    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
023    import org.jetbrains.jet.lang.resolve.name.FqName;
024    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
025    import org.jetbrains.jet.plugin.JetLanguage;
026    
027    import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope;
028    import static org.jetbrains.k2js.translate.utils.TranslationUtils.getStableMangledNameForDescriptor;
029    
030    /**
031     * Encapuslates different types of constants and naming conventions.
032     */
033    public final class Namer {
034        public static final String KOTLIN_NAME = JetLanguage.NAME;
035        public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase();
036        public static final JsNameRef KOTLIN_OBJECT_REF = new JsNameRef(KOTLIN_NAME);
037    
038        public static final String EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getAny(), "equals");
039        public static final String COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getComparable(), "compareTo");
040        public static final String NUMBER_RANGE = "NumberRange";
041        public static final String CHAR_RANGE = "CharRange";
042        public static final String LONG_FROM_NUMBER = "fromNumber";
043        public static final String LONG_TO_NUMBER = "toNumber";
044        public static final String LONG_FROM_INT = "fromInt";
045        public static final String PRIMITIVE_COMPARE_TO = "primitiveCompareTo";
046        public static final String IS_CHAR = "isChar";
047        public static final String IS_NUMBER = "isNumber";
048    
049        public static final String CALLEE_NAME = "$fun";
050    
051        private static final String CALL_FUNCTION = "call";
052        private static final String APPLY_FUNCTION = "apply";
053    
054        private static final String CLASS_OBJECT_NAME = "createClass";
055        private static final String ENUM_CLASS_OBJECT_NAME = "createEnumClass";
056        private static final String TRAIT_OBJECT_NAME = "createTrait";
057        private static final String OBJECT_OBJECT_NAME = "createObject";
058        private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
059        private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
060        private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
061        private static final String CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty";
062        private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty";
063        private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty";
064    
065        private static final String SETTER_PREFIX = "set_";
066        private static final String GETTER_PREFIX = "get_";
067        private static final String BACKING_FIELD_PREFIX = "$";
068        private static final String DELEGATE = "$delegate";
069    
070        private static final String SUPER_METHOD_NAME = "baseInitializer";
071    
072        private static final String ROOT_PACKAGE = "_";
073    
074        private static final String RECEIVER_PARAMETER_NAME = "$receiver";
075    
076        private static final String THROW_NPE_FUN_NAME = "throwNPE";
077        private static final String CLASS_OBJECT_GETTER = "object";
078        private static final String CLASS_OBJECT_INITIALIZER = "object_initializer$";
079        private static final String PROTOTYPE_NAME = "prototype";
080        public static final String CAPTURED_VAR_FIELD = "v";
081    
082        @NotNull
083        public static String getReceiverParameterName() {
084            return RECEIVER_PARAMETER_NAME;
085        }
086    
087        @NotNull
088        public static String getRootPackageName() {
089            return ROOT_PACKAGE;
090        }
091    
092        @NotNull
093        public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) {
094            return new JsNameRef(SUPER_METHOD_NAME, superClassJsName.makeRef());
095        }
096    
097        @NotNull
098        public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter, boolean useNativeAccessor) {
099            if (useNativeAccessor) {
100                return propertyName;
101            }
102    
103            if (isGetter) {
104                return getNameForGetter(propertyName);
105            }
106            else {
107                return getNameForSetter(propertyName);
108            }
109        }
110    
111        @NotNull
112        public static String getKotlinBackingFieldName(@NotNull String propertyName) {
113            return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX);
114        }
115    
116        @NotNull
117        private static String getNameForGetter(@NotNull String propertyName) {
118            return getNameWithPrefix(propertyName, GETTER_PREFIX);
119        }
120    
121        @NotNull
122        private static String getNameForSetter(@NotNull String propertyName) {
123            return getNameWithPrefix(propertyName, SETTER_PREFIX);
124        }
125    
126        @NotNull
127        public static JsExpression getClassObjectAccessor(@NotNull JsExpression referenceToClass) {
128            return new JsNameRef(CLASS_OBJECT_GETTER, referenceToClass);
129        }
130    
131        @NotNull
132        public static String getNameForClassObjectInitializer() {
133            return CLASS_OBJECT_INITIALIZER;
134        }
135    
136        @NotNull
137        public static String getPrototypeName() {
138            return PROTOTYPE_NAME;
139        }
140    
141        @NotNull
142        public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
143            return new JsNameRef(getPrototypeName(), classOrTraitExpression);
144        }
145    
146        @NotNull
147        public static String getDelegatePrefix() {
148            return DELEGATE;
149        }
150    
151        @NotNull
152        public static String getDelegateName(@NotNull String propertyName) {
153            return propertyName + DELEGATE;
154        }
155    
156        @NotNull
157        public static JsNameRef getDelegateNameRef(String propertyName) {
158            return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS);
159        }
160    
161        @NotNull
162        private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) {
163            return prefix + name;
164        }
165    
166        @NotNull
167        public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
168            return new JsNameRef(CALL_FUNCTION, functionExpression);
169        }
170    
171        @NotNull
172        public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) {
173            return new JsNameRef(APPLY_FUNCTION, functionExpression);
174        }
175    
176        @NotNull
177        public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) {
178            return new JsNameRef(CAPTURED_VAR_FIELD, ref);
179        }
180    
181        @NotNull
182        public static Namer newInstance(@NotNull JsScope rootScope) {
183            return new Namer(rootScope);
184        }
185    
186        @NotNull
187        private final JsName kotlinName;
188        @NotNull
189        private final JsObjectScope kotlinScope;
190        @NotNull
191        private final JsName className;
192        @NotNull
193        private final JsName enumClassName;
194        @NotNull
195        private final JsName traitName;
196        @NotNull
197        private final JsExpression definePackage;
198        @NotNull
199        private final JsExpression defineRootPackage;
200        @NotNull
201        private final JsName objectName;
202        @NotNull
203        private final JsName callableRefForMemberFunctionName;
204        @NotNull
205        private final JsName callableRefForExtensionFunctionName;
206        @NotNull
207        private final JsName callableRefForConstructorName;
208        @NotNull
209        private final JsName callableRefForTopLevelProperty;
210        @NotNull
211        private final JsName callableRefForMemberProperty;
212        @NotNull
213        private final JsName callableRefForExtensionProperty;
214        @NotNull
215        private final JsExpression undefinedExpression;
216        @NotNull
217        private final JsExpression callGetProperty;
218        @NotNull
219        private final JsExpression callSetProperty;
220    
221        @NotNull
222        private final JsName isTypeName;
223    
224        private Namer(@NotNull JsScope rootScope) {
225            kotlinName = rootScope.declareName(KOTLIN_NAME);
226            kotlinScope = JsObjectScope(rootScope, "Kotlin standard object");
227            traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME);
228    
229            definePackage = kotlin("definePackage");
230            defineRootPackage = kotlin("defineRootPackage");
231    
232            callGetProperty = kotlin("callGetter");
233            callSetProperty = kotlin("callSetter");
234    
235            className = kotlinScope.declareName(CLASS_OBJECT_NAME);
236            enumClassName = kotlinScope.declareName(ENUM_CLASS_OBJECT_NAME);
237            objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
238            callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
239            callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
240            callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
241            callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY);
242            callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY);
243            callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY);
244    
245            isTypeName = kotlinScope.declareName("isType");
246    
247            undefinedExpression = new JsPrefixOperation(JsUnaryOperator.VOID, rootScope.getProgram().getNumberLiteral(0));
248        }
249    
250        @NotNull
251        public JsExpression classCreationMethodReference() {
252            return kotlin(className);
253        }
254    
255        @NotNull
256        public JsExpression enumClassCreationMethodReference() {
257            return kotlin(enumClassName);
258        }
259    
260        @NotNull
261        public JsExpression traitCreationMethodReference() {
262            return kotlin(traitName);
263        }
264    
265        @NotNull
266        public JsExpression packageDefinitionMethodReference() {
267            return definePackage;
268        }
269    
270        @NotNull
271        public JsExpression rootPackageDefinitionMethodReference() {
272            return defineRootPackage;
273        }
274    
275        @NotNull
276        public JsExpression objectCreationMethodReference() {
277            return kotlin(objectName);
278        }
279    
280        @NotNull
281        public JsExpression callableRefForMemberFunctionReference() {
282            return kotlin(callableRefForMemberFunctionName);
283        }
284    
285        @NotNull
286        public JsExpression callableRefForExtensionFunctionReference() {
287            return kotlin(callableRefForExtensionFunctionName);
288        }
289    
290        @NotNull
291        public JsExpression callableRefForConstructorReference() {
292            return kotlin(callableRefForConstructorName);
293        }
294    
295        @NotNull
296        public JsExpression callableRefForTopLevelPropertyReference() {
297            return kotlin(callableRefForTopLevelProperty);
298        }
299    
300        @NotNull
301        public JsExpression callableRefForMemberPropertyReference() {
302            return kotlin(callableRefForMemberProperty);
303        }
304    
305        @NotNull
306        public JsExpression callableRefForExtensionPropertyReference() {
307            return kotlin(callableRefForExtensionProperty);
308        }
309    
310        @NotNull
311        public JsExpression throwNPEFunctionRef() {
312            return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
313        }
314    
315        @NotNull
316        private JsNameRef kotlin(@NotNull JsName name) {
317            return new JsNameRef(name, kotlinObject());
318        }
319    
320        @NotNull
321        public JsExpression kotlin(@NotNull String name) {
322            return kotlin(kotlinScope.declareName(name));
323        }
324    
325        @NotNull
326        public JsNameRef kotlinObject() {
327            return kotlinName.makeRef();
328        }
329    
330        @NotNull
331        public JsExpression isOperationReference() {
332            return kotlin(isTypeName);
333        }
334    
335        @NotNull
336        /*package*/ JsObjectScope getKotlinScope() {
337            return kotlinScope;
338        }
339    
340        @NotNull
341        static String generatePackageName(@NotNull FqName packageFqName) {
342            return packageFqName.isRoot() ? getRootPackageName() : packageFqName.shortName().asString();
343        }
344    
345        @NotNull
346        public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) {
347            switch (descriptor.getKind()) {
348                case TRAIT:
349                    return traitCreationMethodReference();
350                case ENUM_CLASS:
351                    return enumClassCreationMethodReference();
352                case ENUM_ENTRY:
353                case OBJECT:
354                case CLASS_OBJECT:
355                    return objectCreationMethodReference();
356                case ANNOTATION_CLASS:
357                case CLASS:
358                    return DescriptorUtils.isAnonymousObject(descriptor)
359                           ? objectCreationMethodReference()
360                           : classCreationMethodReference();
361                default:
362                    throw new UnsupportedOperationException("Unsupported class kind: " + descriptor);
363            }
364        }
365    
366        @NotNull
367        public JsExpression getUndefinedExpression() {
368            return undefinedExpression;
369        }
370    
371        @NotNull
372        public JsExpression getCallGetProperty() {
373            return callGetProperty;
374        }
375    
376        @NotNull
377        public JsExpression getCallSetProperty() {
378            return callSetProperty;
379        }
380    }