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