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