JS IR: support kotlin.test
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
|
||||
val IrDeclaration.isExpect get() = descriptor.let { it is MemberDescriptor && it.isExpect }
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceKey
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ConstructorPair
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
@@ -81,6 +82,17 @@ class JsIrBackendContext(
|
||||
}
|
||||
}
|
||||
|
||||
private var testContainerField: IrSimpleFunction? = null
|
||||
|
||||
val hasTests get() = testContainerField != null
|
||||
|
||||
val testContainer
|
||||
get() = testContainerField ?: JsIrBuilder.buildFunction("test fun", irBuiltIns.unitType, implicitDeclarationFile).apply {
|
||||
body = JsIrBuilder.buildBlockBody(emptyList())
|
||||
testContainerField = this
|
||||
implicitDeclarationFile.declarations += this
|
||||
}
|
||||
|
||||
override val sharedVariablesManager = JsSharedVariablesManager(irBuiltIns, implicitDeclarationFile)
|
||||
override val declarationFactory = JsDeclarationFactory()
|
||||
|
||||
@@ -224,6 +236,9 @@ class JsIrBackendContext(
|
||||
|
||||
val throwISEymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single())
|
||||
|
||||
val suiteFun = getFunctions(FqName("kotlin.test.suite")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) }
|
||||
val testFun = getFunctions(FqName("kotlin.test.test")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) }
|
||||
|
||||
val coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
|
||||
val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
|
||||
val coroutineImplResultSymbolGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner }
|
||||
|
||||
@@ -333,10 +333,17 @@ private val callsLoweringPhase = makeJsModulePhase(
|
||||
description = "Handle intrinsics"
|
||||
)
|
||||
|
||||
private val testGenerationPhase = makeJsModulePhase(
|
||||
::TestGenerator,
|
||||
name = "TestGenerationLowering",
|
||||
description = "Generate invocations to kotlin.test suite and test functions"
|
||||
)
|
||||
|
||||
val jsPhases = namedIrModulePhase(
|
||||
name = "IrModuleLowering",
|
||||
description = "IR module lowering",
|
||||
lower = expectDeclarationsRemovingPhase then
|
||||
lower = testGenerationPhase then
|
||||
expectDeclarationsRemovingPhase then
|
||||
functionInliningPhase then
|
||||
lateinitLoweringPhase then
|
||||
tailrecLoweringPhase then
|
||||
|
||||
@@ -5,27 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -149,6 +140,9 @@ object JsIrBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
fun buildAnonymousInitializer() =
|
||||
IrAnonymousInitializerImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor()))
|
||||
|
||||
fun buildGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
|
||||
IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, classSymbol)
|
||||
|
||||
@@ -257,6 +251,7 @@ object JsIrBuilder {
|
||||
fun buildBoolean(type: IrType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||
fun buildInt(type: IrType, v: Int) = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||
fun buildString(type: IrType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
|
||||
fun buildTry(type: IrType) = IrTryImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
|
||||
fun buildCatch(ex: IrVariable, block: IrBlockImpl) = IrCatchImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ex, block)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.isExpect
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.fqNameSafe
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class TestGenerator(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.declarations.forEach {
|
||||
if (it is IrClass) {
|
||||
generateTestCalls(it) { suiteForPackage(irFile.fqName).body }
|
||||
}
|
||||
|
||||
// TODO top-level functions
|
||||
}
|
||||
}
|
||||
|
||||
private val packageSuites = mutableMapOf<FqName, FunctionWithBody>()
|
||||
|
||||
private fun suiteForPackage(fqName: FqName) = packageSuites.getOrPut(fqName) {
|
||||
context.suiteFun!!.createInvocation(fqName.asString(), context.testContainer.body as IrBlockBody)
|
||||
}
|
||||
|
||||
private data class FunctionWithBody(val function: IrSimpleFunction, val body: IrBlockBody)
|
||||
|
||||
private fun IrSimpleFunctionSymbol.createInvocation(
|
||||
name: String,
|
||||
parentBody: IrBlockBody,
|
||||
ignored: Boolean = false
|
||||
): FunctionWithBody {
|
||||
val body = JsIrBuilder.buildBlockBody(emptyList())
|
||||
|
||||
val function = JsIrBuilder.buildFunction(
|
||||
"$name test fun",
|
||||
context.irBuiltIns.unitType,
|
||||
context.implicitDeclarationFile
|
||||
).also {
|
||||
it.body = body
|
||||
context.implicitDeclarationFile.declarations += it
|
||||
}
|
||||
|
||||
parentBody.statements += JsIrBuilder.buildCall(this).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildString(context.irBuiltIns.stringType, name))
|
||||
putValueArgument(1, JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, ignored))
|
||||
|
||||
val refType = IrSimpleTypeImpl(context.functionN(0), false, emptyList(), emptyList())
|
||||
putValueArgument(2, JsIrBuilder.buildFunctionReference(refType, function.symbol))
|
||||
}
|
||||
|
||||
return FunctionWithBody(function, body)
|
||||
}
|
||||
|
||||
private fun generateTestCalls(irClass: IrClass, parentBody: () -> IrBlockBody) {
|
||||
if (irClass.modality == Modality.ABSTRACT || irClass.isEffectivelyExternal() || irClass.isExpect) return
|
||||
|
||||
val suiteFunBody by lazy { context.suiteFun!!.createInvocation(irClass.name.asString(), parentBody(), irClass.isIgnored) }
|
||||
|
||||
val beforeFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isBefore }
|
||||
val afterFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isAfter }
|
||||
|
||||
irClass.declarations.forEach {
|
||||
when {
|
||||
it is IrClass ->
|
||||
generateTestCalls(it) { suiteFunBody.body }
|
||||
|
||||
it is IrSimpleFunction && it.isTest ->
|
||||
generateCodeForTestMethod(it, beforeFunctions, afterFunctions, irClass, suiteFunBody.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateCodeForTestMethod(
|
||||
testFun: IrSimpleFunction,
|
||||
beforeFuns: List<IrSimpleFunction>,
|
||||
afterFuns: List<IrSimpleFunction>,
|
||||
irClass: IrClass,
|
||||
parentBody: IrBlockBody
|
||||
) {
|
||||
val (fn, body) = context.testFun!!.createInvocation(testFun.name.asString(), parentBody, testFun.isIgnored)
|
||||
|
||||
val classVal = JsIrBuilder.buildVar(irClass.defaultType, fn, initializer = irClass.instance())
|
||||
|
||||
body.statements += classVal
|
||||
|
||||
body.statements += beforeFuns.map {
|
||||
JsIrBuilder.buildCall(it.symbol).apply {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(classVal.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
val returnStatement = JsIrBuilder.buildReturn(
|
||||
fn.symbol,
|
||||
JsIrBuilder.buildCall(testFun.symbol).apply {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(classVal.symbol)
|
||||
},
|
||||
context.irBuiltIns.unitType
|
||||
)
|
||||
|
||||
if (afterFuns.isEmpty()) {
|
||||
body.statements += returnStatement
|
||||
} else {
|
||||
body.statements += JsIrBuilder.buildTry(context.irBuiltIns.unitType).apply {
|
||||
tryResult = returnStatement
|
||||
finallyExpression = JsIrBuilder.buildComposite(context.irBuiltIns.unitType).apply {
|
||||
statements += afterFuns.map {
|
||||
JsIrBuilder.buildCall(it.symbol).apply {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(classVal.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.instance(): IrExpression {
|
||||
return if (kind == ClassKind.OBJECT) {
|
||||
JsIrBuilder.buildGetObjectValue(defaultType, symbol)
|
||||
} else {
|
||||
declarations.asSequence().filterIsInstance<IrConstructor>().single { it.isPrimary }.let { constructor ->
|
||||
JsIrBuilder.buildCall(constructor.symbol).also {
|
||||
if (isInner) {
|
||||
it.dispatchReceiver = (parent as IrClass).instance()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IrAnnotationContainer.isTest
|
||||
get() = hasAnnotation("kotlin.test.Test")
|
||||
|
||||
private val IrAnnotationContainer.isIgnored
|
||||
get() = hasAnnotation("kotlin.test.Ignore")
|
||||
|
||||
private val IrAnnotationContainer.isBefore
|
||||
get() = hasAnnotation("kotlin.test.BeforeTest")
|
||||
|
||||
private val IrAnnotationContainer.isAfter
|
||||
get() = hasAnnotation("kotlin.test.AfterTest")
|
||||
|
||||
private fun IrAnnotationContainer.hasAnnotation(fqName: String) =
|
||||
annotations.any { it.symbol.owner.parent.fqNameSafe == FqName(fqName) }
|
||||
}
|
||||
+1
-4
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsDeclarationScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsEmpty
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsVars
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||
|
||||
|
||||
+4
@@ -49,6 +49,10 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
statements += postDeclarationBlock
|
||||
statements += context.staticContext.initializerBlock
|
||||
|
||||
if (backendContext.hasTests) {
|
||||
statements += JsInvocation(context.getNameForSymbol(backendContext.testContainer.symbol).makeRef()).makeStmt()
|
||||
}
|
||||
|
||||
return statements
|
||||
}
|
||||
|
||||
|
||||
@@ -21,25 +21,214 @@ sourceSets {
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
val generateIrRuntimeKlib by task<NoDebugJavaExec> {
|
||||
val inDirs = arrayOf(fileFrom(rootDir, "core", "builtins", "src"),
|
||||
fileFrom(rootDir, "core", "builtins", "native"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "common", "src"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "src", "kotlin"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "js", "src", "generated"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "js", "irRuntime"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "unsigned"),
|
||||
fileFrom(rootDir, "js", "js.translator", "testData", "_commonFiles"))
|
||||
inDirs.forEach { inputs.dir(it) }
|
||||
val unimplementedNativeBuiltIns =
|
||||
(file("$rootDir/core/builtins/native/kotlin/").list().toSet() - file("$rootDir/libraries/stdlib/js/irRuntime/builtins/").list())
|
||||
.map { "core/builtins/native/kotlin/$it" }
|
||||
|
||||
val outDir = "$rootDir/js/js.translator/testData/out/klibs/"
|
||||
outputs.dir(outDir)
|
||||
// Required to compile native builtins with the rest of runtime
|
||||
val builtInsHeader = """@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
"""
|
||||
|
||||
val fullRuntimeSources by task<Copy> {
|
||||
val sources = listOf(
|
||||
"core/builtins/src/kotlin/",
|
||||
"libraries/stdlib/common/src/",
|
||||
"libraries/stdlib/src/kotlin/",
|
||||
"libraries/stdlib/js/src/kotlin/",
|
||||
"libraries/stdlib/js/src/generated/",
|
||||
"libraries/stdlib/js/irRuntime/",
|
||||
"libraries/stdlib/js/runtime/",
|
||||
"libraries/stdlib/unsigned/",
|
||||
|
||||
// TODO get rid - move to test module
|
||||
"js/js.translator/testData/_commonFiles/"
|
||||
) + unimplementedNativeBuiltIns
|
||||
|
||||
val excluded = listOf(
|
||||
"libraries/stdlib/common/src/kotlin/JvmAnnotationsH.kt",
|
||||
"libraries/stdlib/src/kotlin/annotations/Multiplatform.kt",
|
||||
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt",
|
||||
|
||||
// TODO: Support Int.pow
|
||||
"libraries/stdlib/js/src/kotlin/random/PlatformRandom.kt",
|
||||
|
||||
// Fails with: EXPERIMENTAL_IS_NOT_ENABLED
|
||||
"libraries/stdlib/common/src/kotlin/annotations/Annotations.kt",
|
||||
|
||||
// Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt
|
||||
"libraries/stdlib/js/runtime/hacks.kt",
|
||||
|
||||
// TODO: Reuse in IR BE
|
||||
"libraries/stdlib/js/runtime/Enum.kt",
|
||||
|
||||
// JS-specific optimized version of emptyArray() already defined
|
||||
"core/builtins/src/kotlin/ArrayIntrinsics.kt",
|
||||
|
||||
// Unnecessary for now
|
||||
"libraries/stdlib/js/src/kotlin/dom/**",
|
||||
"libraries/stdlib/js/src/kotlin/browser/**",
|
||||
|
||||
// TODO: fix compilation issues in arrayPlusCollection
|
||||
// Replaced with irRuntime/kotlinHacks.kt
|
||||
"libraries/stdlib/js/src/kotlin/kotlin.kt",
|
||||
|
||||
"libraries/stdlib/js/src/kotlin/currentBeMisc.kt",
|
||||
|
||||
// IR BE has its own generated sources
|
||||
"libraries/stdlib/js/src/generated/**",
|
||||
"libraries/stdlib/js/src/kotlin/collectionsExternal.kt",
|
||||
|
||||
// Full version is defined in stdlib
|
||||
// This file is useful for smaller subset of runtime sources
|
||||
"libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt",
|
||||
|
||||
// Mostly array-specific stuff
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt",
|
||||
|
||||
// coroutines
|
||||
// TODO: merge coroutines_13 with JS BE coroutines
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt",
|
||||
|
||||
// Inlining of js fun doesn't update the variables inside
|
||||
"libraries/stdlib/js/src/kotlin/jsTypeOf.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/utils.kt",
|
||||
|
||||
// TODO: Remove stub
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt",
|
||||
|
||||
// Expect declarations get thrown away and libraries/kotlin.test/common/src/main/kotlin/kotlin/test/Assertions.kt doesn't compile
|
||||
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt"
|
||||
)
|
||||
|
||||
sources.forEach { path ->
|
||||
from("$rootDir/$path") {
|
||||
into(path.dropLastWhile { it != '/' })
|
||||
excluded.filter { it.startsWith(path) }.forEach {
|
||||
exclude(it.substring(path.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
into("$buildDir/fullRuntime/src")
|
||||
|
||||
doLast {
|
||||
unimplementedNativeBuiltIns.forEach { path ->
|
||||
val file = File("$buildDir/fullRuntime/src/$path")
|
||||
val sourceCode = builtInsHeader + file.readText()
|
||||
file.writeText(sourceCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val reducedRuntimeSources by task<Copy> {
|
||||
dependsOn(fullRuntimeSources)
|
||||
|
||||
from(fullRuntimeSources.outputs.files.singleFile) {
|
||||
exclude(
|
||||
listOf(
|
||||
"libraries/stdlib/unsigned/**",
|
||||
"libraries/stdlib/common/src/generated/_Arrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_Collections.kt",
|
||||
"libraries/stdlib/common/src/generated/_Comparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_Maps.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sequences.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sets.kt",
|
||||
"libraries/stdlib/common/src/generated/_Strings.kt",
|
||||
"libraries/stdlib/common/src/generated/_UArrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_URanges.kt",
|
||||
"libraries/stdlib/common/src/generated/_UCollections.kt",
|
||||
"libraries/stdlib/common/src/generated/_UComparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_USequences.kt",
|
||||
"libraries/stdlib/common/src/kotlin/SequencesH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/TextH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/UMath.kt",
|
||||
"libraries/stdlib/common/src/kotlin/collections/**",
|
||||
"libraries/stdlib/common/src/kotlin/ioH.kt",
|
||||
"libraries/stdlib/js/irRuntime/collectionsHacks.kt",
|
||||
"libraries/stdlib/js/irRuntime/generated/**",
|
||||
"libraries/stdlib/js/src/kotlin/char.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/**",
|
||||
"libraries/stdlib/js/src/kotlin/console.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coreDeprecated.kt",
|
||||
"libraries/stdlib/js/src/kotlin/date.kt",
|
||||
"libraries/stdlib/js/src/kotlin/debug.kt",
|
||||
"libraries/stdlib/js/src/kotlin/grouping.kt",
|
||||
"libraries/stdlib/js/src/kotlin/json.kt",
|
||||
"libraries/stdlib/js/src/kotlin/numberConversions.kt",
|
||||
"libraries/stdlib/js/src/kotlin/promise.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regex.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regexp.kt",
|
||||
"libraries/stdlib/js/src/kotlin/sequence.kt",
|
||||
"libraries/stdlib/js/src/kotlin/string.kt",
|
||||
"libraries/stdlib/js/src/kotlin/stringsCode.kt",
|
||||
"libraries/stdlib/js/src/kotlin/text.kt",
|
||||
"libraries/stdlib/src/kotlin/collections/**",
|
||||
"libraries/stdlib/src/kotlin/experimental/bitwiseOperations.kt",
|
||||
"libraries/stdlib/src/kotlin/properties/Delegates.kt",
|
||||
"libraries/stdlib/src/kotlin/random/URandom.kt",
|
||||
"libraries/stdlib/src/kotlin/text/**",
|
||||
"libraries/stdlib/src/kotlin/util/KotlinVersion.kt",
|
||||
"libraries/stdlib/src/kotlin/util/Tuples.kt"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from("$rootDir/libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt") {
|
||||
into("libraries/stdlib/js/irRuntime/")
|
||||
}
|
||||
|
||||
into("$buildDir/reducedRuntime/src")
|
||||
}
|
||||
|
||||
|
||||
fun JavaExec.buildKLib(sources: List<String>, dependencies: List<String>, outPath: String) {
|
||||
inputs.files(sources)
|
||||
outputs.dir(file(outPath).parent)
|
||||
|
||||
classpath = sourceSets.test.get().runtimeClasspath
|
||||
main = "org.jetbrains.kotlin.ir.backend.js.GenerateIrRuntimeKt"
|
||||
workingDir = rootDir
|
||||
args = sources.toList() + listOf("-o", outPath) + dependencies.flatMap { listOf("-d", it) }
|
||||
|
||||
passClasspathInJar()
|
||||
}
|
||||
|
||||
val generateFullRuntimeKLib by task<NoDebugJavaExec> {
|
||||
dependsOn(fullRuntimeSources)
|
||||
|
||||
buildKLib(sources = listOf(fullRuntimeSources.outputs.files.singleFile.path),
|
||||
dependencies = emptyList(),
|
||||
outPath = "$buildDir/fullRuntime/klib/JS_IR_RUNTIME.klm")
|
||||
}
|
||||
|
||||
val generateReducedRuntimeKLib by task<NoDebugJavaExec> {
|
||||
dependsOn(reducedRuntimeSources)
|
||||
|
||||
buildKLib(sources = listOf(reducedRuntimeSources.outputs.files.singleFile.path),
|
||||
dependencies = emptyList(),
|
||||
outPath = "$buildDir/reducedRuntime/klib/JS_IR_RUNTIME.klm")
|
||||
}
|
||||
|
||||
val generateKotlinTestKLib by task<NoDebugJavaExec> {
|
||||
dependsOn(generateFullRuntimeKLib)
|
||||
|
||||
buildKLib(
|
||||
sources = listOf(
|
||||
"$rootDir/libraries/kotlin.test/annotations-common/src/main",
|
||||
"$rootDir/libraries/kotlin.test/common/src/main",
|
||||
"$rootDir/libraries/kotlin.test/js/src/main"
|
||||
),
|
||||
dependencies = listOf("${generateFullRuntimeKLib.outputs.files.singleFile.path}/JS_IR_RUNTIME.klm"),
|
||||
outPath = "$buildDir/kotlin.test/klib/kotlin.test.klm"
|
||||
)
|
||||
}
|
||||
|
||||
testsJar {}
|
||||
@@ -5,21 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import java.io.File
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
|
||||
fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguration {
|
||||
fun buildConfiguration(environment: KotlinCoreEnvironment, moduleName: String): CompilerConfiguration {
|
||||
val runtimeConfiguration = environment.configuration.copy()
|
||||
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, "JS_IR_RUNTIME")
|
||||
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||
runtimeConfiguration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
|
||||
runtimeConfiguration.languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
@@ -37,34 +37,69 @@ fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguratio
|
||||
return runtimeConfiguration
|
||||
}
|
||||
|
||||
private val fullRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeFull/"
|
||||
private val defaultRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeDefault/"
|
||||
val environment = KotlinCoreEnvironment.createForTests(Disposable { }, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
|
||||
fun main() {
|
||||
fun createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(environment.project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val environment = KotlinCoreEnvironment.createForTests(Disposable { }, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
fun createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(environment.project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
|
||||
fun buildKlib(sources: List<String>, outputPath: String) {
|
||||
generateKLib(
|
||||
project = environment.project,
|
||||
files = sources.map(::createPsiFile),
|
||||
configuration = buildConfiguration(environment),
|
||||
immediateDependencies = emptyList(),
|
||||
allDependencies = emptyList(),
|
||||
outputKlibPath = outputPath
|
||||
)
|
||||
}
|
||||
|
||||
buildKlib(JsIrTestRuntime.FULL.sources, fullRuntimeKlibPath)
|
||||
buildKlib(JsIrTestRuntime.DEFAULT.sources, defaultRuntimeKlibPath)
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
|
||||
fun buildKLib(moduleName: String, sources: List<String>, outputPath: String, dependencies: List<KlibModuleRef>): KlibModuleRef {
|
||||
return generateKLib(
|
||||
project = environment.project,
|
||||
files = sources.map(::createPsiFile),
|
||||
configuration = buildConfiguration(environment, moduleName),
|
||||
immediateDependencies = dependencies,
|
||||
allDependencies = dependencies,
|
||||
outputKlibPath = outputPath
|
||||
)
|
||||
}
|
||||
|
||||
private fun listOfKtFilesFrom(paths: List<String>): List<String> {
|
||||
val currentDir = File("")
|
||||
return paths.flatMap { path ->
|
||||
File(path)
|
||||
.walkTopDown()
|
||||
.filter { it.extension == "kt" }
|
||||
.map { it.relativeToOrSelf(currentDir).path }
|
||||
.asIterable()
|
||||
}.distinct()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val inputFiles = mutableListOf<String>()
|
||||
var outputPath: String? = null
|
||||
val dependencies = mutableListOf<String>()
|
||||
|
||||
var index = 0
|
||||
while (index < args.size) {
|
||||
val arg = args[index++]
|
||||
|
||||
when (arg) {
|
||||
"-o" -> outputPath = args[index++]
|
||||
"-d" -> dependencies += args[index++]
|
||||
else -> inputFiles += arg
|
||||
}
|
||||
}
|
||||
|
||||
if (outputPath == null) {
|
||||
error("Please set path to .klm file: `-o some/dir/module-name.klm`")
|
||||
}
|
||||
|
||||
val name = outputPath.takeLastWhile { it != '/' }
|
||||
|
||||
if (!name.endsWith(".klm")) error("invalid output file name")
|
||||
|
||||
val dependencyKLibs = dependencies.map {
|
||||
val file = File(it)
|
||||
KlibModuleRef(file.name.dropLast(4), file.parent)
|
||||
}
|
||||
|
||||
buildKLib(name.dropLast(4), listOfKtFilesFrom(inputFiles), File(outputPath).parent, dependencyKLibs)
|
||||
}
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
private const val runtimeDir = "js/js.translator/testData/out/irBox"
|
||||
|
||||
enum class JsIrTestRuntime(
|
||||
val sources: List<String>,
|
||||
val path: String
|
||||
) {
|
||||
// Includes all built-ins and reduced subset of stdlib
|
||||
DEFAULT(
|
||||
sources = reducedRuntimeSources,
|
||||
path = "$runtimeDir/testRuntime.js"
|
||||
),
|
||||
|
||||
// Includes almost full stdlib
|
||||
FULL(
|
||||
sources = fullRuntimeSources,
|
||||
path = "$runtimeDir/testRuntimeFull.js"
|
||||
)
|
||||
}
|
||||
|
||||
// Required to compile native builtins with the rest of runtime
|
||||
private const val builtInsHeader = """@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
"""
|
||||
|
||||
// Native builtins that were not implemented in JS IR runtime
|
||||
private val unimplementedNativeBuiltInsDir = KotlinTestUtils.tmpDir("unimplementedBuiltins").also { tmpDir ->
|
||||
val allBuiltins = listOfKtFilesFrom("core/builtins/native/kotlin").map { File(it).name }
|
||||
val implementedBuiltIns = listOfKtFilesFrom("libraries/stdlib/js/irRuntime/builtins/").map { File(it).name }
|
||||
val unimplementedBuiltIns = allBuiltins - implementedBuiltIns
|
||||
for (filename in unimplementedBuiltIns) {
|
||||
val originalFile = File("core/builtins/native/kotlin", filename)
|
||||
val newFile = File(tmpDir, filename)
|
||||
val sourceCode = builtInsHeader + originalFile.readText()
|
||||
newFile.writeText(sourceCode)
|
||||
}
|
||||
}
|
||||
|
||||
private val fullRuntimeSources = listOfKtFilesFrom(
|
||||
"core/builtins/src/kotlin",
|
||||
"libraries/stdlib/common/src",
|
||||
"libraries/stdlib/src/kotlin/",
|
||||
"libraries/stdlib/js/src/kotlin",
|
||||
"libraries/stdlib/js/src/generated",
|
||||
"libraries/stdlib/js/irRuntime",
|
||||
"libraries/stdlib/js/runtime",
|
||||
"libraries/stdlib/unsigned",
|
||||
|
||||
"core/builtins/src/kotlin/Unit.kt",
|
||||
unimplementedNativeBuiltInsDir.path,
|
||||
"js/js.translator/testData/_commonFiles"
|
||||
) - listOfKtFilesFrom(
|
||||
"libraries/stdlib/common/src/kotlin/JvmAnnotationsH.kt",
|
||||
"libraries/stdlib/src/kotlin/annotations/Multiplatform.kt",
|
||||
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt",
|
||||
|
||||
// TODO: Support Int.pow
|
||||
"libraries/stdlib/js/src/kotlin/random/PlatformRandom.kt",
|
||||
|
||||
// Fails with: EXPERIMENTAL_IS_NOT_ENABLED
|
||||
"libraries/stdlib/common/src/kotlin/annotations/Annotations.kt",
|
||||
|
||||
// Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt
|
||||
"libraries/stdlib/js/runtime/hacks.kt",
|
||||
|
||||
// TODO: Reuse in IR BE
|
||||
"libraries/stdlib/js/runtime/Enum.kt",
|
||||
|
||||
// JS-specific optimized version of emptyArray() already defined
|
||||
"core/builtins/src/kotlin/ArrayIntrinsics.kt",
|
||||
|
||||
// Unnecessary for now
|
||||
"libraries/stdlib/js/src/kotlin/dom",
|
||||
"libraries/stdlib/js/src/kotlin/browser",
|
||||
|
||||
// TODO: fix compilation issues in arrayPlusCollection
|
||||
// Replaced with irRuntime/kotlinHacks.kt
|
||||
"libraries/stdlib/js/src/kotlin/kotlin.kt",
|
||||
|
||||
"libraries/stdlib/js/src/kotlin/currentBeMisc.kt",
|
||||
|
||||
// IR BE has its own generated sources
|
||||
"libraries/stdlib/js/src/generated",
|
||||
"libraries/stdlib/js/src/kotlin/collectionsExternal.kt",
|
||||
|
||||
// Full version is defined in stdlib
|
||||
// This file is useful for smaller subset of runtime sources
|
||||
"libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt",
|
||||
|
||||
// Mostly array-specific stuff
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt",
|
||||
|
||||
// coroutines
|
||||
// TODO: merge coroutines_13 with JS BE coroutines
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt",
|
||||
|
||||
// Inlining of js fun doesn't update the variables inside
|
||||
"libraries/stdlib/js/src/kotlin/jsTypeOf.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/utils.kt",
|
||||
|
||||
// TODO: Remove stub
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt"
|
||||
)
|
||||
|
||||
private val reducedRuntimeSources = fullRuntimeSources - listOfKtFilesFrom(
|
||||
"libraries/stdlib/unsigned",
|
||||
"libraries/stdlib/common/src/generated/_Arrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_Collections.kt",
|
||||
"libraries/stdlib/common/src/generated/_Comparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_Maps.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sequences.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sets.kt",
|
||||
"libraries/stdlib/common/src/generated/_Strings.kt",
|
||||
"libraries/stdlib/common/src/generated/_UArrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_URanges.kt",
|
||||
"libraries/stdlib/common/src/generated/_UCollections.kt",
|
||||
"libraries/stdlib/common/src/generated/_UComparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_USequences.kt",
|
||||
"libraries/stdlib/common/src/kotlin/SequencesH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/TextH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/UMath.kt",
|
||||
"libraries/stdlib/common/src/kotlin/collections/",
|
||||
"libraries/stdlib/common/src/kotlin/ioH.kt",
|
||||
"libraries/stdlib/js/irRuntime/collectionsHacks.kt",
|
||||
"libraries/stdlib/js/irRuntime/generated/",
|
||||
"libraries/stdlib/js/src/kotlin/char.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/",
|
||||
"libraries/stdlib/js/src/kotlin/console.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coreDeprecated.kt",
|
||||
"libraries/stdlib/js/src/kotlin/date.kt",
|
||||
"libraries/stdlib/js/src/kotlin/debug.kt",
|
||||
"libraries/stdlib/js/src/kotlin/grouping.kt",
|
||||
"libraries/stdlib/js/src/kotlin/json.kt",
|
||||
"libraries/stdlib/js/src/kotlin/numberConversions.kt",
|
||||
"libraries/stdlib/js/src/kotlin/promise.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regex.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regexp.kt",
|
||||
"libraries/stdlib/js/src/kotlin/sequence.kt",
|
||||
"libraries/stdlib/js/src/kotlin/string.kt",
|
||||
"libraries/stdlib/js/src/kotlin/stringsCode.kt",
|
||||
"libraries/stdlib/js/src/kotlin/text.kt",
|
||||
"libraries/stdlib/src/kotlin/collections/",
|
||||
"libraries/stdlib/src/kotlin/experimental/bitwiseOperations.kt",
|
||||
"libraries/stdlib/src/kotlin/properties/Delegates.kt",
|
||||
"libraries/stdlib/src/kotlin/random/URandom.kt",
|
||||
"libraries/stdlib/src/kotlin/text/",
|
||||
"libraries/stdlib/src/kotlin/util/KotlinVersion.kt",
|
||||
"libraries/stdlib/src/kotlin/util/Tuples.kt"
|
||||
) + listOfKtFilesFrom(
|
||||
"libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt"
|
||||
)
|
||||
|
||||
private fun listOfKtFilesFrom(vararg paths: String): List<String> {
|
||||
val currentDir = File("")
|
||||
return paths.flatMap { path ->
|
||||
File(path)
|
||||
.walkTopDown()
|
||||
.filter { it.extension == "kt" }
|
||||
.map { it.relativeToOrSelf(currentDir).path }
|
||||
.asIterable()
|
||||
}.distinct()
|
||||
}
|
||||
Reference in New Issue
Block a user