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