[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)
+}