JS: refactor range and progression related intrinsics

This commit is contained in:
Alexey Andreev
2016-11-10 15:08:54 +03:00
parent 5ef8879aae
commit dcb95eb9f0
6 changed files with 67 additions and 126 deletions
@@ -56,8 +56,6 @@ public final class Namer {
public static final String EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getAny(), "equals");
public static final String COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getComparable(), "compareTo");
public static final String INT_RANGE = "kotlin.ranges.IntRange";
public static final String CHAR_RANGE = "kotlin.ranges.CharRange";
public static final String LONG_FROM_NUMBER = "fromNumber";
public static final String LONG_TO_NUMBER = "toNumber";
public static final String LONG_FROM_INT = "fromInt";
@@ -1,50 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.intrinsic.functions.basic
import com.google.dart.compiler.backend.js.ast.JsExpression
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
class FqnCallIntrinsic(
simpleName: String,
fqn: String,
isConstructor: Boolean = false,
receiverAsArgument: Boolean = true
) : LazyImportedCallIntrinsic(simpleName, isConstructor = isConstructor, receiverAsArgument = receiverAsArgument) {
val fqn = FqName(fqn)
override fun getExpression(context: TranslationContext): JsExpression {
val packageDescriptor = context.currentModule.getPackage(fqn.parent())
// Hack to compile stdlib
val descriptors = packageDescriptor.memberScope.getContributedDescriptors(DescriptorKindFilter.ALL) {
it.asString() == fqn.shortName().asString()
}
return if (descriptors.size == 1) {
JsAstUtils.replaceRootReference(context.getQualifiedReference(fqn), Namer.kotlinObject())
}
else {
ReferenceTranslator.translateAsValueReference(descriptors.first(), context)
}
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.intrinsic.functions.basic
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.utils.singletonOrEmptyList
import java.util.*
abstract class LazyImportedCallIntrinsic(
val simpleName: String,
val isConstructor: Boolean = false,
val receiverAsArgument: Boolean = true
) : FunctionIntrinsic() {
private val internalNameMap = WeakHashMap<TranslationContext, JsName>()
override fun apply(receiver: JsExpression?, arguments: MutableList<JsExpression>, context: TranslationContext): JsExpression {
val rootContext = generateSequence(context) { it.parent }.last()
val functionName = internalNameMap.getOrPut(rootContext) {
val declaration = getExpression(rootContext)
if (declaration is JsNameRef && declaration.name != null && declaration.qualifier == null) {
declaration.name!!
}
else {
rootContext.importDeclaration(simpleName, declaration)
}
}
val allArguments = (if (receiverAsArgument) receiver else null).singletonOrEmptyList() + arguments
val function = pureFqn(functionName, null)
return if (isConstructor) JsNew(function, allArguments) else JsInvocation(function, allArguments)
}
abstract fun getExpression(context: TranslationContext): JsExpression
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.intrinsic.functions.basic
import com.google.dart.compiler.backend.js.ast.JsExpression
import com.google.dart.compiler.backend.js.ast.JsNew
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.utils.singletonOrEmptyList
class RangeToIntrinsic(function: FunctionDescriptor) : FunctionIntrinsic() {
val rangeTypeDescriptor = function.returnType!!.constructor.declarationDescriptor as ClassDescriptor
override fun apply(receiver: JsExpression?, arguments: MutableList<JsExpression>, context: TranslationContext): JsExpression {
val packageName = (rangeTypeDescriptor.containingDeclaration as PackageFragmentDescriptor).fqName
val packageDescriptor = context.currentModule.getPackage(packageName)
val existingClasses = packageDescriptor.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) {
it == rangeTypeDescriptor.name
}
val finalClass = (existingClasses.firstOrNull() as? ClassDescriptor) ?: rangeTypeDescriptor
val constructor = ReferenceTranslator.translateAsTypeReference(finalClass, context)
return JsNew(constructor, receiver.singletonOrEmptyList() + arguments)
}
}
@@ -28,10 +28,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
import org.jetbrains.kotlin.js.patterns.NamePredicate;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FqnCallIntrinsic;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.RangeToIntrinsic;
import org.jetbrains.kotlin.js.translate.operation.OperatorTable;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.lexer.KtToken;
@@ -62,12 +61,6 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
}
}
@NotNull
private static final FunctionIntrinsic RANGE_TO_INTRINSIC = new FqnCallIntrinsic("IntRange", Namer.INT_RANGE, true, true);
@NotNull
private static final FunctionIntrinsic CHAR_RANGE_TO_INTRINSIC = new FqnCallIntrinsic("CharRange", Namer.CHAR_RANGE, true, true);
@NotNull
private static final BinaryOperationIntrinsicBase INTEGER_DIVISION_INTRINSIC = new BinaryOperationIntrinsicBase() {
@NotNull
@@ -127,7 +120,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
@Override
public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) {
if (pattern("Char.rangeTo(Char)").apply(descriptor)) {
return CHAR_RANGE_TO_INTRINSIC;
return new RangeToIntrinsic(descriptor);
}
if (PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS.apply(descriptor)) {
@@ -148,7 +141,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
return INTEGER_DIVISION_INTRINSIC;
}
if (descriptor.getName().equals(Name.identifier("rangeTo"))) {
return RANGE_TO_INTRINSIC;
return new RangeToIntrinsic(descriptor);
}
if (INT_WITH_BIT_OPERATIONS.apply(descriptor)) {
JsBinaryOperator op = BINARY_BITWISE_OPERATIONS.get(descriptor.getName().asString());
@@ -18,26 +18,33 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories
import com.google.dart.compiler.backend.js.ast.JsExpression
import com.google.dart.compiler.backend.js.ast.JsNew
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FqnCallIntrinsic
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
object ProgressionCompanionFIF : CompositeFIF() {
init {
val numberProgressionConstructor = FqnCallIntrinsic("IntProgression", "kotlin.ranges.IntProgression", isConstructor = true,
receiverAsArgument = false)
for (type in arrayOf(PrimitiveType.INT)) {
add(methodPattern("${type.typeName}Progression"), numberProgressionConstructor)
}
add(methodPattern("LongProgression"), FqnCallIntrinsic("LongProgression", "kotlin.ranges.LongProgression", isConstructor = true,
receiverAsArgument = false))
add(methodPattern("CharProgression"), FqnCallIntrinsic("CharProgression", "kotlin.ranges.CharProgression", isConstructor = true,
receiverAsArgument = false))
}
object ProgressionCompanionFIF : FunctionIntrinsicFactory {
val patterns = listOf(methodPattern("IntProgression"), methodPattern("LongProgression"), methodPattern("CharProgression"))
private fun methodPattern(builtinProgressionName: String) =
pattern("kotlin.ranges", builtinProgressionName, "Companion", "fromClosedRange")
override fun getIntrinsic(descriptor: FunctionDescriptor): FunctionIntrinsic? =
if (patterns.any { it.apply(descriptor) }) {
FromClosedRangeIntrinsic(descriptor)
}
else {
null
}
private class FromClosedRangeIntrinsic(descriptor: FunctionDescriptor) : FunctionIntrinsic() {
val progressionType = descriptor.containingDeclaration.containingDeclaration as ClassDescriptor
override fun apply(receiver: JsExpression?, arguments: MutableList<JsExpression>, context: TranslationContext): JsExpression {
val constructor = ReferenceTranslator.translateAsTypeReference(progressionType, context)
return JsNew(constructor, arguments)
}
}
}