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.descriptors.ClassKind;
023    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
024    import org.jetbrains.jet.lang.resolve.name.FqName;
025    import org.jetbrains.jet.plugin.JetLanguage;
026    
027    import static org.jetbrains.jet.lang.descriptors.ClassKind.TRAIT;
028    
029    /**
030     * Encapuslates different types of constants and naming conventions.
031     */
032    public final class Namer {
033        public static final String KOTLIN_NAME = JetLanguage.NAME;
034        public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase();
035    
036        public static final String CALLEE_NAME = "$fun";
037    
038        private static final String CALL_FUNCTION = "call";
039        private static final String APPLY_FUNCTION = "apply";
040    
041        private static final String CLASS_OBJECT_NAME = "createClass";
042        private static final String TRAIT_OBJECT_NAME = "createTrait";
043        private static final String OBJECT_OBJECT_NAME = "createObject";
044        private static final String ENUM_ENTRIES_NAME = "createEnumEntries";
045    
046        private static final String SETTER_PREFIX = "set_";
047        private static final String GETTER_PREFIX = "get_";
048        private static final String BACKING_FIELD_PREFIX = "$";
049        private static final String DELEGATE_POSTFIX = "$delegate";
050    
051        private static final String SUPER_METHOD_NAME = "baseInitializer";
052    
053        private static final String ROOT_PACKAGE = "_";
054    
055        private static final String RECEIVER_PARAMETER_NAME = "$receiver";
056    
057        private static final String THROW_NPE_FUN_NAME = "throwNPE";
058        private static final String CLASS_OBJECT_GETTER = "object";
059        private static final String CLASS_OBJECT_INITIALIZER = "object_initializer$";
060        private static final String PROTOTYPE_NAME = "prototype";
061        public static final String CAPTURED_VAR_FIELD = "v";
062    
063        @NotNull
064        public static String getReceiverParameterName() {
065            return RECEIVER_PARAMETER_NAME;
066        }
067    
068        @NotNull
069        public static String getRootPackageName() {
070            return ROOT_PACKAGE;
071        }
072    
073        @NotNull
074        public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) {
075            return new JsNameRef(SUPER_METHOD_NAME, superClassJsName.makeRef());
076        }
077    
078        @NotNull
079        public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter, boolean useNativeAccessor) {
080            if (useNativeAccessor) {
081                return propertyName;
082            }
083    
084            if (isGetter) {
085                return getNameForGetter(propertyName);
086            }
087            else {
088                return getNameForSetter(propertyName);
089            }
090        }
091    
092        @NotNull
093        public static String getKotlinBackingFieldName(@NotNull String propertyName) {
094            return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX);
095        }
096    
097        @NotNull
098        private static String getNameForGetter(@NotNull String propertyName) {
099            return getNameWithPrefix(propertyName, GETTER_PREFIX);
100        }
101    
102        @NotNull
103        private static String getNameForSetter(@NotNull String propertyName) {
104            return getNameWithPrefix(propertyName, SETTER_PREFIX);
105        }
106    
107        @NotNull
108        public static JsExpression getClassObjectAccessor(@NotNull JsExpression referenceToClass) {
109            return new JsNameRef(CLASS_OBJECT_GETTER, referenceToClass);
110        }
111    
112        @NotNull
113        public static String getNameForClassObjectInitializer() {
114            return CLASS_OBJECT_INITIALIZER;
115        }
116    
117        @NotNull
118        public static String getPrototypeName() {
119            return PROTOTYPE_NAME;
120        }
121    
122        @NotNull
123        public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
124            return new JsNameRef(getPrototypeName(), classOrTraitExpression);
125        }
126    
127        @NotNull
128        public static String getDelegateName(@NotNull String propertyName) {
129            return propertyName + DELEGATE_POSTFIX;
130        }
131    
132        @NotNull
133        public static JsNameRef getDelegateNameRef(String propertyName) {
134            return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS);
135        }
136    
137        @NotNull
138        private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) {
139            return prefix + name;
140        }
141    
142        @NotNull
143        public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
144            return new JsNameRef(CALL_FUNCTION, functionExpression);
145        }
146    
147        @NotNull
148        public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) {
149            return new JsNameRef(APPLY_FUNCTION, functionExpression);
150        }
151    
152        @NotNull
153        public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) {
154            return new JsNameRef(CAPTURED_VAR_FIELD, ref);
155        }
156    
157        @NotNull
158        public static Namer newInstance(@NotNull JsScope rootScope) {
159            return new Namer(rootScope);
160        }
161    
162        @NotNull
163        private final JsName kotlinName;
164        @NotNull
165        private final JsScope kotlinScope;
166        @NotNull
167        private final JsName className;
168        @NotNull
169        private final JsName traitName;
170        @NotNull
171        private final JsExpression definePackage;
172        @NotNull
173        private final JsExpression defineRootPackage;
174        @NotNull
175        private final JsName objectName;
176        @NotNull
177        private final JsName enumEntriesName;
178        @NotNull
179        private final JsExpression undefinedExpression;
180        @NotNull
181        private final JsExpression callGetProperty;
182        @NotNull
183        private final JsExpression callSetProperty;
184    
185        @NotNull
186        private final JsName isTypeName;
187    
188        private Namer(@NotNull JsScope rootScope) {
189            kotlinName = rootScope.declareName(KOTLIN_NAME);
190            kotlinScope = new JsScope(rootScope, "Kotlin standard object");
191            traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME);
192    
193            definePackage = kotlin("definePackage");
194            defineRootPackage = kotlin("defineRootPackage");
195    
196            callGetProperty = kotlin("callGetter");
197            callSetProperty = kotlin("callSetter");
198    
199            className = kotlinScope.declareName(CLASS_OBJECT_NAME);
200            enumEntriesName = kotlinScope.declareName(ENUM_ENTRIES_NAME);
201            objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
202    
203            isTypeName = kotlinScope.declareName("isType");
204    
205            undefinedExpression = new JsPrefixOperation(JsUnaryOperator.VOID, rootScope.getProgram().getNumberLiteral(0));
206        }
207    
208        @NotNull
209        public JsExpression classCreationMethodReference() {
210            return kotlin(className);
211        }
212    
213        @NotNull
214        public JsExpression enumEntriesCreationMethodReference() {
215            return kotlin(enumEntriesName);
216        }
217    
218        @NotNull
219        public JsExpression traitCreationMethodReference() {
220            return kotlin(traitName);
221        }
222    
223        @NotNull
224        public JsExpression packageDefinitionMethodReference() {
225            return definePackage;
226        }
227    
228        @NotNull
229        public JsExpression rootPackageDefinitionMethodReference() {
230            return defineRootPackage;
231        }
232    
233        @NotNull
234        public JsExpression objectCreationMethodReference() {
235            return kotlin(objectName);
236        }
237    
238        @NotNull
239        public JsExpression throwNPEFunctionRef() {
240            return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
241        }
242    
243        @NotNull
244        private JsNameRef kotlin(@NotNull JsName name) {
245            return new JsNameRef(name, kotlinObject());
246        }
247    
248        @NotNull
249        public JsExpression kotlin(@NotNull String name) {
250            return kotlin(kotlinScope.declareName(name));
251        }
252    
253        @NotNull
254        public JsNameRef kotlinObject() {
255            return kotlinName.makeRef();
256        }
257    
258        @NotNull
259        public JsExpression isOperationReference() {
260            return kotlin(isTypeName);
261        }
262    
263        @NotNull
264            /*package*/ JsScope getKotlinScope() {
265            return kotlinScope;
266        }
267    
268        @NotNull
269        static String generatePackageName(@NotNull FqName packageFqName) {
270            return packageFqName.isRoot() ? getRootPackageName() : packageFqName.shortName().asString();
271        }
272    
273        @NotNull
274        public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) {
275            ClassKind kind = descriptor.getKind();
276            if (kind == TRAIT) {
277                return traitCreationMethodReference();
278            }
279    
280            if (kind.isSingleton() || DescriptorUtils.isAnonymousObject(descriptor)) {
281                return objectCreationMethodReference();
282            }
283    
284            return classCreationMethodReference();
285        }
286    
287        @NotNull
288        public JsInvocation enumEntriesObjectCreateInvocation() {
289            return new JsInvocation(enumEntriesCreationMethodReference());
290        }
291    
292        @NotNull
293        public JsExpression getUndefinedExpression() {
294            return undefinedExpression;
295        }
296    
297        @NotNull
298        public JsExpression getCallGetProperty() {
299            return callGetProperty;
300        }
301    
302        @NotNull
303        public JsExpression getCallSetProperty() {
304            return callSetProperty;
305        }
306    }