From fe9ab0a1fcb186c3f7f816f68a95cfb3566822d1 Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Thu, 16 Nov 2023 15:58:43 +0200 Subject: [PATCH] [Swift Export] KT-63516 Add a sir-compiler-bridge module that adds Kotlin and C bridges for SIR. As SIR is still WIP, the module accepts `BridgeRequest` instances instead of SIR elements. --- .../build.gradle.kts | 1 + .../api/GenerateSirAnalysisApiTests.kt | 11 ++ native/swift/sir-compiler-bridge/README.md | 18 +++ .../sir-compiler-bridge/build.gradle.kts | 31 ++++ .../kotlin/sir/bridge/BridgeGenerator.kt | 108 ++++++++++++++ .../sir/bridge/impl/BridgeGeneratorImpl.kt | 140 ++++++++++++++++++ .../sir/bridge/impl/CHeaderGenerator.kt | 34 +++++ .../sir/bridge/impl/KotlinFileGenerator.kt | 33 +++++ .../sir/bridge/AbstractKotlinSirBridgeTest.kt | 85 +++++++++++ .../testData/multiple_requests/expected.h | 6 + .../testData/multiple_requests/expected.kt | 13 ++ .../multiple_requests/request0.properties | 4 + .../multiple_requests/request1.properties | 4 + .../testData/primitive_parameters/expected.h | 7 + .../testData/primitive_parameters/expected.kt | 20 +++ .../primitive_parameters/request0.properties | 4 + .../primitive_parameters/request1.properties | 4 + .../primitive_parameters/request2.properties | 4 + .../testData/primitive_types/expected.h | 11 ++ .../testData/primitive_types/expected.kt | 31 ++++ .../primitive_types/request0.properties | 3 + .../primitive_types/request1.properties | 3 + .../primitive_types/request2.properties | 3 + .../primitive_types/request3.properties | 3 + .../primitive_types/request4.properties | 3 + .../testData/smoke0/expected.h | 3 + .../testData/smoke0/expected.kt | 7 + .../testData/smoke0/request.properties | 4 + .../unsigned_primitive_types/expected.h | 9 ++ .../unsigned_primitive_types/expected.kt | 25 ++++ .../request1.properties | 3 + .../request2.properties | 3 + .../request3.properties | 3 + .../request4.properties | 3 + .../SirCompilerBridgeTestGenerated.java | 56 +++++++ settings.gradle | 1 + 36 files changed, 701 insertions(+) create mode 100644 native/swift/sir-compiler-bridge/README.md create mode 100644 native/swift/sir-compiler-bridge/build.gradle.kts create mode 100644 native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/BridgeGenerator.kt create mode 100644 native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/BridgeGeneratorImpl.kt create mode 100644 native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/CHeaderGenerator.kt create mode 100644 native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/KotlinFileGenerator.kt create mode 100644 native/swift/sir-compiler-bridge/test/org/jetbrains/kotlin/sir/bridge/AbstractKotlinSirBridgeTest.kt create mode 100644 native/swift/sir-compiler-bridge/testData/multiple_requests/expected.h create mode 100644 native/swift/sir-compiler-bridge/testData/multiple_requests/expected.kt create mode 100644 native/swift/sir-compiler-bridge/testData/multiple_requests/request0.properties create mode 100644 native/swift/sir-compiler-bridge/testData/multiple_requests/request1.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.h create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.kt create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_parameters/request0.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_parameters/request1.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_parameters/request2.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/expected.h create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/expected.kt create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/request0.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/request1.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/request2.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/request3.properties create mode 100644 native/swift/sir-compiler-bridge/testData/primitive_types/request4.properties create mode 100644 native/swift/sir-compiler-bridge/testData/smoke0/expected.h create mode 100644 native/swift/sir-compiler-bridge/testData/smoke0/expected.kt create mode 100644 native/swift/sir-compiler-bridge/testData/smoke0/request.properties create mode 100644 native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.h create mode 100644 native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.kt create mode 100644 native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request1.properties create mode 100644 native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request2.properties create mode 100644 native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request3.properties create mode 100644 native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request4.properties create mode 100644 native/swift/sir-compiler-bridge/tests-gen/org/jetbrains/kotlin/sir/bridge/SirCompilerBridgeTestGenerated.java diff --git a/generators/sir-analysis-api-generator/build.gradle.kts b/generators/sir-analysis-api-generator/build.gradle.kts index a1b35e50665..47d0d22ebc9 100644 --- a/generators/sir-analysis-api-generator/build.gradle.kts +++ b/generators/sir-analysis-api-generator/build.gradle.kts @@ -10,6 +10,7 @@ sourceSets { dependencies { testApi(projectTests(":native:swift:sir-analysis-api")) + testApi(projectTests(":native:swift:sir-compiler-bridge")) testImplementation(projectTests(":generators:test-generator")) testRuntimeOnly(projectTests(":analysis:analysis-test-framework")) diff --git a/generators/sir-analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/native/swift/sir/analysis/api/GenerateSirAnalysisApiTests.kt b/generators/sir-analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/native/swift/sir/analysis/api/GenerateSirAnalysisApiTests.kt index ef232f267d6..9cd2b30da9c 100644 --- a/generators/sir-analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/native/swift/sir/analysis/api/GenerateSirAnalysisApiTests.kt +++ b/generators/sir-analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/native/swift/sir/analysis/api/GenerateSirAnalysisApiTests.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.generators.tests.native.swift.sir.analysis.api import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5 import org.jetbrains.kotlin.sir.analysisapi.AbstractKotlinSirContextTest +import org.jetbrains.kotlin.sir.bridge.AbstractKotlinSirBridgeTest fun main() { @@ -22,5 +23,15 @@ fun main() { model("", pattern = "^([^_](.+)).kt$", recursive = false) } } + testGroup( + "native/swift/sir-compiler-bridge/tests-gen/", + "native/swift/sir-compiler-bridge/testData" + ) { + testClass( + suiteTestClassName = "SirCompilerBridgeTestGenerated" + ) { + model("", extension = null, recursive = false) + } + } } } diff --git a/native/swift/sir-compiler-bridge/README.md b/native/swift/sir-compiler-bridge/README.md new file mode 100644 index 00000000000..2209be2f25f --- /dev/null +++ b/native/swift/sir-compiler-bridge/README.md @@ -0,0 +1,18 @@ +# Swift IR to Kotlin compiler bridges + +This module is responsible for the generation of "glue" code between Swift Export and Kotlin compiler. + +Swift does not "know" how to call Kotlin directly. But it has a C/C++/Objective-C interop, and we can leverage it for Swift Export. + +We do the following: +1. Generate a Kotlin wrapper around the original Kotlin function with a primitive C-like ABI. +2. Generate a C header with C declarations of these wrappers. +3. Call these C functions from Swift functions. + +That's it! This approach also has the following advantages: +1. All nuances of Kotlin compiler and Kotlin/Native runtime are hidden behind wrappers with a simple ABI. +So Swift Export (mostly) does not need to care about how Kotlin/Native works under the hood. +2. The contract between Swift Export and Kotlin compiler is well-defined in the form of a set of compiler intrinsics. + +For the sake of simplicity, Kotlin wrappers are generated as Kotlin sources, +but later we can switch to direct generation of Kotlin Backend IR. \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/build.gradle.kts b/native/swift/sir-compiler-bridge/build.gradle.kts new file mode 100644 index 00000000000..8fa412bbf2d --- /dev/null +++ b/native/swift/sir-compiler-bridge/build.gradle.kts @@ -0,0 +1,31 @@ +plugins { + kotlin("jvm") +} + +description = "SIR to Kotlin bindings generator" + +dependencies { + compileOnly(kotlinStdlib()) + + testApi(platform(libs.junit.bom)) + testRuntimeOnly(libs.junit.jupiter.engine) + testImplementation(libs.junit.jupiter.api) + + testImplementation(projectTests(":compiler:tests-common")) + testImplementation(projectTests(":compiler:tests-common-new")) +} + +sourceSets { + "main" { projectDefault() } + "test" { + projectDefault() + generatedTestDir() + } +} + +projectTest(jUnitMode = JUnitMode.JUnit5) { + workingDir = rootDir + useJUnitPlatform { } +} + +testsJar() \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/BridgeGenerator.kt b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/BridgeGenerator.kt new file mode 100644 index 00000000000..f0ac062cb85 --- /dev/null +++ b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/BridgeGenerator.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.sir.bridge + +import org.jetbrains.kotlin.sir.bridge.impl.BridgeGeneratorImpl +import org.jetbrains.kotlin.sir.bridge.impl.CBridgePrinter +import org.jetbrains.kotlin.sir.bridge.impl.KotlinBridgePrinter + +/** + * Description of a Kotlin function for which we are creating the bridge. + * + * TODO: Replace with SIR once KT-63266 is merged. + * + * @param fqName Fully qualified name of the function we are bridging. + * @param bridgeName C name of the bridge + */ +class BridgeRequest( + val fqName: List, + val bridgeName: String, + val parameters: List, + val returnType: Type, +) { + class Parameter( + val name: String, + val type: Type, + ) + + sealed interface Type { + data object Boolean : Type + + data object Byte : Type + data object Short : Type + data object Int : Type + data object Long : Type + + data object UByte : Type + data object UShort : Type + data object UInt : Type + data object ULong : Type + } +} + +/** + * A C-like wrapper around some Kotlin function. + * Abstracts away all nuances of Kotlin compiler ABI, making it possible + * to call Kotlin code from other environments. + */ +class FunctionBridge( + val kotlinFunctionBridge: KotlinFunctionBridge, + val cDeclarationBridge: CFunctionBridge, +) + +/** + * C part of [FunctionBridgeImpl]. + * + * @param lines with function declaration. + * @param headerDependencies required headers. + */ +class CFunctionBridge( + val lines: List, + val headerDependencies: List, +) + +/** + * Kotlin part of [FunctionBridgeImpl]. + * + * @param lines definition of Kotlin bridge. + * @param packageDependencies required packages to make sources compile. + */ +class KotlinFunctionBridge( + val lines: List, + val packageDependencies: List, +) + +/** + * Generates [FunctionBridge] that binds SIR function to its Kotlin origin. + */ +interface BridgeGenerator { + fun generate(request: BridgeRequest): FunctionBridge +} + +/** + * A common interface for classes that serialize [FunctionBridge] in some form. + */ +interface BridgePrinter { + /** + * Populate printer with an additional [bridge]. + */ + fun add(bridge: FunctionBridge) + + /** + * Outputs the aggregated result. + */ + fun print(): Sequence +} + +fun createBridgeGenerator(): BridgeGenerator = + BridgeGeneratorImpl() + +fun createCBridgePrinter(): BridgePrinter = + CBridgePrinter() + +fun createKotlinBridgePrinter(): BridgePrinter = + KotlinBridgePrinter() + diff --git a/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/BridgeGeneratorImpl.kt b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/BridgeGeneratorImpl.kt new file mode 100644 index 00000000000..05bd2cfa740 --- /dev/null +++ b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/BridgeGeneratorImpl.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.sir.bridge.impl + +import org.jetbrains.kotlin.sir.bridge.* + +private const val exportAnnotationFqName = "kotlin.native.internal.ExportForCppRuntime" +private const val stdintHeader = "stdint.h" + +internal class BridgeGeneratorImpl : BridgeGenerator { + override fun generate(request: BridgeRequest): FunctionBridge { + + val (kotlinReturnType, cReturnType) = bridgeType(request.returnType) + val parameterBridges = request.parameters.map { bridgeParameter(it) } + + val cDeclaration = createCDeclaration(request.bridgeName, cReturnType, parameterBridges.map { it.c }) + val kotlinBridge = createKotlinBridge(request.bridgeName, request.fqName, kotlinReturnType, parameterBridges.map { it.kotlin }) + return FunctionBridge( + KotlinFunctionBridge(kotlinBridge, listOf(exportAnnotationFqName)), + CFunctionBridge(cDeclaration, listOf(stdintHeader)) + ) + } +} + +private fun createKotlinBridge( + bridgeName: String, + functionFqName: List, + returnType: KotlinType, + parameterBridges: List +): List { + val declaration = createKotlinDeclarationSignature(bridgeName, returnType, parameterBridges) + val annotation = "@${exportAnnotationFqName.substringAfterLast('.')}(\"${bridgeName}\")" + val resultName = "result" + val callSite = createCallSite(functionFqName, parameterBridges.map { it.name }, resultName) + return """ + $annotation + $declaration { + $callSite + return $resultName + } + """.trimIndent().lines() +} + +private fun createCallSite(functionFqName: List, parameterNames: List, resultName: String): String { + val functionCall = "${functionFqName.joinToString(separator = ".")}(${parameterNames.joinToString(", ")})" + return "val $resultName = $functionCall" +} + +private fun createKotlinDeclarationSignature(bridgeName: String, returnType: KotlinType, parameters: List): String { + return "public fun $bridgeName(${ + parameters.joinToString( + separator = ", ", + transform = { "${it.name}: ${it.type.repr}" } + ) + }): ${returnType.repr}" +} + +private fun createCDeclaration(bridgeName: String, returnType: CType, parameters: List): List { + val cParameters = parameters.joinToString(separator = ", ", transform = { "${it.type.repr} ${it.name}" }) + val declaration = "${returnType.repr} $bridgeName($cParameters);" + return listOf(declaration) +} + + +private fun bridgeType(type: BridgeRequest.Type): Pair { + return when (type) { + BridgeRequest.Type.Boolean -> (KotlinType.Boolean to CType.Bool) + + BridgeRequest.Type.Byte -> (KotlinType.Byte to CType.Int8) + BridgeRequest.Type.Int -> (KotlinType.Int to CType.Int32) + BridgeRequest.Type.Long -> (KotlinType.Long to CType.Int64) + BridgeRequest.Type.Short -> (KotlinType.Short to CType.Int16) + + BridgeRequest.Type.UByte -> (KotlinType.UByte to CType.UInt8) + BridgeRequest.Type.UInt -> (KotlinType.UInt to CType.UInt32) + BridgeRequest.Type.ULong -> (KotlinType.ULong to CType.UInt64) + BridgeRequest.Type.UShort -> (KotlinType.UShort to CType.UInt16) + } +} + +private fun bridgeParameter(request: BridgeRequest.Parameter): BridgeParameter { + val bridgeParameterName = createBridgeParameterName(request.name) + val (kotlinType, cType) = bridgeType(request.type) + return BridgeParameter( + KotlinBridgeParameter(bridgeParameterName, kotlinType), + CBridgeParameter(bridgeParameterName, cType) + ) +} + +fun createBridgeParameterName(kotlinName: String): String { + // TODO: Post-process because C has stricter naming conventions. + return kotlinName +} + +internal data class BridgeParameter( + val kotlin: KotlinBridgeParameter, + val c: CBridgeParameter, +) + +internal data class CBridgeParameter( + val name: String, + val type: CType, +) + +enum class CType(val repr: String) { + Bool("_Bool"), + + Int8("int8_t"), + Int16("int16_t"), + Int32("int32_t"), + Int64("int64_t"), + + UInt8("uint8_t"), + UInt16("uint16_t"), + UInt32("uint32_t"), + UInt64("uint64_t"), +} + +internal data class KotlinBridgeParameter( + val name: String, + val type: KotlinType, +) + +internal enum class KotlinType(val repr: String) { + Boolean("Boolean"), + + Byte("Byte"), + Short("Short"), + Int("Int"), + Long("Long"), + + UByte("UByte"), + UShort("UShort"), + UInt("UInt"), + ULong("ULong"), +} + diff --git a/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/CHeaderGenerator.kt b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/CHeaderGenerator.kt new file mode 100644 index 00000000000..0e1d774ec85 --- /dev/null +++ b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/CHeaderGenerator.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.sir.bridge.impl + +import org.jetbrains.kotlin.sir.bridge.BridgePrinter +import org.jetbrains.kotlin.sir.bridge.FunctionBridge + +internal class CBridgePrinter : BridgePrinter { + + private val includes = mutableSetOf() + + private val functions = mutableListOf>() + + override fun add(bridge: FunctionBridge) { + functions += bridge.cDeclarationBridge.lines + includes += bridge.cDeclarationBridge.headerDependencies + } + + override fun print(): Sequence = sequence { + if (includes.isNotEmpty()) { + includes.forEach { + yield("#include <$it>") + } + yield("") + } + functions.forEach { functionLines -> + yieldAll(functionLines) + yield("") + } + } +} \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/KotlinFileGenerator.kt b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/KotlinFileGenerator.kt new file mode 100644 index 00000000000..5df81ac0600 --- /dev/null +++ b/native/swift/sir-compiler-bridge/src/org/jetbrains/kotlin/sir/bridge/impl/KotlinFileGenerator.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.sir.bridge.impl + +import org.jetbrains.kotlin.sir.bridge.BridgePrinter +import org.jetbrains.kotlin.sir.bridge.FunctionBridge + +internal class KotlinBridgePrinter : BridgePrinter { + + private val imports = mutableSetOf() + private val functions = mutableListOf>() + + override fun add(bridge: FunctionBridge) { + functions += bridge.kotlinFunctionBridge.lines + imports += bridge.kotlinFunctionBridge.packageDependencies + } + + override fun print(): Sequence = sequence { + if (imports.isNotEmpty()) { + imports.forEach { + yield("import $it") + } + yield("") + } + functions.forEach { functionLines -> + yieldAll(functionLines) + yield("") + } + } +} \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/test/org/jetbrains/kotlin/sir/bridge/AbstractKotlinSirBridgeTest.kt b/native/swift/sir-compiler-bridge/test/org/jetbrains/kotlin/sir/bridge/AbstractKotlinSirBridgeTest.kt new file mode 100644 index 00000000000..fa1265763fa --- /dev/null +++ b/native/swift/sir-compiler-bridge/test/org/jetbrains/kotlin/sir/bridge/AbstractKotlinSirBridgeTest.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.sir.bridge + +import com.intellij.testFramework.TestDataFile +import org.jetbrains.kotlin.test.services.JUnit5Assertions +import org.jetbrains.kotlin.test.util.KtTestUtil +import java.io.File +import java.util.* + +abstract class AbstractKotlinSirBridgeTest { + protected fun runTest(@TestDataFile testPath: String) { + val testPathFull = File(KtTestUtil.getHomeDirectory()).resolve(testPath) + val expectedKotlinSrc = testPathFull.resolve("expected.kt") + val expectedCHeader = testPathFull.resolve("expected.h") + + val requests = parseRequestsFromTestDir(testPathFull) + + val generator = createBridgeGenerator() + val kotlinBridgePrinter = createKotlinBridgePrinter() + val cBridgePrinter = createCBridgePrinter() + + requests.forEach { request -> + val bridge = generator.generate(request) + kotlinBridgePrinter.add(bridge) + cBridgePrinter.add(bridge) + } + + val actualKotlinSrc = kotlinBridgePrinter.print().joinToString(separator = lineSeparator) + val actualHeader = cBridgePrinter.print().joinToString(separator = lineSeparator) + + JUnit5Assertions.assertEqualsToFile(expectedCHeader, actualHeader) + JUnit5Assertions.assertEqualsToFile(expectedKotlinSrc, actualKotlinSrc) + } +} + +private val lineSeparator: String = System.getProperty("line.separator") + +private fun parseRequestsFromTestDir(testDir: File): List = + testDir.listFiles() + ?.filter { it.extension == "properties" && it.name.startsWith("request") } + ?.map { readRequestFromFile(it) } + ?.sortedBy { it.bridgeName } + ?: emptyList() + +private fun parseType(typeName: String): BridgeRequest.Type { + return when (typeName.lowercase()) { + "boolean" -> BridgeRequest.Type.Boolean + + "byte" -> BridgeRequest.Type.Byte + "short" -> BridgeRequest.Type.Short + "int" -> BridgeRequest.Type.Int + "long" -> BridgeRequest.Type.Long + + "ubyte" -> BridgeRequest.Type.UByte + "ushort" -> BridgeRequest.Type.UShort + "uint" -> BridgeRequest.Type.UInt + "ulong" -> BridgeRequest.Type.ULong + + else -> error("Unknown type: $typeName") + } +} + +private fun readRequestFromFile(file: File): BridgeRequest { + val properties = Properties() + file.bufferedReader().use(properties::load) + val fqName = properties.getProperty("fqName").split('.') + val bridgeName = properties.getProperty("bridgeName") + val returnType = parseType(properties.getProperty("returnType")) + val parameters = properties.getProperty("parameters").let { parametersString -> + when { + parametersString.isNullOrEmpty() -> emptyList() + else -> parametersString.split(Regex("\\s+")) + }.map { + BridgeRequest.Parameter( + name = it.substringBefore(':'), + type = parseType(it.substringAfter(':')) + ) + } + } + return BridgeRequest(fqName, bridgeName, parameters, returnType) +} \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/multiple_requests/expected.h b/native/swift/sir-compiler-bridge/testData/multiple_requests/expected.h new file mode 100644 index 00000000000..e3184d6871a --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/multiple_requests/expected.h @@ -0,0 +1,6 @@ +#include + +int32_t a_b_bar_bridge(int32_t param1, int64_t param2); + +_Bool a_b_foo_bridge(int32_t param1, int64_t param2); + diff --git a/native/swift/sir-compiler-bridge/testData/multiple_requests/expected.kt b/native/swift/sir-compiler-bridge/testData/multiple_requests/expected.kt new file mode 100644 index 00000000000..8646bea2fa8 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/multiple_requests/expected.kt @@ -0,0 +1,13 @@ +import kotlin.native.internal.ExportForCppRuntime + +@ExportForCppRuntime("a_b_bar_bridge") +public fun a_b_bar_bridge(param1: Int, param2: Long): Int { + val result = a.b.bar(param1, param2) + return result +} + +@ExportForCppRuntime("a_b_foo_bridge") +public fun a_b_foo_bridge(param1: Int, param2: Long): Boolean { + val result = a.b.foo(param1, param2) + return result +} diff --git a/native/swift/sir-compiler-bridge/testData/multiple_requests/request0.properties b/native/swift/sir-compiler-bridge/testData/multiple_requests/request0.properties new file mode 100644 index 00000000000..e2f4b41f374 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/multiple_requests/request0.properties @@ -0,0 +1,4 @@ +fqName=a.b.foo +bridgeName=a_b_foo_bridge +parameters=param1:int param2:long +returnType=boolean \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/multiple_requests/request1.properties b/native/swift/sir-compiler-bridge/testData/multiple_requests/request1.properties new file mode 100644 index 00000000000..9271d9f8f49 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/multiple_requests/request1.properties @@ -0,0 +1,4 @@ +fqName=a.b.bar +bridgeName=a_b_bar_bridge +parameters=param1:int param2:long +returnType=int \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.h b/native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.h new file mode 100644 index 00000000000..aee71c5f3e5 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.h @@ -0,0 +1,7 @@ +#include + +int32_t a(int8_t p0, int16_t p1, int32_t p2, int64_t p3); + +uint32_t b(uint8_t p0, uint16_t p1, uint32_t p2, uint64_t p3); + +_Bool c(_Bool p0); diff --git a/native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.kt b/native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.kt new file mode 100644 index 00000000000..9fe15102ba3 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_parameters/expected.kt @@ -0,0 +1,20 @@ +import kotlin.native.internal.ExportForCppRuntime + +@ExportForCppRuntime("a") +public fun a(p0: Byte, p1: Short, p2: Int, p3: Long): Int { + val result = pkg.a(p0, p1, p2, p3) + return result +} + +@ExportForCppRuntime("b") +public fun b(p0: UByte, p1: UShort, p2: UInt, p3: ULong): UInt { + val result = pkg.b(p0, p1, p2, p3) + return result +} + +@ExportForCppRuntime("c") +public fun c(p0: Boolean): Boolean { + val result = pkg.c(p0) + return result +} + diff --git a/native/swift/sir-compiler-bridge/testData/primitive_parameters/request0.properties b/native/swift/sir-compiler-bridge/testData/primitive_parameters/request0.properties new file mode 100644 index 00000000000..e9b8b374928 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_parameters/request0.properties @@ -0,0 +1,4 @@ +fqName=pkg.a +bridgeName=a +returnType=int +parameters=p0:byte p1:short p2:int p3:long \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_parameters/request1.properties b/native/swift/sir-compiler-bridge/testData/primitive_parameters/request1.properties new file mode 100644 index 00000000000..93624a60435 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_parameters/request1.properties @@ -0,0 +1,4 @@ +fqName=pkg.b +bridgeName=b +returnType=uint +parameters=p0:ubyte p1:ushort p2:uint p3:ulong \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_parameters/request2.properties b/native/swift/sir-compiler-bridge/testData/primitive_parameters/request2.properties new file mode 100644 index 00000000000..e38f086accd --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_parameters/request2.properties @@ -0,0 +1,4 @@ +fqName=pkg.c +bridgeName=c +returnType=boolean +parameters=p0:boolean \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/expected.h b/native/swift/sir-compiler-bridge/testData/primitive_types/expected.h new file mode 100644 index 00000000000..3fde3ae88d4 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/expected.h @@ -0,0 +1,11 @@ +#include + +_Bool a_bridge(); + +int16_t b_bridge(); + +int32_t c_bridge(); + +int64_t d_bridge(); + +int8_t e_bridge(); diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/expected.kt b/native/swift/sir-compiler-bridge/testData/primitive_types/expected.kt new file mode 100644 index 00000000000..dcd7f12bb16 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/expected.kt @@ -0,0 +1,31 @@ +import kotlin.native.internal.ExportForCppRuntime + +@ExportForCppRuntime("a_bridge") +public fun a_bridge(): Boolean { + val result = a() + return result +} + +@ExportForCppRuntime("b_bridge") +public fun b_bridge(): Short { + val result = b() + return result +} + +@ExportForCppRuntime("c_bridge") +public fun c_bridge(): Int { + val result = c() + return result +} + +@ExportForCppRuntime("d_bridge") +public fun d_bridge(): Long { + val result = d() + return result +} + +@ExportForCppRuntime("e_bridge") +public fun e_bridge(): Byte { + val result = e() + return result +} \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/request0.properties b/native/swift/sir-compiler-bridge/testData/primitive_types/request0.properties new file mode 100644 index 00000000000..9bf8f3808a8 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/request0.properties @@ -0,0 +1,3 @@ +fqName=a +bridgeName=a_bridge +returnType=boolean \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/request1.properties b/native/swift/sir-compiler-bridge/testData/primitive_types/request1.properties new file mode 100644 index 00000000000..190a9fc55ee --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/request1.properties @@ -0,0 +1,3 @@ +fqName=b +bridgeName=b_bridge +returnType=short \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/request2.properties b/native/swift/sir-compiler-bridge/testData/primitive_types/request2.properties new file mode 100644 index 00000000000..9cc18acc3e0 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/request2.properties @@ -0,0 +1,3 @@ +fqName=c +bridgeName=c_bridge +returnType=int \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/request3.properties b/native/swift/sir-compiler-bridge/testData/primitive_types/request3.properties new file mode 100644 index 00000000000..d65bf6bfb94 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/request3.properties @@ -0,0 +1,3 @@ +fqName=d +bridgeName=d_bridge +returnType=long \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/primitive_types/request4.properties b/native/swift/sir-compiler-bridge/testData/primitive_types/request4.properties new file mode 100644 index 00000000000..e75f9169518 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/primitive_types/request4.properties @@ -0,0 +1,3 @@ +fqName=e +bridgeName=e_bridge +returnType=byte \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/smoke0/expected.h b/native/swift/sir-compiler-bridge/testData/smoke0/expected.h new file mode 100644 index 00000000000..bc3ee2452e5 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/smoke0/expected.h @@ -0,0 +1,3 @@ +#include + +int32_t a_b_foo_bridge(int32_t param1, int64_t param2); diff --git a/native/swift/sir-compiler-bridge/testData/smoke0/expected.kt b/native/swift/sir-compiler-bridge/testData/smoke0/expected.kt new file mode 100644 index 00000000000..1bc517c569f --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/smoke0/expected.kt @@ -0,0 +1,7 @@ +import kotlin.native.internal.ExportForCppRuntime + +@ExportForCppRuntime("a_b_foo_bridge") +public fun a_b_foo_bridge(param1: Int, param2: Long): Int { + val result = a.b.foo(param1, param2) + return result +} \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/smoke0/request.properties b/native/swift/sir-compiler-bridge/testData/smoke0/request.properties new file mode 100644 index 00000000000..9a915ec3005 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/smoke0/request.properties @@ -0,0 +1,4 @@ +fqName=a.b.foo +bridgeName=a_b_foo_bridge +parameters=param1:int param2:long +returnType=int \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.h b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.h new file mode 100644 index 00000000000..9690b6067e8 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.h @@ -0,0 +1,9 @@ +#include + +uint16_t b_bridge(); + +uint32_t c_bridge(); + +uint64_t d_bridge(); + +uint8_t e_bridge(); diff --git a/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.kt b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.kt new file mode 100644 index 00000000000..614685c6d45 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/expected.kt @@ -0,0 +1,25 @@ +import kotlin.native.internal.ExportForCppRuntime + +@ExportForCppRuntime("b_bridge") +public fun b_bridge(): UShort { + val result = b() + return result +} + +@ExportForCppRuntime("c_bridge") +public fun c_bridge(): UInt { + val result = c() + return result +} + +@ExportForCppRuntime("d_bridge") +public fun d_bridge(): ULong { + val result = d() + return result +} + +@ExportForCppRuntime("e_bridge") +public fun e_bridge(): UByte { + val result = e() + return result +} \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request1.properties b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request1.properties new file mode 100644 index 00000000000..51f56a4e6e2 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request1.properties @@ -0,0 +1,3 @@ +fqName=b +bridgeName=b_bridge +returnType=ushort \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request2.properties b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request2.properties new file mode 100644 index 00000000000..6aea2a31e9d --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request2.properties @@ -0,0 +1,3 @@ +fqName=c +bridgeName=c_bridge +returnType=uint \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request3.properties b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request3.properties new file mode 100644 index 00000000000..c67657a4346 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request3.properties @@ -0,0 +1,3 @@ +fqName=d +bridgeName=d_bridge +returnType=ulong \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request4.properties b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request4.properties new file mode 100644 index 00000000000..dc0e7ff2e17 --- /dev/null +++ b/native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/request4.properties @@ -0,0 +1,3 @@ +fqName=e +bridgeName=e_bridge +returnType=ubyte \ No newline at end of file diff --git a/native/swift/sir-compiler-bridge/tests-gen/org/jetbrains/kotlin/sir/bridge/SirCompilerBridgeTestGenerated.java b/native/swift/sir-compiler-bridge/tests-gen/org/jetbrains/kotlin/sir/bridge/SirCompilerBridgeTestGenerated.java new file mode 100644 index 00000000000..5ce29be98d7 --- /dev/null +++ b/native/swift/sir-compiler-bridge/tests-gen/org/jetbrains/kotlin/sir/bridge/SirCompilerBridgeTestGenerated.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.sir.bridge; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.native.swift.sir.analysis.api.GenerateSirAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("native/swift/sir-compiler-bridge/testData") +@TestDataPath("$PROJECT_ROOT") +public class SirCompilerBridgeTestGenerated extends AbstractKotlinSirBridgeTest { + @Test + public void testAllFilesPresentInTestData() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/swift/sir-compiler-bridge/testData"), Pattern.compile("^([^\\.]+)$"), null, false); + } + + @Test + @TestMetadata("multiple_requests") + public void testMultiple_requests() throws Exception { + runTest("native/swift/sir-compiler-bridge/testData/multiple_requests/"); + } + + @Test + @TestMetadata("smoke0") + public void testSmoke0() throws Exception { + runTest("native/swift/sir-compiler-bridge/testData/smoke0/"); + } + + @Test + @TestMetadata("primitive_types") + public void testPrimitive_types() throws Exception { + runTest("native/swift/sir-compiler-bridge/testData/primitive_types/"); + } + + @Test + @TestMetadata("unsigned_primitive_types") + public void testUnsigned_primitive_types() throws Exception { + runTest("native/swift/sir-compiler-bridge/testData/unsigned_primitive_types/"); + } + + @Test + @TestMetadata("primitive_parameters") + public void testPrimitive_parameters() throws Exception { + runTest("native/swift/sir-compiler-bridge/testData/primitive_parameters/"); + } +} diff --git a/settings.gradle b/settings.gradle index bedd860d0f2..34636f09d06 100644 --- a/settings.gradle +++ b/settings.gradle @@ -401,6 +401,7 @@ include ":plugins:compose-compiler-plugin:compiler", include ":native:swift:sir", ":native:swift:sir-passes", ":native:swift:sir-analysis-api", + ":native:swift:sir-compiler-bridge", ":generators:sir-analysis-api-generator" void intellij(String imlPath) {