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.DeclarationDescriptor;
023    import org.jetbrains.jet.lang.descriptors.Named;
024    import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
025    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
026    import org.jetbrains.jet.plugin.JetLanguage;
027    import org.jetbrains.jet.lang.resolve.name.Name;
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        public static final String OUTER_CLASS_NAME = "$outer";
038    
039        private static final String INITIALIZE_METHOD_NAME = "initialize";
040        private static final String CLASS_OBJECT_NAME = "createClass";
041        private static final String TRAIT_OBJECT_NAME = "createTrait";
042        private static final String OBJECT_OBJECT_NAME = "createObject";
043        private static final String ENUM_ENTRIES_NAME = "createEnumEntries";
044        private static final String SETTER_PREFIX = "set_";
045        private static final String GETTER_PREFIX = "get_";
046        private static final String BACKING_FIELD_PREFIX = "$";
047        private static final String SUPER_METHOD_NAME = "super_init";
048        private static final String ROOT_NAMESPACE = "_";
049        private static final String RECEIVER_PARAMETER_NAME = "$receiver";
050        private static final String CLASSES_OBJECT_NAME = "classes";
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    
055    
056        private static final String DELEGATE_POSTFIX = "$delegate";
057        private static final String PROPERTY_METADATA = "PropertyMetadata";
058    
059        private static final Named CLASS_OBJECT_INITIALIZER_NAMED = new Named() {
060            @NotNull
061            @Override
062            public Name getName() {
063                return Name.identifier(CLASS_OBJECT_INITIALIZER);
064            }
065        };
066    
067        @NotNull
068        public static String getReceiverParameterName() {
069            return RECEIVER_PARAMETER_NAME;
070        }
071    
072        @NotNull
073        public static String getRootNamespaceName() {
074            return ROOT_NAMESPACE;
075        }
076    
077        @NotNull
078        public static JsNameRef initializeMethodReference() {
079            return new JsNameRef(INITIALIZE_METHOD_NAME);
080        }
081    
082        @NotNull
083        public static String superMethodName() {
084            return SUPER_METHOD_NAME;
085        }
086    
087        @NotNull
088        public static String nameForClassesVariable() {
089            return CLASSES_OBJECT_NAME;
090        }
091    
092        @NotNull
093        public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter, boolean useNativeAccessor) {
094            if (useNativeAccessor) {
095                return propertyName;
096            }
097    
098            if (isGetter) {
099                return getNameForGetter(propertyName);
100            }
101            else {
102                return getNameForSetter(propertyName);
103            }
104        }
105    
106        @NotNull
107        public static String getKotlinBackingFieldName(@NotNull String propertyName) {
108            return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX);
109        }
110    
111        @NotNull
112        private static String getNameForGetter(@NotNull String propertyName) {
113            return getNameWithPrefix(propertyName, GETTER_PREFIX);
114        }
115    
116        @NotNull
117        private static String getNameForSetter(@NotNull String propertyName) {
118            return getNameWithPrefix(propertyName, SETTER_PREFIX);
119        }
120    
121        @NotNull
122        public static JsExpression getClassObjectAccessor(@NotNull JsExpression referenceToClass) {
123            return new JsInvocation(new JsNameRef(CLASS_OBJECT_GETTER, referenceToClass));
124        }
125    
126        @NotNull
127        public static Named getNamedForClassObjectInitializer() {
128            return CLASS_OBJECT_INITIALIZER_NAMED;
129        }
130    
131        @NotNull
132        public static String getDelegateName(@NotNull String propertyName) {
133            return propertyName + DELEGATE_POSTFIX;
134        }
135    
136        @NotNull
137        public static JsNameRef getDelegateNameRef(String propertyName) {
138            return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS);
139        }
140    
141        @NotNull
142        private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) {
143            return prefix + name;
144        }
145    
146        @NotNull
147        public static Namer newInstance(@NotNull JsScope rootScope) {
148            return new Namer(rootScope);
149        }
150    
151        @NotNull
152        private final JsName kotlinName;
153        @NotNull
154        private final JsScope kotlinScope;
155        @NotNull
156        private final JsName className;
157        @NotNull
158        private final JsName traitName;
159        @NotNull
160        private final JsExpression definePackage;
161        @NotNull
162        private final JsName objectName;
163        @NotNull
164        private final JsName enumEntriesName;
165    
166        @NotNull
167        private final JsName isTypeName;
168    
169        private Namer(@NotNull JsScope rootScope) {
170            kotlinName = rootScope.declareName(KOTLIN_NAME);
171            kotlinScope = new JsScope(rootScope, "Kotlin standard object");
172            traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME);
173    
174            definePackage = kotlin("definePackage");
175    
176            className = kotlinScope.declareName(CLASS_OBJECT_NAME);
177            enumEntriesName = kotlinScope.declareName(ENUM_ENTRIES_NAME);
178            objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
179    
180            isTypeName = kotlinScope.declareName("isType");
181        }
182    
183        @NotNull
184        public JsExpression classCreationMethodReference() {
185            return kotlin(className);
186        }
187    
188        @NotNull
189        public JsExpression enumEntriesCreationMethodReference() {
190            return kotlin(enumEntriesName);
191        }
192    
193        @NotNull
194        public JsExpression traitCreationMethodReference() {
195            return kotlin(traitName);
196        }
197    
198        @NotNull
199        public JsExpression packageDefinitionMethodReference() {
200            return definePackage;
201        }
202    
203        @NotNull
204        public JsExpression objectCreationMethodReference() {
205            return kotlin(objectName);
206        }
207    
208        @NotNull
209        public JsExpression throwNPEFunctionRef() {
210            return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
211        }
212    
213        @NotNull
214        public JsNameRef propertyMetadataRef() {
215            return new JsNameRef(PROPERTY_METADATA, kotlinObject());
216        }
217    
218        @NotNull
219        private JsNameRef kotlin(@NotNull JsName name) {
220            return new JsNameRef(name, kotlinObject());
221        }
222    
223        @NotNull
224        public JsExpression kotlin(@NotNull String name) {
225            return kotlin(kotlinScope.declareName(name));
226        }
227    
228        @NotNull
229        public JsNameRef kotlinObject() {
230            return kotlinName.makeRef();
231        }
232    
233        @NotNull
234        public JsExpression isOperationReference() {
235            return kotlin(isTypeName);
236        }
237    
238        @NotNull
239            /*package*/ JsScope getKotlinScope() {
240            return kotlinScope;
241        }
242    
243        @NotNull
244        static String generateNamespaceName(DeclarationDescriptor descriptor) {
245            if (DescriptorUtils.isRootNamespace((NamespaceDescriptor) descriptor)) {
246                return getRootNamespaceName();
247            }
248            else {
249                return descriptor.getName().asString();
250            }
251        }
252    
253        @NotNull
254        public JsInvocation classCreateInvocation(@NotNull ClassDescriptor descriptor) {
255            switch (descriptor.getKind()) {
256                case TRAIT:
257                    return new JsInvocation(traitCreationMethodReference());
258    
259                case OBJECT:
260                case CLASS_OBJECT:
261                case ENUM_ENTRY:
262                    return new JsInvocation(objectCreationMethodReference());
263    
264                default:
265                    return new JsInvocation(classCreationMethodReference());
266            }
267        }
268    
269        @NotNull
270        public JsInvocation enumEntriesObjectCreateInvocation() {
271            return new JsInvocation(enumEntriesCreationMethodReference());
272        }
273    }