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.common.collect.Maps;
020 import com.google.dart.compiler.backend.js.ast.JsName;
021 import com.google.dart.compiler.backend.js.ast.JsObjectScope;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
026 import org.jetbrains.jet.lang.resolve.name.Name;
027
028 import java.util.Map;
029
030 import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope;
031 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
032
033 /**
034 * Provides a mechanism to bind some of the kotlin/java declations with library implementations.
035 * Makes sense only for those declaration that cannot be annotated. (Use library annotation in this case)
036 */
037 public final class StandardClasses {
038
039 private final class Builder {
040
041 @Nullable
042 private /*var*/ FqNameUnsafe currentFQName = null;
043 @Nullable
044 private /*var*/ String currentObjectName = null;
045
046 @NotNull
047 public Builder forFQ(@NotNull String classFQName) {
048 currentFQName = new FqNameUnsafe(classFQName);
049 return this;
050 }
051
052 @NotNull
053 public Builder kotlinClass(@NotNull String kotlinName) {
054 kotlinTopLevelObject(kotlinName);
055 constructor();
056 return this;
057 }
058
059 private void kotlinTopLevelObject(@NotNull String kotlinName) {
060 assert currentFQName != null;
061 currentObjectName = kotlinName;
062 declareKotlinObject(currentFQName, kotlinName);
063 }
064
065 @NotNull
066 private Builder constructor() {
067 assert currentFQName != null;
068 assert currentObjectName != null;
069 declareInner(currentFQName, "<init>", currentObjectName);
070 return this;
071 }
072
073 @NotNull
074 public Builder methods(@NotNull String... methodNames) {
075 assert currentFQName != null;
076 declareMethods(currentFQName, methodNames);
077 return this;
078 }
079
080 @NotNull
081 public Builder properties(@NotNull String... propertyNames) {
082 assert currentFQName != null;
083 declareReadonlyProperties(currentFQName, propertyNames);
084 return this;
085 }
086 }
087
088 @NotNull
089 public static StandardClasses bindImplementations(@NotNull JsObjectScope kotlinObjectScope) {
090 StandardClasses standardClasses = new StandardClasses(kotlinObjectScope);
091 declareKotlinStandardClasses(standardClasses);
092 return standardClasses;
093 }
094
095 private static void declareKotlinStandardClasses(@NotNull StandardClasses standardClasses) {
096 standardClasses.declare().forFQ("kotlin.Iterator").kotlinClass("Iterator").methods("next").properties("hasNext");
097
098 standardClasses.declare().forFQ("kotlin.IntRange").kotlinClass("NumberRange")
099 .methods("iterator", "contains").properties("start", "end", "increment");
100
101 standardClasses.declare().forFQ("kotlin.LongRange").kotlinClass("LongRange")
102 .methods("iterator", "contains").properties("start", "end", "increment");
103
104 standardClasses.declare().forFQ("kotlin.CharRange").kotlinClass("CharRange")
105 .methods("iterator", "contains").properties("start", "end", "increment");
106
107 standardClasses.declare().forFQ("kotlin.IntProgression").kotlinClass("NumberProgression")
108 .methods("iterator", "contains").properties("start", "end", "increment");
109
110 standardClasses.declare().forFQ("kotlin.LongProgression").kotlinClass("LongProgression")
111 .methods("iterator", "contains").properties("start", "end", "increment");
112
113 standardClasses.declare().forFQ("kotlin.CharProgression").kotlinClass("CharProgression")
114 .methods("iterator", "contains").properties("start", "end", "increment");
115
116 standardClasses.declare().forFQ("kotlin.Enum").kotlinClass("Enum");
117
118 standardClasses.declare().forFQ("kotlin.Comparable").kotlinClass("Comparable");
119 }
120
121
122 @NotNull
123 private final JsObjectScope kotlinScope;
124
125
126 @NotNull
127 private final Map<FqNameUnsafe, JsName> standardObjects = Maps.newHashMap();
128
129 @NotNull
130 private final Map<FqNameUnsafe, JsObjectScope> scopeMap = Maps.newHashMap();
131
132 private StandardClasses(@NotNull JsObjectScope kotlinScope) {
133 this.kotlinScope = kotlinScope;
134 }
135
136 private void declareTopLevelObjectInScope(@NotNull JsObjectScope scope, @NotNull Map<FqNameUnsafe, JsName> map,
137 @NotNull FqNameUnsafe fullQualifiedName, @NotNull String name) {
138 JsName declaredName = scope.declareName(name);
139 map.put(fullQualifiedName, declaredName);
140 scopeMap.put(fullQualifiedName, JsObjectScope(scope, "scope for " + name));
141 }
142
143 private void declareKotlinObject(@NotNull FqNameUnsafe fullQualifiedName, @NotNull String kotlinLibName) {
144 declareTopLevelObjectInScope(kotlinScope, standardObjects, fullQualifiedName, kotlinLibName);
145 }
146
147 private void declareInner(@NotNull FqNameUnsafe fullQualifiedClassName,
148 @NotNull String shortMethodName,
149 @NotNull String javascriptName) {
150 JsObjectScope classScope = scopeMap.get(fullQualifiedClassName);
151 assert classScope != null;
152 FqNameUnsafe fullQualifiedMethodName = fullQualifiedClassName.child(Name.guess(shortMethodName));
153 standardObjects.put(fullQualifiedMethodName, classScope.declareName(javascriptName));
154 }
155
156 private void declareMethods(@NotNull FqNameUnsafe classFQName,
157 @NotNull String... methodNames) {
158 for (String methodName : methodNames) {
159 declareInner(classFQName, methodName, methodName);
160 }
161 }
162
163 private void declareReadonlyProperties(@NotNull FqNameUnsafe classFQName,
164 @NotNull String... propertyNames) {
165 for (String propertyName : propertyNames) {
166 declareInner(classFQName, propertyName, propertyName);
167 }
168 }
169
170 public boolean isStandardObject(@NotNull DeclarationDescriptor descriptor) {
171 return standardObjects.containsKey(getFqName(descriptor));
172 }
173
174 @NotNull
175 public JsName getStandardObjectName(@NotNull DeclarationDescriptor descriptor) {
176 return standardObjects.get(getFqName(descriptor));
177 }
178
179 @NotNull
180 private Builder declare() {
181 return new Builder();
182 }
183 }