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