rrn/rd/KT-63270-swift-printer
KT-63270: add swift printing capabilities to SIR Co-authored-by: Artem Olkov <artem.olkov@jetbrains.com> Co-authored-by: Sergej Jaskiewicz <jaskiewiczs@icloud.com> Merge-request: KT-MR-13191 Merged-by: Gleb Lukianets <Gleb.Lukianets@jetbrains.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
description = "Printer for SIR"
|
||||
|
||||
dependencies {
|
||||
compileOnly(kotlinStdlib())
|
||||
|
||||
api(project(":native:swift:sir"))
|
||||
|
||||
implementation(project(":core:util.runtime"))
|
||||
|
||||
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() }
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.sir.printer
|
||||
|
||||
import org.jetbrains.kotlin.sir.*
|
||||
import org.jetbrains.kotlin.sir.visitors.SirVisitor
|
||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||
|
||||
private const val DEFAULT_INDENT: String = " "
|
||||
|
||||
class SirAsSwiftSourcesPrinter : SirVisitor<Unit, SmartPrinter>() {
|
||||
fun print(element: SirElement): String = buildString {
|
||||
element.accept(this@SirAsSwiftSourcesPrinter, SmartPrinter(this))
|
||||
}.trim()
|
||||
|
||||
override fun visitModule(module: SirModule, data: SmartPrinter) = with(data) {
|
||||
module.declarations.forEach {
|
||||
it.accept(this@SirAsSwiftSourcesPrinter, this)
|
||||
if (module.declarations.last() != it) {
|
||||
println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(function: SirFunction, data: SmartPrinter): Unit = with(data) {
|
||||
println(listOfNotNull(
|
||||
function.visibility.takeIf { it != SirVisibility.INTERNAL }?.let { "${it.swift} " },
|
||||
"func ",
|
||||
function.name.swiftIdentifier,
|
||||
function.parameters.takeIf { it.isNotEmpty() }
|
||||
?.joinToString(prefix = "(\n", postfix = "\n)", separator = ",\n") {
|
||||
it.swift.prependIndent(DEFAULT_INDENT)
|
||||
} ?: "()",
|
||||
" -> ",
|
||||
function.returnType.swift,
|
||||
" { fatalError() }"
|
||||
).joinToString(separator = ""))
|
||||
}
|
||||
|
||||
override fun visitForeignFunction(function: SirForeignFunction, data: SmartPrinter) {} // we do not write Foreign nodes
|
||||
|
||||
override fun visitElement(element: SirElement, data: SmartPrinter): Unit = with(data) {
|
||||
println("/* ERROR: unsupported element type: " + element.javaClass.simpleName + " */")
|
||||
}
|
||||
}
|
||||
|
||||
private val SirVisibility.swift
|
||||
get(): String = when (this) {
|
||||
SirVisibility.PRIVATE -> "private"
|
||||
SirVisibility.FILEPRIVATE -> "fileprivate"
|
||||
SirVisibility.INTERNAL -> "internal"
|
||||
SirVisibility.PUBLIC -> "public"
|
||||
SirVisibility.PACKAGE -> "package"
|
||||
}
|
||||
|
||||
private val SirParameter.swift get(): String = (argumentName ?: "_") + (parameterName?.let { " $it" } ?: "") + ": " + type.swift
|
||||
|
||||
private val SirType.swift
|
||||
get(): String = when (this) {
|
||||
is SirExistentialType -> "Any"
|
||||
is SirNominalType -> type.swiftFqName
|
||||
}
|
||||
|
||||
private val SirNamedDeclaration.swiftFqName: String
|
||||
get() {
|
||||
val parentName = (parent as? SirNamedDeclaration)?.swiftFqName ?: ((parent as? SirNamed)?.name)
|
||||
return parentName?.let { "$it.$name" } ?: name
|
||||
}
|
||||
|
||||
private val simpleIdentifierRegex = Regex("[_a-zA-Z][_a-zA-Z0-9]*")
|
||||
|
||||
private val String.swiftIdentifier get() = if (simpleIdentifierRegex.matches(this)) this else "`$this`"
|
||||
@@ -0,0 +1,9 @@
|
||||
public func foo(
|
||||
arg1: Swift.Bool,
|
||||
arg2: Swift.Int8,
|
||||
arg3: Swift.Int16,
|
||||
arg4: Swift.Int32,
|
||||
arg5: Swift.Int64,
|
||||
arg6: Swift.Double,
|
||||
arg7: Swift.Float
|
||||
) -> Swift.Bool { fatalError() }
|
||||
@@ -0,0 +1 @@
|
||||
public func foo() -> Swift.Bool { fatalError() }
|
||||
@@ -0,0 +1,3 @@
|
||||
public func foo1() -> Swift.Bool { fatalError() }
|
||||
|
||||
public func foo2() -> Swift.Bool { fatalError() }
|
||||
@@ -0,0 +1,3 @@
|
||||
public func foo(
|
||||
arg1: Swift.Int32
|
||||
) -> Swift.Bool { fatalError() }
|
||||
@@ -0,0 +1,4 @@
|
||||
public func foo(
|
||||
arg1: Swift.Int32,
|
||||
arg2: Swift.Double
|
||||
) -> Swift.Bool { fatalError() }
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.printer
|
||||
|
||||
import org.jetbrains.kotlin.sir.*
|
||||
import org.jetbrains.kotlin.sir.builder.buildForeignFunction
|
||||
import org.jetbrains.kotlin.sir.builder.buildFunction
|
||||
import org.jetbrains.kotlin.sir.builder.buildModule
|
||||
import org.jetbrains.kotlin.sir.util.SirSwiftModule
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import org.jetbrains.sir.printer.SirAsSwiftSourcesPrinter
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
fun basicModule(): SirModule = buildModule { name = "Test" }
|
||||
|
||||
class SirAsSwiftSourcesPrinterTests {
|
||||
@Test
|
||||
fun `should ignore foreign elements`() {
|
||||
val module = buildModule {
|
||||
name = "Test"
|
||||
declarations.add(foreignFunction())
|
||||
}
|
||||
|
||||
runTest(
|
||||
module,
|
||||
"testData/empty"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should print simple function`() {
|
||||
val module = buildModule {
|
||||
name = "Test"
|
||||
declarations.add(
|
||||
buildFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
name = "foo"
|
||||
returnType = SirNominalType(SirSwiftModule.bool)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
runTest(
|
||||
module,
|
||||
"testData/simple_function"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should print multiple functions`() {
|
||||
val module = buildModule {
|
||||
name = "Test"
|
||||
declarations.add(
|
||||
buildFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
name = "foo1"
|
||||
returnType = SirNominalType(SirSwiftModule.bool)
|
||||
}
|
||||
)
|
||||
declarations.add(
|
||||
buildFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
name = "foo2"
|
||||
returnType = SirNominalType(SirSwiftModule.bool)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
runTest(
|
||||
module,
|
||||
"testData/simple_multiple_function"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should print single argument`() {
|
||||
val module = buildModule {
|
||||
name = "Test"
|
||||
declarations.add(
|
||||
buildFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
name = "foo"
|
||||
parameters.add(
|
||||
SirParameter(
|
||||
argumentName = "arg1",
|
||||
type = SirNominalType(SirSwiftModule.int32)
|
||||
)
|
||||
)
|
||||
returnType = SirNominalType(SirSwiftModule.bool)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
runTest(
|
||||
module,
|
||||
"testData/single_argument"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should print two argument`() {
|
||||
val module = buildModule {
|
||||
name = "Test"
|
||||
|
||||
declarations.add(
|
||||
buildFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
name = "foo"
|
||||
parameters.add(
|
||||
SirParameter(
|
||||
argumentName = "arg1",
|
||||
type = SirNominalType(SirSwiftModule.int32)
|
||||
)
|
||||
)
|
||||
parameters.add(
|
||||
SirParameter(
|
||||
argumentName = "arg2",
|
||||
type = SirNominalType(SirSwiftModule.double)
|
||||
)
|
||||
)
|
||||
returnType = SirNominalType(SirSwiftModule.bool)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
runTest(
|
||||
module,
|
||||
"testData/two_arguments"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should all types as parameter be handled`() {
|
||||
val module = buildModule {
|
||||
name = "Test"
|
||||
declarations.add(foreignFunction())
|
||||
|
||||
declarations.add(
|
||||
buildFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
name = "foo"
|
||||
parameters.addAll(
|
||||
listOf(
|
||||
SirParameter(
|
||||
argumentName = "arg1",
|
||||
type = SirNominalType(SirSwiftModule.bool)
|
||||
),
|
||||
SirParameter(
|
||||
argumentName = "arg2",
|
||||
type = SirNominalType(SirSwiftModule.int8)
|
||||
),
|
||||
SirParameter(
|
||||
argumentName = "arg3",
|
||||
type = SirNominalType(SirSwiftModule.int16)
|
||||
),
|
||||
SirParameter(
|
||||
argumentName = "arg4",
|
||||
type = SirNominalType(SirSwiftModule.int32)
|
||||
),
|
||||
SirParameter(
|
||||
argumentName = "arg5",
|
||||
type = SirNominalType(SirSwiftModule.int64)
|
||||
),
|
||||
SirParameter(
|
||||
argumentName = "arg6",
|
||||
type = SirNominalType(SirSwiftModule.double)
|
||||
),
|
||||
SirParameter(
|
||||
argumentName = "arg7",
|
||||
type = SirNominalType(SirSwiftModule.float)
|
||||
),
|
||||
)
|
||||
)
|
||||
returnType = SirNominalType(SirSwiftModule.bool)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
runTest(
|
||||
module,
|
||||
"testData/all_types_argument"
|
||||
)
|
||||
}
|
||||
|
||||
private fun runTest(module: SirModule, goldenDataFile: String) {
|
||||
val expectedSwiftSrc = File(KtTestUtil.getHomeDirectory()).resolve("$goldenDataFile.golden.swift")
|
||||
|
||||
val actualSwiftSrc = SirAsSwiftSourcesPrinter().print(module)
|
||||
JUnit5Assertions.assertEqualsToFile(expectedSwiftSrc, actualSwiftSrc)
|
||||
}
|
||||
|
||||
private fun foreignFunction(): SirForeignFunction = buildForeignFunction {
|
||||
origin = SirOrigin.Unknown
|
||||
visibility = SirVisibility.PUBLIC
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user