[WIP] Swift export: introduce MixedAST instead of String code representation
diff --git a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/SirBridgeProviderImpl.kt b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/SirBridgeProviderImpl.kt
index feff9e9..4f59500 100644
--- a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/SirBridgeProviderImpl.kt
+++ b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/SirBridgeProviderImpl.kt
@@ -11,6 +11,9 @@
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.sir.*
import org.jetbrains.kotlin.sir.providers.*
+import org.jetbrains.kotlin.sir.providers.impl.tree.MixedAST
+import org.jetbrains.kotlin.sir.providers.impl.tree.ast
+import org.jetbrains.kotlin.sir.providers.impl.tree.invoke
import org.jetbrains.kotlin.sir.providers.source.kaSymbolOrNull
import org.jetbrains.kotlin.sir.providers.utils.KotlinCoroutineSupportModule
import org.jetbrains.kotlin.sir.providers.utils.KotlinRuntimeSupportModule
@@ -234,9 +237,11 @@
} else if (errorParameter != null) {
add("var ${errorParameter.name}: UnsafeMutableRawPointer? = nil")
add("let _result = ".takeIf { resultTransformer != null }.orEmpty() + descriptor.swiftInvocationLineForCBridge(typeNamer))
- val error = errorParameter.bridge.inSwiftSources.kotlinToSwift(typeNamer, errorParameter.name)
+ val error = errorParameter.bridge.inSwiftSources.kotlinToSwift(typeNamer, errorParameter.name.ast())
add("guard ${errorParameter.name} == nil else { throw KotlinError(wrapped: $error) }")
- resultTransformer?.let { add(it(descriptor.returnType.inSwiftSources.kotlinToSwift(typeNamer, "_result"))) }
+ resultTransformer?.let {
+ add(it(descriptor.returnType.inSwiftSources.kotlinToSwift(typeNamer, "_result".ast()).toString()))
+ }
} else {
val swiftCallAndTransformationLines = descriptor.swiftLinesForCBridgeCallAndTransformation(typeNamer)
addAll(swiftCallAndTransformationLines.dropLast(1))
@@ -295,7 +300,7 @@
allParameters.forEach {
val parameterName = "__${it.name}".kotlinIdentifier
- add("${indent}val $parameterName = ${it.bridge.inKotlinSources.swiftToKotlin(typeNamer, it.name.kotlinIdentifier)}")
+ add("${indent}val $parameterName = ${it.bridge.inKotlinSources.swiftToKotlin(typeNamer, it.name.kotlinIdentifier.ast())}")
}
val callSite = buildCallSite()
val resultName = "_result"
@@ -326,7 +331,7 @@
"""
try {
val $resultName = $callSite
- return ${returnType.inKotlinSources.kotlinToSwift(typeNamer, resultName)}
+ return ${returnType.inKotlinSources.kotlinToSwift(typeNamer, resultName.ast())}
} catch (error: Throwable) {
__${errorParameter.name}.value = StableRef.create(error).asCPointer()
return $defaultValue
@@ -335,28 +340,28 @@
)
} else {
add("${indent}val $resultName = $callSite")
- add("${indent}return ${returnType.inKotlinSources.kotlinToSwift(typeNamer, resultName)}")
+ add("${indent}return ${returnType.inKotlinSources.kotlinToSwift(typeNamer, resultName.ast())}")
}
}
add("}")
}
-private fun BridgeFunctionDescriptor.swiftInvocationLineForCBridge(typeNamer: SirTypeNamer): String {
- val parameters = allParameters.filter { it.isRenderable }.joinToString {
+private fun BridgeFunctionDescriptor.swiftInvocationLineForCBridge(typeNamer: SirTypeNamer): MixedAST {
+ val parameters = allParameters.filter { it.isRenderable }.map {
// We fix ugly `self` escaping here. This is the only place we'd otherwise need full support for swift's contextual keywords
- it.bridge.inSwiftSources.swiftToKotlin(typeNamer, it.name.takeIf { it == "self" } ?: it.name.swiftIdentifier)
+ it.bridge.inSwiftSources.swiftToKotlin(typeNamer, (it.name.takeIf { it == "self" } ?: it.name.swiftIdentifier).ast())
}
- return "$cBridgeName($parameters)"
+ return cBridgeName.ast().invoke(*parameters.toTypedArray())
}
private fun BridgeFunctionDescriptor.swiftLinesForCBridgeCallAndTransformation(typeNamer: SirTypeNamer): List<String> {
val swiftInvocation = swiftInvocationLineForCBridge(typeNamer)
if (returnType.typeList.size <= 1) {
- return listOf(returnType.inSwiftSources.kotlinToSwift(typeNamer, swiftInvocation))
+ return listOf(returnType.inSwiftSources.kotlinToSwift(typeNamer, swiftInvocation).toString())
}
return buildList {
add("let _result = $swiftInvocation")
- add(returnType.inSwiftSources.kotlinToSwift(typeNamer, "_result"))
+ add(returnType.inSwiftSources.kotlinToSwift(typeNamer, "_result".ast()).toString())
}
}
@@ -429,7 +434,7 @@
private val BridgeFunctionDescriptor.safeImportName: String
get() = kotlinFqName.pathSegments().joinToString(separator = "_") { it.asString().replace("_", "__") }
-private fun String.prependIndentToTrailingLines(indent: String): String = this.lines().let { lines ->
+private fun MixedAST.prependIndentToTrailingLines(indent: String): String = toString().lines().let { lines ->
lines.singleOrNull() ?: buildString {
append(lines.first())
for (line in lines.drop(1)) {
diff --git a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/TypeBridging.kt b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/TypeBridging.kt
index 26c06c0..3d88d6d 100644
--- a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/TypeBridging.kt
+++ b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/BridgeProvider/TypeBridging.kt
@@ -9,6 +9,33 @@
import org.jetbrains.kotlin.sir.providers.SirSession
import org.jetbrains.kotlin.sir.providers.SirTypeNamer
import org.jetbrains.kotlin.sir.providers.impl.BridgeProvider.Bridge.*
+import org.jetbrains.kotlin.sir.providers.impl.tree.MixedAST
+import org.jetbrains.kotlin.sir.providers.impl.tree.access
+import org.jetbrains.kotlin.sir.providers.impl.tree.addr
+import org.jetbrains.kotlin.sir.providers.impl.tree.asExcl
+import org.jetbrains.kotlin.sir.providers.impl.tree.ast
+import org.jetbrains.kotlin.sir.providers.impl.tree.block
+import org.jetbrains.kotlin.sir.providers.impl.tree.brackets
+import org.jetbrains.kotlin.sir.providers.impl.tree.cond
+import org.jetbrains.kotlin.sir.providers.impl.tree.create
+import org.jetbrains.kotlin.sir.providers.impl.tree.createClassWrapper
+import org.jetbrains.kotlin.sir.providers.impl.tree.createProtocolWrapper
+import org.jetbrains.kotlin.sir.providers.impl.tree.createRetainedExternalRCRef
+import org.jetbrains.kotlin.sir.providers.impl.tree.dereferenceExternalRCRef
+import org.jetbrains.kotlin.sir.providers.impl.tree.eq
+import org.jetbrains.kotlin.sir.providers.impl.tree.exclExcl
+import org.jetbrains.kotlin.sir.providers.impl.tree.externalRCRef
+import org.jetbrains.kotlin.sir.providers.impl.tree.interpretObjCPointer
+import org.jetbrains.kotlin.sir.providers.impl.tree.invoke
+import org.jetbrains.kotlin.sir.providers.impl.tree.invokeLambda
+import org.jetbrains.kotlin.sir.providers.impl.tree.kotlinTypeName
+import org.jetbrains.kotlin.sir.providers.impl.tree.named
+import org.jetbrains.kotlin.sir.providers.impl.tree.objcPtr
+import org.jetbrains.kotlin.sir.providers.impl.tree.op
+import org.jetbrains.kotlin.sir.providers.impl.tree.ret
+import org.jetbrains.kotlin.sir.providers.impl.tree.safeAccess
+import org.jetbrains.kotlin.sir.providers.impl.tree.switch
+import org.jetbrains.kotlin.sir.providers.impl.tree.variable
import org.jetbrains.kotlin.sir.providers.toBridge
import org.jetbrains.kotlin.sir.providers.utils.KotlinRuntimeModule
import org.jetbrains.kotlin.sir.providers.utils.KotlinRuntimeSupportModule
@@ -160,14 +187,14 @@
* Generate value conversions from Swift to Kotlin.
*/
internal interface SwiftToKotlinValueConversion {
- fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String = valueExpression
+ fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
}
/**
* Generate value conversions from Kotlin to Swift.
*/
internal interface KotlinToSwiftValueConversion {
- fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String = valueExpression
+ fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
}
/**
@@ -176,13 +203,16 @@
internal interface ValueConversion : SwiftToKotlinValueConversion, KotlinToSwiftValueConversion
internal object IdentityValueConversion : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) = valueExpression
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) = valueExpression
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
}
-private fun String.mapSwift(temporalName: String = "it", transform: (String) -> String): String {
- val adapter = transform(temporalName).takeIf { it != temporalName }
- return this + (adapter?.let { ".map { $temporalName in $it }" } ?: "")
+private fun MixedAST.mapSwift(temporalName: String = "it", transform: (MixedAST) -> MixedAST): MixedAST {
+ val adapter = transform(temporalName.ast()).takeIf { it.toString() != temporalName }
+ if (adapter == null) return this
+ return access("map").invokeLambda {
+ temporalName.ast().op(MixedAST.Operator.IN, adapter)
+ }
}
internal sealed interface AnyBridge {
@@ -275,9 +305,9 @@
object AsVoid : WithSingleType(SirNominalType(SirSwiftModule.void), KotlinType.Unit, CType.Void) {
override val inKotlinSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String = "Unit"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = MixedAST.Unit
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String = valueExpression
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
}
override val inSwiftSources = IdentityValueConversion
@@ -289,11 +319,14 @@
CType.Int32
) {
override val inKotlinSources = object : SwiftToKotlinValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String = valueExpression
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
}
override val inSwiftSources = object : SwiftToKotlinValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String = "{ $valueExpression; return 0 }()"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = block {
+ +valueExpression
+ +"0".ast().ret()
+ }.invoke()
}
}
@@ -315,27 +348,28 @@
class AsObject(swiftType: SirNominalType, kotlinType: KotlinType, cType: CType) : WithSingleType(swiftType, kotlinType, cType) {
override val inKotlinSources = object : ValueConversion {
// nulls are handled by AsOptionalWrapper, so safe to cast from nullable to non-nullable
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.dereferenceExternalRCRef($valueExpression) as ${
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.dereferenceExternalRCRef().op(
+ MixedAST.Operator.AS,
typeNamer.kotlinFqName(
swiftType,
SirTypeNamer.KotlinNameType.PARAMETRIZED
- )
- }"
+ ).ast()
+ )
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.createRetainedExternalRCRef($valueExpression)"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.createRetainedExternalRCRef()
}
override val inSwiftSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) = "${valueExpression}.__externalRCRef()"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.externalRCRef()
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
- val swiftFqName = typeNamer.swiftFqName(swiftType)
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
return if (swiftType.isValueType) {
- "$swiftFqName(__externalRCRefUnsafe: $valueExpression, options: .asBestFittingWrapper)"
+ swiftType.create(typeNamer, valueExpression)
} else {
- "$swiftFqName.__createClassWrapper(externalRCRef: $valueExpression)"
+ swiftType.createClassWrapper(typeNamer, valueExpression)
}
}
}
@@ -359,23 +393,23 @@
*/
object AsAnyBridgeable : WithSingleType(KotlinRuntimeSupportModule.kotlinBridgeableType, KotlinType.KotlinObject, CType.Object) {
override val inKotlinSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.dereferenceExternalRCRef($valueExpression) as kotlin.Any"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.dereferenceExternalRCRef().op(MixedAST.Operator.AS, MixedAST.KotlinAny)
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.createRetainedExternalRCRef($valueExpression)"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.createRetainedExternalRCRef()
}
override val inSwiftSources: ValueConversion = object : ValueConversion {
override fun swiftToKotlin(
typeNamer: SirTypeNamer,
- valueExpression: String,
- ): String {
- return "$valueExpression.__externalRCRef()"
- }
+ valueExpression: MixedAST,
+ ): MixedAST = valueExpression.externalRCRef()
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "${typeNamer.swiftFqName(SirNominalType(KotlinRuntimeModule.kotlinBase))}.__createProtocolWrapper(externalRCRef: $valueExpression) as! ${typeNamer.swiftFqName(swiftType)}"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ SirNominalType(KotlinRuntimeModule.kotlinBase)
+ .createProtocolWrapper(typeNamer, valueExpression)
+ .asExcl(typeNamer, swiftType)
}
}
@@ -394,34 +428,38 @@
*/
class AsExistential(swiftType: SirExistentialType, kotlinType: KotlinType, cType: CType) : WithSingleType(swiftType, kotlinType, cType) {
override val inKotlinSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.dereferenceExternalRCRef($valueExpression) as ${
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.dereferenceExternalRCRef().op(
+ MixedAST.Operator.AS,
typeNamer.kotlinFqName(
swiftType,
SirTypeNamer.KotlinNameType.PARAMETRIZED
- )
- }"
+ ).ast()
+ )
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.createRetainedExternalRCRef($valueExpression)"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.createRetainedExternalRCRef()
}
override val inSwiftSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) = "${valueExpression}.__externalRCRef()"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.externalRCRef()
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "${typeNamer.swiftFqName(SirNominalType(KotlinRuntimeModule.kotlinBase))}.__createProtocolWrapper(externalRCRef: $valueExpression) as! ${typeNamer.swiftFqName(swiftType)}"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ SirNominalType(KotlinRuntimeModule.kotlinBase)
+ .createProtocolWrapper(typeNamer, valueExpression)
+ .asExcl(typeNamer, swiftType)
}
}
class AsOpaqueObject(swiftType: SirType, kotlinType: KotlinType, cType: CType) : WithSingleType(swiftType, kotlinType, cType) {
override val inKotlinSources = object : ValueConversion {
// nulls are handled by AsOptionalWrapper, so safe to cast from nullable to non-nullable
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.dereferenceExternalRCRef($valueExpression)!!"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.dereferenceExternalRCRef().exclExcl()
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "kotlin.native.internal.ref.createRetainedExternalRCRef($valueExpression)"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.createRetainedExternalRCRef()
}
override val inSwiftSources = IdentityValueConversion
@@ -432,11 +470,11 @@
cType: CType,
) : WithSingleType(swiftType, KotlinType.ObjCObjectUnretained, cType) {
override val inKotlinSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String =
- "interpretObjCPointer<${typeNamer.kotlinFqName(swiftType, SirTypeNamer.KotlinNameType.PARAMETRIZED)}>($valueExpression)"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.interpretObjCPointer(swiftType, typeNamer)
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "$valueExpression.objcPtr()"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.objcPtr()
}
override val inSwiftSources: ValueConversion = IdentityValueConversion
@@ -448,11 +486,11 @@
) : AsObjCBridged(swiftType, CType.id) {
override val inSwiftSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
- return "$valueExpression as! NSObject? ?? NSNull()"
- }
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.op(MixedAST.Operator.AS_EXCL, "NSObject?".ast())
+ .op(MixedAST.Operator.SWIFT_ELVIS, MixedAST.NsNull.invoke())
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String = valueExpression
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = valueExpression
}
}
@@ -465,11 +503,11 @@
// promotes `UInt16` (which `UTF16.CodeUnit` is) to the closest fitting signed integer storage (C int).
// -[NSNumber toKotlin] then produces Int box when crossing bridge,
// which doesn't pass strict cast checks near interpretObjCPointer
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String =
- "interpretObjCPointer<Int>($valueExpression).toChar()"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.interpretObjCPointer("Int").access("toChar")
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "$valueExpression.objcPtr()"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.objcPtr()
}
} else {
super.inKotlinSources
@@ -477,10 +515,10 @@
override val inSwiftSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String =
- "NSNumber(value: $valueExpression)"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ "NSNumber".ast().invoke(valueExpression.named("value"))
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
require(swiftType is SirNominalType)
val fromNSNumberValue = when (swiftType.typeDeclaration) {
SirSwiftModule.bool -> "boolValue"
@@ -500,7 +538,7 @@
else -> error("Attempt to get ${swiftType.typeDeclaration} from NSNumber")
}
- return "$valueExpression.$fromNSNumberValue"
+ return valueExpression.access(fromNSNumberValue)
}
}
}
@@ -511,8 +549,8 @@
}
override val inKotlinSources = object : ValueConversion by super.inKotlinSources {
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String =
- super@OptionalChar.inKotlinSources.kotlinToSwift(typeNamer, "${valueExpression}?.code")
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ super@OptionalChar.inKotlinSources.kotlinToSwift(typeNamer, valueExpression.safeAccess("code"))
}
}
@@ -520,8 +558,8 @@
swiftType: SirNominalType,
) : AsObjCBridged(swiftType, CType.NSObject) {
override val inSwiftSources: ValueConversion = object : ValueConversion {
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String =
- "$valueExpression as! ${typeNamer.swiftFqName(swiftType)}"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.asExcl(typeNamer, swiftType)
}
}
@@ -530,17 +568,16 @@
cType: CType,
) : AsObjCBridged(swiftType, cType) {
abstract inner class InSwiftSources : ValueConversion {
- abstract override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String
+ abstract override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
- return "$valueExpression as! ${typeNamer.swiftFqName(swiftType)}"
- }
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.asExcl(typeNamer, swiftType)
}
}
open class AsNSArray(swiftType: SirNominalType, elementBridge: WithSingleType) : AsNSCollection(swiftType, CType.NSArray(elementBridge.cType)) {
override val inSwiftSources = object : InSwiftSources() {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
return valueExpression.mapSwift { elementBridge.inSwiftSources.swiftToKotlin(typeNamer, it) }
}
}
@@ -548,26 +585,21 @@
class AsNSArrayForVariadic(swiftType: SirNominalType, elementBridge: WithSingleType) : AsNSArray(swiftType, elementBridge) {
override val inKotlinSources: ValueConversion = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
val arrayKind = typeNamer.kotlinPrimitiveFqNameIfAny(swiftType.typeArguments.single()) ?: "Typed"
- return "interpretObjCPointer<${
- typeNamer.kotlinFqName(
- swiftType,
- SirTypeNamer.KotlinNameType.PARAMETRIZED
- )
- }>($valueExpression).to${arrayKind}Array()"
+ return valueExpression.interpretObjCPointer(swiftType, typeNamer).access("to${arrayKind}Array").invoke()
}
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "$valueExpression.objcPtr()"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.objcPtr()
}
}
class AsNSSet(swiftType: SirNominalType, elementBridge: WithSingleType) : AsNSCollection(swiftType, CType.NSSet(elementBridge.cType)) {
override val inSwiftSources = object : InSwiftSources() {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
val transformedElements = valueExpression.mapSwift { elementBridge.inSwiftSources.swiftToKotlin(typeNamer, it) }
- return if (transformedElements == valueExpression) valueExpression else "Set($transformedElements)"
+ return if (transformedElements == valueExpression) valueExpression else "Set".ast().invoke(transformedElements)
}
}
}
@@ -576,16 +608,25 @@
AsNSCollection(swiftType, CType.NSDictionary(keyBridge.cType, valueBridge.cType)) {
override val inSwiftSources = object : InSwiftSources() {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
- val keyAdapter = keyBridge.inSwiftSources.swiftToKotlin(typeNamer, "key")
- val valueAdapter = valueBridge.inSwiftSources.swiftToKotlin(typeNamer, "value")
- return if (keyAdapter == "key" && valueAdapter == "value") {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
+ val key = "key".ast()
+ val value = "value".ast()
+ val keyAdapter = keyBridge.inSwiftSources.swiftToKotlin(typeNamer, key)
+ val valueAdapter = valueBridge.inSwiftSources.swiftToKotlin(typeNamer, value)
+ return if (keyAdapter.toString() == "key" && valueAdapter.toString() == "value") {
valueExpression
} else {
- "Dictionary(uniqueKeysWithValues: $valueExpression.map { key, value in (" +
- "${keyBridge.inSwiftSources.swiftToKotlin(typeNamer, "key")}, " +
- "${valueBridge.inSwiftSources.swiftToKotlin(typeNamer, "value")} " +
- ")})"
+ val argument = valueExpression.access("map").invokeLambda {
+ +key.op(MixedAST.Operator.COMMA, value)
+ .op(
+ MixedAST.Operator.IN,
+ brackets(
+ keyBridge.inSwiftSources.swiftToKotlin(typeNamer, key),
+ valueBridge.inSwiftSources.swiftToKotlin(typeNamer, value)
+ )
+ )
+ }
+ "Dictionary".ast().invoke(argument.named("uniqueKeysWithValues"))
}
}
}
@@ -597,14 +638,16 @@
CType.Void
) {
override val inKotlinSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) = "null"
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) = "Unit"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = MixedAST.Null
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = MixedAST.Unit
}
override val inSwiftSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String) = error("unrepresentable")
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String) =
- "{ ${valueExpression}; return nil; }()"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = error("unrepresentable")
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST = block {
+ +valueExpression
+ +MixedAST.Nil.ret()
+ }.invoke()
}
}
@@ -617,40 +660,46 @@
override val inKotlinSources: ValueConversion
get() = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
require(wrappedObject is SwiftToKotlinBridge)
- return "if ($valueExpression == kotlin.native.internal.NativePtr.NULL) null else ${
+ return valueExpression.eq(MixedAST.NativeNull).cond(
+ MixedAST.Null,
wrappedObject.inKotlinSources.swiftToKotlin(typeNamer, valueExpression)
- }"
+ )
}
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
require(wrappedObject is KotlinToSwiftBridge)
- return "if ($valueExpression == null) kotlin.native.internal.NativePtr.NULL else ${
+ return valueExpression.eq(MixedAST.NativeNull).cond(
+ MixedAST.Null,
wrappedObject.inKotlinSources.kotlinToSwift(typeNamer, valueExpression)
- }"
+ )
}
}
override val inSwiftSources: ValueConversion = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
require(
wrappedObject is AsObjCBridged || wrappedObject is AsObject ||
wrappedObject is AsExistential || wrappedObject is AsAnyBridgeable || wrappedObject is AsBlock ||
wrappedObject is SirCustomTypeTranslatorImpl.RangeBridge
)
- return valueExpression.mapSwift { wrappedObject.inSwiftSources.swiftToKotlin(typeNamer, it) } +
- " ?? ${wrappedObject.renderNil()}"
+ return valueExpression.mapSwift {
+ wrappedObject.inSwiftSources.swiftToKotlin(typeNamer, it)
+ }.op(MixedAST.Operator.SWIFT_ELVIS, wrappedObject.nil())
}
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
return when (wrappedObject) {
is AsObjCBridged ->
valueExpression.mapSwift { wrappedObject.inSwiftSources.kotlinToSwift(typeNamer, it) }
is AsObject, is AsExistential, is AsAnyBridgeable, is SirCustomTypeTranslatorImpl.RangeBridge ->
- "{ switch $valueExpression { case ${wrappedObject.renderNil()}: .none; case let res: ${
- wrappedObject.inSwiftSources.kotlinToSwift(typeNamer, "res")
- }; } }()"
+ block {
+ +valueExpression.switch {
+ case(wrappedObject.nil(), MixedAST.None)
+ case("res".variable(), wrappedObject.inSwiftSources.kotlinToSwift(typeNamer, "res".ast()))
+ }
+ }.invoke()
is AsBlock,
is AsIs,
is AsVoid,
@@ -711,50 +760,46 @@
override val inKotlinSources: SwiftToKotlinValueConversion
get() = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
val argsInClosure = parameters
.mapIndexed { idx, el -> "arg${idx}" to el }.takeIf { it.isNotEmpty() }
- val defineArgs = argsInClosure
- ?.let {
- " ${
- it.joinToString {
- "${it.first}: ${
- typeNamer.kotlinFqName(
- it.second.swiftType,
- SirTypeNamer.KotlinNameType.PARAMETRIZED
- )
- }"
- }
- } ->"
+ val defineArgs = argsInClosure?.map { (name, bridge) ->
+ name.ast().op(MixedAST.Operator.COLON, bridge.swiftType.kotlinTypeName(typeNamer))
+ }
+ val callArgs = argsInClosure?.map { (name, bridge) ->
+ bridge.inKotlinSources.kotlinToSwift(typeNamer, name.ast())
+ }.orEmpty()
+ return "run".ast().invokeLambda {
+ +"kotlinFun".variable().op(
+ MixedAST.Operator.ASSIGN,
+ "convertBlockPtrToKotlinFunction<$kotlinFunctionTypeRendered>".ast().invoke(valueExpression)
+ )
+ +block(defineArgs?.let { MixedAST.LambdaParameters(it) }) {
+ +"_result".variable().op(MixedAST.Operator.ASSIGN, "kotlinFun".ast().invoke(*callArgs.toTypedArray()))
+ +returnType.inKotlinSources.swiftToKotlin(typeNamer, "_result".ast())
}
- val callArgs = argsInClosure
- ?.let { it.joinToString { it.second.inKotlinSources.kotlinToSwift(typeNamer, it.first) } } ?: ""
- return """run {
- | val kotlinFun = convertBlockPtrToKotlinFunction<$kotlinFunctionTypeRendered>($valueExpression);
- | {${defineArgs ?: ""}
- | val _result = kotlinFun($callArgs)
- | ${returnType.inKotlinSources.swiftToKotlin(typeNamer, "_result")}
- | }
- |}""".replaceIndentByMargin(" ")
+ }
}
}
override val inSwiftSources = object : SwiftToKotlinValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
val argsInClosure = parameters
.mapIndexed { idx, el -> "arg${idx}" to el }.takeIf { it.isNotEmpty() }
- val defineArgs = argsInClosure
- ?.let { " ${it.joinToString { it.first }} in" } ?: ""
- val callArgs = argsInClosure
- ?.let {
- it.joinToString { param ->
- param.second.inSwiftSources.kotlinToSwift(typeNamer, param.first)
- }
- } ?: ""
- return """{
- | let originalBlock = $valueExpression
- | return {$defineArgs ${"return ${returnType.inSwiftSources.swiftToKotlin(typeNamer, "originalBlock($callArgs)")}"} }
- |}()""".trimMargin()
+ val defineArgs = argsInClosure?.map { (name, bridge) ->
+ name.ast().op(MixedAST.Operator.IN, "".ast())
+ }
+ val callArgs = argsInClosure?.map { (name, bridge) ->
+ bridge.inSwiftSources.kotlinToSwift(typeNamer, name.ast())
+ }.orEmpty()
+ return block {
+ +"originalBlock".variable().op(MixedAST.Operator.ASSIGN, valueExpression)
+ +block(defineArgs?.let { MixedAST.LambdaParameters(it) }) {
+ returnType.inSwiftSources.swiftToKotlin(
+ typeNamer, "originalBlock".ast().invoke(*callArgs.toTypedArray())
+ ).ret()
+ }.ret()
+ }
}
}
}
@@ -765,15 +810,15 @@
override val inSwiftSources: ValueConversion
get() = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
- return "&$valueExpression"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
+ return valueExpression.addr()
}
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
- return "${typeNamer.swiftFqName(SirNominalType(KotlinRuntimeModule.kotlinBase))}.__createClassWrapper(externalRCRef: $valueExpression)"
- }
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ SirNominalType(KotlinRuntimeModule.kotlinBase)
+ .createClassWrapper(typeNamer, valueExpression)
}
}
}
-private fun AnyBridge.renderNil(): String = if (this is AsObjCBridgedOptional) "NSNull()" else "nil"
+private fun AnyBridge.nil(): MixedAST = if (this is AsObjCBridgedOptional) MixedAST.NsNull else MixedAST.Nil
diff --git a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/SirCustomTypeTranslatorImpl.kt b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/SirCustomTypeTranslatorImpl.kt
index 1e6907f..c63a42b 100644
--- a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/SirCustomTypeTranslatorImpl.kt
+++ b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/SirCustomTypeTranslatorImpl.kt
@@ -52,6 +52,13 @@
import org.jetbrains.kotlin.sir.providers.impl.BridgeProvider.Bridge.AsNSSet
import org.jetbrains.kotlin.sir.providers.impl.BridgeProvider.Bridge.AsObjCBridged
import org.jetbrains.kotlin.sir.providers.impl.SirTypeProviderImpl.TypeTranslationCtx
+import org.jetbrains.kotlin.sir.providers.impl.tree.MixedAST
+import org.jetbrains.kotlin.sir.providers.impl.tree.access
+import org.jetbrains.kotlin.sir.providers.impl.tree.ast
+import org.jetbrains.kotlin.sir.providers.impl.tree.createRetainedExternalRCRef
+import org.jetbrains.kotlin.sir.providers.impl.tree.invoke
+import org.jetbrains.kotlin.sir.providers.impl.tree.op
+import org.jetbrains.kotlin.sir.providers.impl.tree.parameterX
import org.jetbrains.kotlin.sir.util.SirSwiftModule
public class SirCustomTypeTranslatorImpl(
@@ -214,24 +221,25 @@
get() = typeList.first().cType
override val inKotlinSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String {
- val operator = if (inclusive) ".." else "..<"
- return "${valueExpression}_1 $operator ${valueExpression}_2"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
+ val operator = if (inclusive) MixedAST.Operator.RANGE_KOTLIN else MixedAST.Operator.RANGE_UNTIL
+ return valueExpression.parameterX(1).op(operator, valueExpression.parameterX(2))
}
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String =
- "kotlin.native.internal.ref.createRetainedExternalRCRef($valueExpression)"
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.createRetainedExternalRCRef()
}
override val inSwiftSources = object : ValueConversion {
- override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: String): String =
- "$valueExpression.lowerBound, $valueExpression.upperBound"
+ override fun swiftToKotlin(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST =
+ valueExpression.access("lowerBound").op(MixedAST.Operator.COMMA, valueExpression.access("upperBound"))
- override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: String): String {
+ override fun kotlinToSwift(typeNamer: SirTypeNamer, valueExpression: MixedAST): MixedAST {
val startBridge = nativePointerToMultipleObjCBridge(0)
val endBridge = nativePointerToMultipleObjCBridge(1)
- val operator = if (inclusive) "..." else "..<"
- return "${startBridge.name}($valueExpression) $operator ${endBridge.name}($valueExpression)"
+ val operator = if (inclusive) MixedAST.Operator.RANGE_SWIFT else MixedAST.Operator.RANGE_UNTIL
+ return startBridge.name.ast().invoke(valueExpression)
+ .op(operator, endBridge.name.ast().invoke(valueExpression))
}
}
diff --git a/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/tree/MixedAST.kt b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/tree/MixedAST.kt
new file mode 100644
index 0000000..6dabd68
--- /dev/null
+++ b/native/swift/sir-providers/src/org/jetbrains/kotlin/sir/providers/impl/tree/MixedAST.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2010-2025 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.providers.impl.tree
+
+import org.jetbrains.kotlin.sir.SirType
+import org.jetbrains.kotlin.sir.providers.SirTypeNamer
+
+/**
+ * This class represents simple AST, that is used in TypeBridging.kt
+ * for Swift & Kotlin generated code representation
+ */
+internal sealed class MixedAST {
+ class Direct(val expression: String) : MixedAST() {
+ override fun toString(): String = expression
+ }
+
+ class ExternalRcRef(val argument: MixedAST) : MixedAST() {
+ override fun toString(): String = "$argument.__externalRCRef()"
+ }
+
+ class BinaryOp(val left: MixedAST, val operator: Operator, val right: MixedAST) : MixedAST() {
+ override fun toString(): String = "$left$operator$right"
+
+ fun replace(operator: Operator = this.operator, transform: (MixedAST) -> MixedAST) =
+ BinaryOp(transform(left), operator, transform(right))
+ }
+
+ class Conditional(val condition: MixedAST, val ifTrue: MixedAST, val ifFalse: MixedAST) : MixedAST() {
+ override fun toString(): String = "if ($condition) $ifTrue else $ifFalse"
+ }
+
+ class Variable(val identifier: MixedAST) : MixedAST() {
+ override fun toString(): String = "let $identifier"
+ }
+
+ class Case(val branch: MixedAST, val result: MixedAST) : MixedAST() {
+ override fun toString(): String = "case $branch: $result;"
+ }
+
+ class Switch(val subject: MixedAST, val cases: List<Case>) : MixedAST() {
+ override fun toString(): String = buildString {
+ append("switch $subject { ")
+ append(cases.joinToString(separator = " "))
+ append(" }")
+ }
+ }
+
+ class Block(val lambdaParameters: LambdaParameters?, val argument: MixedAST) : MixedAST() {
+ override fun toString(): String =
+ if (lambdaParameters == null) "{ $argument }"
+ else "{ $lambdaParameters $argument }"
+ }
+
+ class Invoke(val callee: MixedAST, val argument: MixedAST? = null) : MixedAST() {
+ override fun toString(): String = if (argument == null) "$callee()" else "$callee($argument)"
+ }
+
+ class InvokeLambda(val callee: MixedAST, val argument: Block) : MixedAST() {
+ override fun toString(): String = "$callee $argument"
+ }
+
+ class Return(val argument: MixedAST) : MixedAST() {
+ override fun toString(): String = "return $argument"
+ }
+
+ class ExclExcl(val argument: MixedAST) : MixedAST() {
+ override fun toString(): String = "$argument!!"
+ }
+
+ class Addr(val argument: MixedAST) : MixedAST() {
+ override fun toString(): String = "&$argument"
+ }
+
+ class LambdaParameters(val parameters: List<MixedAST>) : MixedAST() {
+ override fun toString(): String = parameters.joinToString() + " -> "
+ }
+
+ object Unit : MixedAST() {
+ override fun toString(): String = "Unit"
+ }
+
+ object Null : MixedAST() {
+ override fun toString(): String = "null"
+ }
+
+ object Nil : MixedAST() {
+ override fun toString(): String = "nil"
+ }
+
+ object NativeNull : MixedAST() {
+ override fun toString(): String = "kotlin.native.internal.NativePtr.NULL"
+ }
+
+ object NsNull : MixedAST() {
+ override fun toString(): String = "NSNull"
+ }
+
+ object None : MixedAST() {
+ override fun toString(): String = ".none"
+ }
+
+ object KotlinAny : MixedAST() {
+ override fun toString(): String = "kotlin.Any"
+ }
+
+ enum class Operator(private val representation: String) {
+ COMMA(", "),
+ SEMICOLON("; "),
+ COLON(": "),
+ ACCESS("."),
+ SAFE_ACCESS("?."),
+ AS(" as "),
+ AS_EXCL(" as! "),
+ ASSIGN(" = "),
+ EQUALS(" == "),
+ IN(" in "),
+ SWIFT_ELVIS(" ?? "),
+ RANGE_KOTLIN(" .. "),
+ RANGE_SWIFT(" ... "),
+ RANGE_UNTIL(" ..< "),
+ ;
+
+ override fun toString(): String = representation
+ }
+}
+
+internal fun String.ast() = MixedAST.Direct(this)
+
+internal fun MixedAST.parameterX(index: Int): MixedAST.Direct {
+ assert(this is MixedAST.Direct)
+ return MixedAST.Direct("${this}_$index")
+}
+
+internal fun MixedAST.access(name: String) = MixedAST.BinaryOp(this, MixedAST.Operator.ACCESS, name.ast())
+
+internal fun MixedAST.safeAccess(name: String) = MixedAST.BinaryOp(this, MixedAST.Operator.SAFE_ACCESS, name.ast())
+
+internal fun MixedAST.externalRCRef() = access("__externalRCRef").invoke()
+
+internal fun MixedAST.dereferenceExternalRCRef() = access("kotlin.native.internal.ref.dereferenceExternalRCRef").invoke()
+
+internal fun MixedAST.createRetainedExternalRCRef() = access("kotlin.native.internal.ref.createRetainedExternalRCRef").invoke()
+
+internal fun MixedAST.objcPtr() = access("objcPtr").invoke()
+
+internal fun MixedAST.interpretObjCPointer(type: SirType, namer: SirTypeNamer) =
+ interpretObjCPointer(type.kotlinTypeName(namer).toString())
+
+internal fun MixedAST.interpretObjCPointer(typeName: String) =
+ "__interpretObjCPointer<$typeName>".ast().invoke(this)
+
+internal fun MixedAST.invoke(vararg arguments: MixedAST): MixedAST.Invoke {
+ if (arguments.isEmpty()) return MixedAST.Invoke(this)
+ var argument: MixedAST = arguments.first()
+ for (i in 1 until arguments.size) {
+ argument = argument.op(MixedAST.Operator.COMMA, arguments[i])
+ }
+ return MixedAST.Invoke(this, argument)
+}
+
+internal fun brackets(vararg arguments: MixedAST): MixedAST =
+ "".ast().invoke(*arguments)
+
+internal fun MixedAST.invokeLambda(f: BlockBuilder.() -> Unit) =
+ MixedAST.InvokeLambda(this, block(f))
+
+internal fun String.variable(): MixedAST.Variable = MixedAST.Variable(ast())
+
+internal fun MixedAST.named(name: String): MixedAST = name.ast().op(MixedAST.Operator.COLON, this)
+
+internal fun asBestFittingWrapper() = ".asBestFittingWrapper".ast().named("options")
+
+internal fun MixedAST.ret() = MixedAST.Return(this)
+
+internal fun MixedAST.exclExcl() = MixedAST.ExclExcl(this)
+
+internal fun MixedAST.asExcl(namer: SirTypeNamer, type: SirType) =
+ op(MixedAST.Operator.AS_EXCL, type.swiftTypeName(namer))
+
+internal fun MixedAST.addr() = MixedAST.Addr(this)
+
+internal fun MixedAST.eq(right: MixedAST) = op(MixedAST.Operator.EQUALS, right)
+
+internal fun MixedAST.op(op: MixedAST.Operator, right: MixedAST) = MixedAST.BinaryOp(this, op, right)
+
+internal fun MixedAST.cond(ifTrue: MixedAST, ifFalse: MixedAST) = MixedAST.Conditional(this, ifTrue, ifFalse)
+
+internal fun SirType.kotlinTypeName(namer: SirTypeNamer): MixedAST =
+ namer.kotlinFqName(this, SirTypeNamer.KotlinNameType.PARAMETRIZED).ast()
+
+internal fun SirType.swiftTypeName(namer: SirTypeNamer): MixedAST =
+ namer.swiftFqName(this).ast()
+
+internal fun SirType.createProtocolWrapper(namer: SirTypeNamer, expression: MixedAST): MixedAST =
+ swiftTypeName(namer).access("__createProtocolWrapper").invoke(expression.named("externalRCRef"))
+
+internal fun SirType.createClassWrapper(namer: SirTypeNamer, expression: MixedAST): MixedAST =
+ swiftTypeName(namer).access("__createClassWrapper").invoke(expression.named("externalRCRef"))
+
+internal fun SirType.create(namer: SirTypeNamer, expression: MixedAST): MixedAST =
+ swiftTypeName(namer).invoke(expression.named("__externalRCRefUnsafe"), asBestFittingWrapper())
+
+internal fun block(lambdaParameters: MixedAST.LambdaParameters? = null, f: BlockBuilder.() -> Unit): MixedAST.Block {
+ return BlockBuilder(lambdaParameters).apply { f() }.block
+}
+
+internal fun MixedAST.switch(f: SwitchBuilder.() -> Unit): MixedAST.Switch {
+ return SwitchBuilder(this).apply { f() }.switch
+}
+
+internal class BlockBuilder(val lambdaParameters: MixedAST.LambdaParameters?) {
+ private val statements: MutableList<MixedAST> = mutableListOf()
+
+ operator fun MixedAST.unaryPlus() {
+ add(this)
+ }
+
+ fun add(statement: MixedAST) {
+ statements += statement
+ }
+
+ fun add(s: String) {
+ add(s.ast())
+ }
+
+ val block: MixedAST.Block
+ get() {
+ var ast = statements.first()
+ for (i in 1 until statements.size) {
+ ast = ast.op(MixedAST.Operator.SEMICOLON, statements[i])
+ }
+ return MixedAST.Block(lambdaParameters, ast)
+ }
+}
+
+internal class SwitchBuilder(val subject: MixedAST) {
+ private val cases: MutableList<MixedAST.Case> = mutableListOf()
+
+ fun case(branch: MixedAST, result: MixedAST) {
+ cases.add(MixedAST.Case(branch, result))
+ }
+
+ val switch: MixedAST.Switch
+ get() = MixedAST.Switch(subject, cases)
+}