001 /* 002 * Copyright 2010-2016 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.kotlin.js.translate.context; 018 019 import com.google.dart.compiler.backend.js.ast.*; 020 import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; 021 import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; 022 import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck; 023 import com.intellij.openapi.util.text.StringUtil; 024 import org.jetbrains.annotations.NotNull; 025 import org.jetbrains.annotations.Nullable; 026 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 027 import org.jetbrains.kotlin.descriptors.CallableDescriptor; 028 import org.jetbrains.kotlin.descriptors.ClassDescriptor; 029 import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; 030 import org.jetbrains.kotlin.idea.KotlinLanguage; 031 import org.jetbrains.kotlin.js.resolve.JsPlatform; 032 import org.jetbrains.kotlin.name.FqName; 033 import org.jetbrains.kotlin.name.FqNameUnsafe; 034 import org.jetbrains.kotlin.resolve.DescriptorUtils; 035 036 import java.util.Arrays; 037 import java.util.Collections; 038 import java.util.List; 039 040 import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope; 041 import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects; 042 import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName; 043 import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor; 044 import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; 045 046 /** 047 * Encapsulates different types of constants and naming conventions. 048 */ 049 public final class Namer { 050 public static final String KOTLIN_NAME = KotlinLanguage.NAME; 051 public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase(); 052 053 public static final String EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getAny(), "equals"); 054 public static final String COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getComparable(), "compareTo"); 055 public static final String NUMBER_RANGE = "NumberRange"; 056 public static final String CHAR_RANGE = "CharRange"; 057 public static final String LONG_FROM_NUMBER = "fromNumber"; 058 public static final String LONG_TO_NUMBER = "toNumber"; 059 public static final String LONG_FROM_INT = "fromInt"; 060 public static final String LONG_ZERO = "ZERO"; 061 public static final String LONG_ONE = "ONE"; 062 public static final String LONG_NEG_ONE = "NEG_ONE"; 063 public static final String PRIMITIVE_COMPARE_TO = "primitiveCompareTo"; 064 public static final String IS_CHAR = "isChar"; 065 public static final String IS_NUMBER = "isNumber"; 066 public static final String IS_CHAR_SEQUENCE = "isCharSequence"; 067 068 public static final String CALLEE_NAME = "$fun"; 069 070 public static final String CALL_FUNCTION = "call"; 071 private static final String APPLY_FUNCTION = "apply"; 072 073 public static final String OUTER_FIELD_NAME = "$outer"; 074 075 private static final String CLASS_OBJECT_NAME = "createClass"; 076 private static final String ENUM_CLASS_OBJECT_NAME = "createEnumClass"; 077 private static final String TRAIT_OBJECT_NAME = "createTrait"; 078 private static final String OBJECT_OBJECT_NAME = "createObject"; 079 private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction"; 080 private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction"; 081 private static final String CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getCallableRefForLocalExtensionFunction"; 082 private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor"; 083 private static final String CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty"; 084 private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty"; 085 private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty"; 086 087 private static final String SETTER_PREFIX = "set_"; 088 private static final String GETTER_PREFIX = "get_"; 089 private static final String BACKING_FIELD_PREFIX = "$"; 090 private static final String DELEGATE = "$delegate"; 091 092 private static final String SUPER_METHOD_NAME = "baseInitializer"; 093 094 private static final String ROOT_PACKAGE = "_"; 095 096 private static final String RECEIVER_PARAMETER_NAME = "$receiver"; 097 public static final String ANOTHER_THIS_PARAMETER_NAME = "$this"; 098 099 private static final String THROW_NPE_FUN_NAME = "throwNPE"; 100 private static final String THROW_CLASS_CAST_EXCEPTION_FUN_NAME = "throwCCE"; 101 private static final String PROTOTYPE_NAME = "prototype"; 102 private static final String CAPTURED_VAR_FIELD = "v"; 103 104 public static final JsNameRef IS_ARRAY_FUN_REF = new JsNameRef("isArray", "Array"); 105 public static final String DEFINE_INLINE_FUNCTION = "defineInlineFunction"; 106 107 private static final JsNameRef JS_OBJECT = new JsNameRef("Object"); 108 private static final JsNameRef JS_OBJECT_CREATE_FUNCTION = new JsNameRef("create", JS_OBJECT); 109 110 public static boolean isUndefined(@NotNull JsExpression expr) { 111 if (expr instanceof JsPrefixOperation) { 112 JsUnaryOperator op = ((JsPrefixOperation) expr).getOperator(); 113 114 return op == JsUnaryOperator.VOID; 115 } 116 117 return false; 118 } 119 120 @NotNull 121 public static String getFunctionTag(@NotNull CallableDescriptor functionDescriptor) { 122 String moduleName = getModuleName(functionDescriptor); 123 FqNameUnsafe fqNameParent = DescriptorUtils.getFqName(functionDescriptor).parent(); 124 String qualifier = null; 125 126 if (!fqNameParent.isRoot()) { 127 qualifier = fqNameParent.asString(); 128 } 129 130 String mangledName = getSuggestedName(functionDescriptor); 131 return StringUtil.join(Arrays.asList(moduleName, qualifier, mangledName), "."); 132 } 133 134 @NotNull 135 public static String getReceiverParameterName() { 136 return RECEIVER_PARAMETER_NAME; 137 } 138 139 @NotNull 140 public static String getRootPackageName() { 141 return ROOT_PACKAGE; 142 } 143 144 @NotNull 145 public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) { 146 return fqnWithoutSideEffects(SUPER_METHOD_NAME, superClassJsName.makeRef()); 147 } 148 149 @NotNull 150 public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter, boolean useNativeAccessor) { 151 if (useNativeAccessor) { 152 return propertyName; 153 } 154 155 if (isGetter) { 156 return getNameForGetter(propertyName); 157 } 158 else { 159 return getNameForSetter(propertyName); 160 } 161 } 162 163 @NotNull 164 public static String getKotlinBackingFieldName(@NotNull String propertyName) { 165 return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX); 166 } 167 168 @NotNull 169 private static String getNameForGetter(@NotNull String propertyName) { 170 return getNameWithPrefix(propertyName, GETTER_PREFIX); 171 } 172 173 @NotNull 174 private static String getNameForSetter(@NotNull String propertyName) { 175 return getNameWithPrefix(propertyName, SETTER_PREFIX); 176 } 177 178 @NotNull 179 public static String getPrototypeName() { 180 return PROTOTYPE_NAME; 181 } 182 183 @NotNull 184 public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) { 185 return fqnWithoutSideEffects(getPrototypeName(), classOrTraitExpression); 186 } 187 188 @NotNull 189 public static String getDelegatePrefix() { 190 return DELEGATE; 191 } 192 193 @NotNull 194 public static String getDelegateName(@NotNull String propertyName) { 195 return propertyName + DELEGATE; 196 } 197 198 @NotNull 199 public static JsNameRef getDelegateNameRef(String propertyName) { 200 return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS); 201 } 202 203 @NotNull 204 private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) { 205 return prefix + name; 206 } 207 208 @NotNull 209 public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) { 210 return fqnWithoutSideEffects(CALL_FUNCTION, functionExpression); 211 } 212 213 @NotNull 214 public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) { 215 return fqnWithoutSideEffects(APPLY_FUNCTION, functionExpression); 216 } 217 218 @NotNull 219 public static JsInvocation createObjectWithPrototypeFrom(JsNameRef referenceToClass) { 220 return new JsInvocation(JS_OBJECT_CREATE_FUNCTION, getRefToPrototype(referenceToClass)); 221 } 222 223 @NotNull 224 public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) { 225 return fqnWithoutSideEffects(CAPTURED_VAR_FIELD, ref); 226 } 227 228 @NotNull 229 public static String isInstanceSuggestedName(@NotNull TypeParameterDescriptor descriptor) { 230 return "is" + descriptor.getName().getIdentifier(); 231 } 232 233 @NotNull 234 public static Namer newInstance(@NotNull JsScope rootScope) { 235 return new Namer(rootScope); 236 } 237 238 @NotNull 239 private final JsObjectScope kotlinScope; 240 @NotNull 241 private final JsName className; 242 @NotNull 243 private final JsName enumClassName; 244 @NotNull 245 private final JsName traitName; 246 @NotNull 247 private final JsExpression definePackage; 248 @NotNull 249 private final JsExpression defineRootPackage; 250 @NotNull 251 private final JsName objectName; 252 @NotNull 253 private final JsName callableRefForMemberFunctionName; 254 @NotNull 255 private final JsName callableRefForExtensionFunctionName; 256 @NotNull 257 private final JsName callableRefForLocalExtensionFunctionName; 258 @NotNull 259 private final JsName callableRefForConstructorName; 260 @NotNull 261 private final JsName callableRefForTopLevelProperty; 262 @NotNull 263 private final JsName callableRefForMemberProperty; 264 @NotNull 265 private final JsName callableRefForExtensionProperty; 266 @NotNull 267 private final JsExpression callGetProperty; 268 @NotNull 269 private final JsExpression callSetProperty; 270 271 @NotNull 272 private final JsName isTypeName; 273 274 @NotNull 275 private final JsExpression modulesMap; 276 277 private Namer(@NotNull JsScope rootScope) { 278 kotlinScope = JsObjectScope(rootScope, "Kotlin standard object"); 279 traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME); 280 281 definePackage = kotlin("definePackage"); 282 defineRootPackage = kotlin("defineRootPackage"); 283 284 callGetProperty = kotlin("callGetter"); 285 callSetProperty = kotlin("callSetter"); 286 287 className = kotlinScope.declareName(CLASS_OBJECT_NAME); 288 enumClassName = kotlinScope.declareName(ENUM_CLASS_OBJECT_NAME); 289 objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME); 290 callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME); 291 callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME); 292 callableRefForLocalExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME); 293 callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME); 294 callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY); 295 callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY); 296 callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY); 297 298 isTypeName = kotlinScope.declareName("isType"); 299 modulesMap = kotlin("modules"); 300 MetadataProperties.setSideEffects((HasMetadata) modulesMap, false); 301 } 302 303 @NotNull 304 public JsExpression classCreationMethodReference() { 305 return kotlin(className); 306 } 307 308 @NotNull 309 public JsExpression enumClassCreationMethodReference() { 310 return kotlin(enumClassName); 311 } 312 313 @NotNull 314 public JsExpression traitCreationMethodReference() { 315 return kotlin(traitName); 316 } 317 318 @NotNull 319 public JsExpression packageDefinitionMethodReference() { 320 return definePackage; 321 } 322 323 @NotNull 324 public JsExpression rootPackageDefinitionMethodReference() { 325 return defineRootPackage; 326 } 327 328 @NotNull 329 public JsExpression objectCreationMethodReference() { 330 return kotlin(objectName); 331 } 332 333 @NotNull 334 public JsExpression callableRefForMemberFunctionReference() { 335 return kotlin(callableRefForMemberFunctionName); 336 } 337 338 @NotNull 339 public JsExpression callableRefForExtensionFunctionReference() { 340 return kotlin(callableRefForExtensionFunctionName); 341 } 342 343 @NotNull 344 public JsExpression callableRefForLocalExtensionFunctionReference() { 345 return kotlin(callableRefForLocalExtensionFunctionName); 346 } 347 348 @NotNull 349 public JsExpression callableRefForConstructorReference() { 350 return kotlin(callableRefForConstructorName); 351 } 352 353 @NotNull 354 public JsExpression callableRefForTopLevelPropertyReference() { 355 return kotlin(callableRefForTopLevelProperty); 356 } 357 358 @NotNull 359 public JsExpression callableRefForMemberPropertyReference() { 360 return kotlin(callableRefForMemberProperty); 361 } 362 363 @NotNull 364 public JsExpression callableRefForExtensionPropertyReference() { 365 return kotlin(callableRefForExtensionProperty); 366 } 367 368 @NotNull 369 public static JsExpression throwNPEFunctionRef() { 370 return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject()); 371 } 372 373 @NotNull 374 public JsExpression throwClassCastExceptionFunRef() { 375 return new JsNameRef(THROW_CLASS_CAST_EXCEPTION_FUN_NAME, kotlinObject()); 376 } 377 378 @NotNull 379 public static JsNameRef kotlin(@NotNull JsName name) { 380 return fqnWithoutSideEffects(name, kotlinObject()); 381 } 382 383 @NotNull 384 public JsNameRef kotlin(@NotNull String name) { 385 return kotlin(kotlinScope.declareName(name)); 386 } 387 388 @NotNull 389 public static JsNameRef kotlinObject() { 390 return fqnWithoutSideEffects(KOTLIN_NAME, null); 391 } 392 393 @NotNull 394 public JsExpression isTypeOf(@NotNull JsExpression type) { 395 return invokeFunctionAndSetTypeCheckMetadata("isTypeOf", type, TypeCheck.TYPEOF); 396 } 397 398 @NotNull 399 public JsExpression isInstanceOf(@NotNull JsExpression type) { 400 return invokeFunctionAndSetTypeCheckMetadata("isInstanceOf", type, TypeCheck.INSTANCEOF); 401 } 402 403 @NotNull 404 public JsExpression orNull(@NotNull JsExpression callable) { 405 return invokeFunctionAndSetTypeCheckMetadata("orNull", callable, TypeCheck.OR_NULL); 406 } 407 408 @NotNull 409 public JsExpression andPredicate(@NotNull JsExpression a, @NotNull JsExpression b) { 410 return invokeFunctionAndSetTypeCheckMetadata("andPredicate", Arrays.asList(a, b), TypeCheck.AND_PREDICATE); 411 } 412 413 @NotNull 414 public JsExpression isAny() { 415 return invokeFunctionAndSetTypeCheckMetadata("isAny", Collections.<JsExpression>emptyList(), TypeCheck.IS_ANY); 416 } 417 418 @NotNull 419 public JsExpression isComparable() { 420 return kotlin("isComparable"); 421 } 422 423 @NotNull 424 public JsExpression isCharSequence() { 425 return kotlin(IS_CHAR_SEQUENCE); 426 } 427 428 @NotNull 429 private JsExpression invokeFunctionAndSetTypeCheckMetadata( 430 @NotNull String functionName, 431 @Nullable JsExpression argument, 432 @NotNull TypeCheck metadata 433 ) { 434 List<JsExpression> arguments = argument != null ? Collections.singletonList(argument) : Collections.<JsExpression>emptyList(); 435 return invokeFunctionAndSetTypeCheckMetadata(functionName, arguments, metadata); 436 } 437 438 @NotNull 439 private JsExpression invokeFunctionAndSetTypeCheckMetadata( 440 @NotNull String functionName, 441 @NotNull List<JsExpression> arguments, 442 @NotNull TypeCheck metadata 443 ) { 444 JsInvocation invocation = new JsInvocation(kotlin(functionName)); 445 invocation.getArguments().addAll(arguments); 446 MetadataProperties.setTypeCheck(invocation, metadata); 447 MetadataProperties.setSideEffects(invocation, false); 448 return invocation; 449 } 450 451 @NotNull 452 public JsExpression isInstanceOf(@NotNull JsExpression instance, @NotNull JsExpression type) { 453 JsInvocation result = new JsInvocation(kotlin(isTypeName), instance, type); 454 MetadataProperties.setSideEffects(result, false); 455 return result; 456 } 457 458 @NotNull 459 /*package*/ JsObjectScope getKotlinScope() { 460 return kotlinScope; 461 } 462 463 @NotNull 464 static String generatePackageName(@NotNull FqName packageFqName) { 465 return packageFqName.isRoot() ? getRootPackageName() : packageFqName.shortName().asString(); 466 } 467 468 @NotNull 469 public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) { 470 switch (descriptor.getKind()) { 471 case INTERFACE: 472 return traitCreationMethodReference(); 473 case ENUM_CLASS: 474 return enumClassCreationMethodReference(); 475 case ENUM_ENTRY: 476 case OBJECT: 477 return objectCreationMethodReference(); 478 case ANNOTATION_CLASS: 479 case CLASS: 480 return classCreationMethodReference(); 481 default: 482 throw new UnsupportedOperationException("Unsupported class kind: " + descriptor); 483 } 484 } 485 486 @NotNull 487 public static JsExpression getUndefinedExpression() { 488 return new JsPrefixOperation(JsUnaryOperator.VOID, JsNumberLiteral.ZERO); 489 } 490 491 @NotNull 492 public JsExpression getCallGetProperty() { 493 return callGetProperty; 494 } 495 496 @NotNull 497 public JsExpression getCallSetProperty() { 498 return callSetProperty; 499 } 500 501 @NotNull 502 public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) { 503 JsArrayAccess result = new JsArrayAccess(modulesMap, moduleName); 504 MetadataProperties.setSideEffects(result, false); 505 return result; 506 } 507 508 public static JsNameRef kotlinLong() { 509 return fqnWithoutSideEffects("Long", kotlinObject()); 510 } 511 512 @NotNull 513 public static JsNameRef createInlineFunction() { 514 return fqnWithoutSideEffects(DEFINE_INLINE_FUNCTION, kotlinObject()); 515 } 516 }