Improve naming in produced framework
* Group top-level declarations by file name instead of package name
* Remove main prefix from Swift class names
* Use 'Kotlin' prefix
* Instead of 'Stdlib'
* In Swift names for KotlinMutableSet/Dictionary, KotlinNumber and subclasses
This commit is contained in:
committed by
SvyatoslavScherbina
parent
2f61cf9fa3
commit
da2736337e
+18
-15
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
@@ -149,24 +148,28 @@ internal class ObjCExportCodeGenerator(
|
||||
|
||||
internal fun emitRtti(
|
||||
generatedClasses: Collection<ClassDescriptor>,
|
||||
topLevel: Map<FqName, List<CallableMemberDescriptor>>
|
||||
topLevel: Map<SourceFile, List<CallableMemberDescriptor>>
|
||||
) {
|
||||
val objCTypeAdapters = mutableListOf<ObjCTypeAdapter>()
|
||||
|
||||
generatedClasses.forEach {
|
||||
objCTypeAdapters += createTypeAdapter(it)
|
||||
val className = namer.getClassOrProtocolName(it)
|
||||
val superClass = it.getSuperClassOrAny()
|
||||
val superClassName = namer.getClassOrProtocolName(superClass)
|
||||
|
||||
dataGenerator.emitEmptyClass(className, superClassName)
|
||||
// Note: it is generated only to be visible for linker.
|
||||
// Methods will be added at runtime.
|
||||
if (!it.isInterface) {
|
||||
val className = namer.getClassOrProtocolName(it).binaryName
|
||||
val superClass = it.getSuperClassOrAny()
|
||||
val superClassName = namer.getClassOrProtocolName(superClass).binaryName
|
||||
|
||||
dataGenerator.emitEmptyClass(className, superClassName)
|
||||
// Note: it is generated only to be visible for linker.
|
||||
// Methods will be added at runtime.
|
||||
}
|
||||
}
|
||||
|
||||
topLevel.forEach { fqName, declarations ->
|
||||
objCTypeAdapters += createTypeAdapterForPackage(fqName, declarations)
|
||||
dataGenerator.emitEmptyClass(namer.getPackageName(fqName), namer.kotlinAnyName)
|
||||
topLevel.forEach { sourceFile, declarations ->
|
||||
objCTypeAdapters += createTypeAdapterForFileClass(sourceFile, declarations)
|
||||
val name = namer.getFileClassName(sourceFile).binaryName
|
||||
dataGenerator.emitEmptyClass(name, namer.kotlinAnyName.binaryName)
|
||||
}
|
||||
|
||||
NSNumberKind.values().mapNotNull { it.mappedKotlinClassId }.forEach {
|
||||
@@ -831,11 +834,11 @@ private fun ObjCExportCodeGenerator.vtableIndex(descriptor: FunctionDescriptor):
|
||||
}
|
||||
}
|
||||
|
||||
private fun ObjCExportCodeGenerator.createTypeAdapterForPackage(
|
||||
fqName: FqName,
|
||||
private fun ObjCExportCodeGenerator.createTypeAdapterForFileClass(
|
||||
sourceFile: SourceFile,
|
||||
declarations: List<CallableMemberDescriptor>
|
||||
): ObjCExportCodeGenerator.ObjCTypeAdapter {
|
||||
val name = namer.getPackageName(fqName)
|
||||
val name = namer.getFileClassName(sourceFile).binaryName
|
||||
|
||||
val adapters = declarations.toMethods().map { createMethodAdapter(it, it) }
|
||||
|
||||
@@ -934,7 +937,7 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
|
||||
|
||||
val irClass = context.ir.get(descriptor)
|
||||
val typeInfo = constPointer(codegen.typeInfoValue(irClass))
|
||||
val objCName = namer.getClassOrProtocolName(descriptor)
|
||||
val objCName = namer.getClassOrProtocolName(descriptor).binaryName
|
||||
|
||||
val vtableSize = if (descriptor.kind == ClassKind.INTERFACE) {
|
||||
-1
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.objcexport.ObjCExportCodeGenerato
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceFile
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -33,7 +34,7 @@ internal class ObjCExport(val codegen: CodeGenerator) {
|
||||
|
||||
val objCCodeGenerator: ObjCExportCodeGenerator
|
||||
val generatedClasses: Set<ClassDescriptor>
|
||||
val topLevelDeclarations: Map<FqName, List<CallableMemberDescriptor>>
|
||||
val topLevelDeclarations: Map<SourceFile, List<CallableMemberDescriptor>>
|
||||
|
||||
if (context.config.produce == CompilerOutputKind.FRAMEWORK) {
|
||||
val headerGenerator = ObjCExportHeaderGeneratorImpl(context)
|
||||
|
||||
+74
-40
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
@@ -43,7 +42,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
internal val namer = ObjCExportNamerImpl(moduleDescriptor, builtIns, mapper, topLevelNamePrefix)
|
||||
|
||||
internal val generatedClasses = mutableSetOf<ClassDescriptor>()
|
||||
internal val topLevel = mutableMapOf<FqName, MutableList<CallableMemberDescriptor>>()
|
||||
internal val topLevel = mutableMapOf<SourceFile, MutableList<CallableMemberDescriptor>>()
|
||||
|
||||
private val mappedToNSNumber: List<ClassDescriptor> = with(builtIns) {
|
||||
val result = mutableListOf(boolean, byte, short, int, long, float, double)
|
||||
@@ -63,15 +62,15 @@ abstract class ObjCExportHeaderGenerator(
|
||||
result += CustomTypeMapper.Collection(generator, list, "NSArray")
|
||||
result += CustomTypeMapper.Collection(generator, mutableList, "NSMutableArray")
|
||||
result += CustomTypeMapper.Collection(generator, set, "NSSet")
|
||||
result += CustomTypeMapper.Collection(generator, mutableSet, namer.mutableSetName)
|
||||
result += CustomTypeMapper.Collection(generator, mutableSet, namer.mutableSetName.objCName)
|
||||
result += CustomTypeMapper.Collection(generator, map, "NSDictionary")
|
||||
result += CustomTypeMapper.Collection(generator, mutableMap, namer.mutableMapName)
|
||||
result += CustomTypeMapper.Collection(generator, mutableMap, namer.mutableMapName.objCName)
|
||||
|
||||
NSNumberKind.values().forEach {
|
||||
// TODO: NSNumber seem to have different equality semantics.
|
||||
if (it.mappedKotlinClassId != null) {
|
||||
val descriptor = moduleDescriptor.findClassAcrossModuleDependencies(it.mappedKotlinClassId)!!
|
||||
result += CustomTypeMapper.Simple(descriptor, namer.numberBoxName(descriptor))
|
||||
result += CustomTypeMapper.Simple(descriptor, namer.numberBoxName(descriptor).objCName)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,7 +98,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
private val kotlinAnyName = namer.kotlinAnyName
|
||||
|
||||
private val stubs = mutableListOf<Stub<*>>()
|
||||
private val classOrInterfaceToName = mutableMapOf<ClassDescriptor, String>()
|
||||
private val classOrInterfaceToName = mutableMapOf<ClassDescriptor, ObjCExportNamer.ClassOrProtocolName>()
|
||||
|
||||
private val classForwardDeclarations = mutableSetOf<String>()
|
||||
private val protocolForwardDeclarations = mutableSetOf<String>()
|
||||
@@ -107,37 +106,74 @@ abstract class ObjCExportHeaderGenerator(
|
||||
private val extensions = mutableMapOf<ClassDescriptor, MutableList<CallableMemberDescriptor>>()
|
||||
private val extraClassesToTranslate = mutableSetOf<ClassDescriptor>()
|
||||
|
||||
private fun objCInterface(
|
||||
name: ObjCExportNamer.ClassOrProtocolName,
|
||||
generics: List<String> = emptyList(),
|
||||
descriptor: ClassDescriptor? = null,
|
||||
superClass: String? = null,
|
||||
superProtocols: List<String> = emptyList(),
|
||||
categoryName: String? = null,
|
||||
members: List<Stub<*>> = emptyList(),
|
||||
attributes: List<String> = emptyList()
|
||||
): ObjCInterface = ObjCInterface(
|
||||
name.objCName,
|
||||
generics,
|
||||
descriptor,
|
||||
superClass,
|
||||
superProtocols,
|
||||
categoryName,
|
||||
members,
|
||||
attributes + name.toNameAttributes()
|
||||
)
|
||||
|
||||
private fun objCProtocol(
|
||||
name: ObjCExportNamer.ClassOrProtocolName,
|
||||
descriptor: ClassDescriptor,
|
||||
superProtocols: List<String>,
|
||||
members: List<Stub<*>>,
|
||||
attributes: List<String> = emptyList()
|
||||
): ObjCProtocol = ObjCProtocol(
|
||||
name.objCName,
|
||||
descriptor,
|
||||
superProtocols,
|
||||
members,
|
||||
attributes + name.toNameAttributes()
|
||||
)
|
||||
|
||||
private fun ObjCExportNamer.ClassOrProtocolName.toNameAttributes(): List<String> = listOfNotNull(
|
||||
binaryName.takeIf { it != objCName }?.let { objcRuntimeNameAttribute(it) },
|
||||
swiftName.takeIf { it != objCName }?.let { swiftNameAttribute(it) }
|
||||
)
|
||||
|
||||
fun translateModule(): List<Stub<*>> {
|
||||
// TODO: make the translation order stable
|
||||
// to stabilize name mangling.
|
||||
|
||||
stubs.add(ObjCInterface(kotlinAnyName, superClass = "NSObject", members = buildMembers {
|
||||
stubs.add(objCInterface(kotlinAnyName, superClass = "NSObject", members = buildMembers {
|
||||
+ObjCMethod(null, true, ObjCInstanceType, listOf("init"), emptyList(), listOf("unavailable"))
|
||||
+ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable"))
|
||||
+ObjCMethod(null, false, ObjCVoidType, listOf("initialize"), emptyList(), listOf("objc_requires_super"))
|
||||
}))
|
||||
|
||||
// TODO: add comment to the header.
|
||||
stubs.add(ObjCInterface(
|
||||
stubs.add(objCInterface(
|
||||
kotlinAnyName,
|
||||
superProtocols = listOf("NSCopying"),
|
||||
categoryName = "${kotlinAnyName}Copying"
|
||||
categoryName = "${kotlinAnyName.objCName}Copying"
|
||||
))
|
||||
|
||||
// TODO: only if appears
|
||||
stubs.add(ObjCInterface(
|
||||
stubs.add(objCInterface(
|
||||
namer.mutableSetName,
|
||||
generics = listOf("ObjectType"),
|
||||
superClass = "NSMutableSet<ObjectType>",
|
||||
attributes = listOf(objcRuntimeNameAttribute("KotlinMutableSet"))
|
||||
superClass = "NSMutableSet<ObjectType>"
|
||||
))
|
||||
|
||||
// TODO: only if appears
|
||||
stubs.add(ObjCInterface(
|
||||
stubs.add(objCInterface(
|
||||
namer.mutableMapName,
|
||||
generics = listOf("KeyType", "ObjectType"),
|
||||
superClass = "NSMutableDictionary<KeyType, ObjectType>",
|
||||
attributes = listOf(objcRuntimeNameAttribute("KotlinMutableDictionary"))
|
||||
superClass = "NSMutableDictionary<KeyType, ObjectType>"
|
||||
))
|
||||
|
||||
stubs.add(ObjCInterface("NSError", categoryName = "NSErrorKotlinException", members = buildMembers {
|
||||
@@ -158,7 +194,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
if (classDescriptor != null) {
|
||||
extensions.getOrPut(classDescriptor, { mutableListOf() }) += it
|
||||
} else {
|
||||
topLevel.getOrPut(packageFragment.fqName, { mutableListOf() }) += it
|
||||
topLevel.getOrPut(it.source.containingFile, { mutableListOf() }) += it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,8 +224,8 @@ abstract class ObjCExportHeaderGenerator(
|
||||
translateExtensions(classDescriptor, declarations)
|
||||
}
|
||||
|
||||
topLevel.forEach { packageFqName, declarations ->
|
||||
translateTopLevel(packageFqName, declarations)
|
||||
topLevel.forEach { sourceFile, declarations ->
|
||||
translateTopLevel(sourceFile, declarations)
|
||||
}
|
||||
|
||||
while (extraClassesToTranslate.isNotEmpty()) {
|
||||
@@ -214,11 +250,10 @@ abstract class ObjCExportHeaderGenerator(
|
||||
+nsNumberInit(it, listOf("unavailable"))
|
||||
}
|
||||
}
|
||||
stubs.add(ObjCInterface(
|
||||
stubs.add(objCInterface(
|
||||
namer.kotlinNumberName,
|
||||
superClass = "NSNumber",
|
||||
members = members,
|
||||
attributes = listOf(objcRuntimeNameAttribute("KotlinNumber"))
|
||||
members = members
|
||||
))
|
||||
|
||||
NSNumberKind.values().forEach {
|
||||
@@ -236,11 +271,10 @@ abstract class ObjCExportHeaderGenerator(
|
||||
+nsNumberFactory(kind)
|
||||
+nsNumberInit(kind)
|
||||
}
|
||||
return ObjCInterface(
|
||||
return objCInterface(
|
||||
name,
|
||||
superClass = namer.kotlinNumberName,
|
||||
members = members,
|
||||
attributes = listOf(objcRuntimeNameAttribute("Kotlin${kotlinClassId.shortClassName}"))
|
||||
superClass = namer.kotlinNumberName.objCName,
|
||||
members = members
|
||||
)
|
||||
}
|
||||
|
||||
@@ -266,21 +300,21 @@ abstract class ObjCExportHeaderGenerator(
|
||||
)
|
||||
}
|
||||
|
||||
private fun translateClassName(descriptor: ClassDescriptor): String = classOrInterfaceToName.getOrPut(descriptor) {
|
||||
private fun translateClassName(descriptor: ClassDescriptor) = classOrInterfaceToName.getOrPut(descriptor) {
|
||||
assert(mapper.shouldBeExposed(descriptor))
|
||||
val forwardDeclarations = if (descriptor.isInterface) protocolForwardDeclarations else classForwardDeclarations
|
||||
|
||||
namer.getClassOrProtocolName(descriptor).also { forwardDeclarations += it }
|
||||
namer.getClassOrProtocolName(descriptor).also { forwardDeclarations += it.objCName }
|
||||
}
|
||||
|
||||
private fun translateInterface(descriptor: ClassDescriptor) {
|
||||
if (!generatedClasses.add(descriptor)) return
|
||||
|
||||
val name: String = translateClassName(descriptor)
|
||||
val name = translateClassName(descriptor)
|
||||
val members: List<Stub<*>> = buildMembers { translateClassOrInterfaceMembers(descriptor) }
|
||||
val superProtocols: List<String> = descriptor.superProtocols
|
||||
|
||||
val protocolStub = ObjCProtocol(name, descriptor, superProtocols, members)
|
||||
val protocolStub = objCProtocol(name, descriptor, superProtocols, members)
|
||||
|
||||
stubs.add(protocolStub)
|
||||
}
|
||||
@@ -292,7 +326,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
.filter { mapper.shouldBeExposed(it) }
|
||||
.map {
|
||||
translateInterface(it)
|
||||
translateClassName(it)
|
||||
translateClassName(it).objCName
|
||||
}
|
||||
.toList()
|
||||
|
||||
@@ -303,19 +337,19 @@ abstract class ObjCExportHeaderGenerator(
|
||||
val members = buildMembers {
|
||||
translateMembers(declarations)
|
||||
}
|
||||
stubs.add(ObjCInterface(name, categoryName = "Extensions", members = members))
|
||||
stubs.add(objCInterface(name, categoryName = "Extensions", members = members))
|
||||
}
|
||||
|
||||
private fun translateTopLevel(packageFqName: FqName, declarations: List<CallableMemberDescriptor>) {
|
||||
val name = namer.getPackageName(packageFqName)
|
||||
private fun translateTopLevel(sourceFile: SourceFile, declarations: List<CallableMemberDescriptor>) {
|
||||
val name = namer.getFileClassName(sourceFile)
|
||||
|
||||
// TODO: stop inheriting KotlinBase.
|
||||
val members = buildMembers {
|
||||
translateMembers(declarations)
|
||||
}
|
||||
stubs.add(ObjCInterface(
|
||||
stubs.add(objCInterface(
|
||||
name,
|
||||
superClass = namer.kotlinAnyName,
|
||||
superClass = namer.kotlinAnyName.objCName,
|
||||
members = members,
|
||||
attributes = listOf("objc_subclassing_restricted")
|
||||
))
|
||||
@@ -327,7 +361,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
val name = translateClassName(descriptor)
|
||||
val superClass = descriptor.getSuperClassNotAny()
|
||||
|
||||
val superName: String = if (superClass == null) {
|
||||
val superName = if (superClass == null) {
|
||||
kotlinAnyName
|
||||
} else {
|
||||
translateClass(superClass)
|
||||
@@ -404,10 +438,10 @@ abstract class ObjCExportHeaderGenerator(
|
||||
|
||||
val attributes = if (descriptor.isFinalOrEnum) listOf("objc_subclassing_restricted") else emptyList()
|
||||
|
||||
val interfaceStub = ObjCInterface(
|
||||
val interfaceStub = objCInterface(
|
||||
name,
|
||||
descriptor = descriptor,
|
||||
superClass = superName,
|
||||
superClass = superName.objCName,
|
||||
superProtocols = superProtocols,
|
||||
members = members,
|
||||
attributes = attributes
|
||||
@@ -763,9 +797,9 @@ abstract class ObjCExportHeaderGenerator(
|
||||
scheduleClassToBeGenerated(classDescriptor)
|
||||
|
||||
return if (classDescriptor.isInterface) {
|
||||
ObjCProtocolType(translateClassName(classDescriptor))
|
||||
ObjCProtocolType(translateClassName(classDescriptor).objCName)
|
||||
} else {
|
||||
ObjCClassType(translateClassName(classDescriptor))
|
||||
ObjCClassType(translateClassName(classDescriptor).objCName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
-29
@@ -9,14 +9,20 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isArray
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||
|
||||
|
||||
interface ObjCExportNamer {
|
||||
fun getPackageName(fqName: FqName): String
|
||||
fun getClassOrProtocolName(descriptor: ClassDescriptor): String
|
||||
data class ClassOrProtocolName(val swiftName: String, val objCName: String, val binaryName: String = objCName)
|
||||
|
||||
fun getFileClassName(file: SourceFile): ClassOrProtocolName
|
||||
fun getClassOrProtocolName(descriptor: ClassDescriptor): ClassOrProtocolName
|
||||
fun getSelector(method: FunctionDescriptor): String
|
||||
fun getSwiftName(method: FunctionDescriptor): String
|
||||
fun getPropertyName(property: PropertyDescriptor): String
|
||||
@@ -40,15 +46,27 @@ internal class ObjCExportNamerImpl(
|
||||
private val topLevelNamePrefix: String = moduleDescriptor.namePrefix
|
||||
) : ObjCExportNamer {
|
||||
|
||||
val kotlinAnyName = "KotlinBase"
|
||||
private fun String.mangleClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
|
||||
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = "$topLevelNamePrefix${this}")
|
||||
|
||||
private val commonPackageSegments = moduleDescriptor.guessMainPackage().pathSegments()
|
||||
private fun String.toUnmangledClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
|
||||
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = this)
|
||||
|
||||
val mutableSetName = "${topLevelNamePrefix}MutableSet"
|
||||
val mutableMapName = "${topLevelNamePrefix}MutableDictionary"
|
||||
private fun String.toSpecialStandardClassOrProtocolName() = ObjCExportNamer.ClassOrProtocolName(
|
||||
swiftName = "Kotlin$this",
|
||||
objCName = "${topLevelNamePrefix}$this",
|
||||
binaryName = "Kotlin$this"
|
||||
)
|
||||
|
||||
fun numberBoxName(descriptor: ClassDescriptor): String = "$topLevelNamePrefix${descriptor.name.asString()}"
|
||||
val kotlinNumberName = "${topLevelNamePrefix}Number"
|
||||
val kotlinAnyName = "KotlinBase".toUnmangledClassOrProtocolName()
|
||||
|
||||
val mutableSetName = "MutableSet".toSpecialStandardClassOrProtocolName()
|
||||
val mutableMapName = "MutableDictionary".toSpecialStandardClassOrProtocolName()
|
||||
|
||||
fun numberBoxName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName =
|
||||
descriptor.name.asString().toSpecialStandardClassOrProtocolName()
|
||||
|
||||
val kotlinNumberName = "Number".toSpecialStandardClassOrProtocolName()
|
||||
|
||||
private val methodSelectors = object : Mapping<FunctionDescriptor, String>() {
|
||||
|
||||
@@ -109,26 +127,26 @@ internal class ObjCExportNamerImpl(
|
||||
first.containingDeclaration == second.containingDeclaration
|
||||
}
|
||||
|
||||
override fun getPackageName(fqName: FqName): String = classNames.getOrPut(fqName) {
|
||||
StringBuilder().apply {
|
||||
append(topLevelNamePrefix)
|
||||
fqName.pathSegments().forEachIndexed { index, segment ->
|
||||
if (index < commonPackageSegments.size) {
|
||||
assert(commonPackageSegments[index] == segment)
|
||||
} else {
|
||||
append(segment.asString().capitalize())
|
||||
}
|
||||
}
|
||||
}.mangledSequence { append("_") }
|
||||
}
|
||||
override fun getFileClassName(file: SourceFile): ObjCExportNamer.ClassOrProtocolName = classNames.getOrPut(file) {
|
||||
val psiSourceFile = file as? PsiSourceFile ?: error("SourceFile '$file' is not PsiSourceFile")
|
||||
val psiFile = psiSourceFile.psiFile
|
||||
val ktFile = psiFile as? KtFile ?: error("PsiFile '$psiFile' is not KtFile")
|
||||
StringBuilder(PackagePartClassUtils.getFilePartShortName(ktFile.name)).mangledSequence { append("_") }
|
||||
}.mangleClassOrProtocolName()
|
||||
|
||||
private val predefinedClassNames = mapOf(
|
||||
builtIns.any to kotlinAnyName,
|
||||
builtIns.mutableSet to mutableSetName,
|
||||
builtIns.mutableMap to mutableMapName
|
||||
)
|
||||
|
||||
override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName {
|
||||
predefinedClassNames[descriptor]?.let { return it }
|
||||
|
||||
override fun getClassOrProtocolName(descriptor: ClassDescriptor): String {
|
||||
val mapping = if (descriptor.isInterface) protocolNames else classNames
|
||||
|
||||
return mapping.getOrPut(descriptor) {
|
||||
StringBuilder().apply {
|
||||
append(topLevelNamePrefix)
|
||||
|
||||
if (descriptor.module != moduleDescriptor) {
|
||||
append(descriptor.module.namePrefix)
|
||||
}
|
||||
@@ -137,7 +155,7 @@ internal class ObjCExportNamerImpl(
|
||||
.toList().reversed()
|
||||
.joinTo(this, "") { it.name.asString().capitalize() }
|
||||
}.mangledSequence { append("_") }
|
||||
}
|
||||
}.mangleClassOrProtocolName()
|
||||
}
|
||||
|
||||
override fun getSelector(method: FunctionDescriptor): String = methodSelectors.getOrPut(method) {
|
||||
@@ -192,7 +210,7 @@ internal class ObjCExportNamerImpl(
|
||||
assert(mapper.isBaseMethod(method))
|
||||
|
||||
val parameters = mapper.bridgeMethod(method).valueParametersAssociated(method)
|
||||
|
||||
|
||||
StringBuilder().apply {
|
||||
append(method.getMangledName(forSwift = true))
|
||||
append("(")
|
||||
@@ -261,9 +279,10 @@ internal class ObjCExportNamerImpl(
|
||||
init {
|
||||
val any = builtIns.any
|
||||
|
||||
classNames.forceAssign(any, kotlinAnyName)
|
||||
classNames.forceAssign(builtIns.mutableSet, mutableSetName)
|
||||
classNames.forceAssign(builtIns.mutableMap, mutableMapName)
|
||||
predefinedClassNames.forEach { descriptor, name ->
|
||||
// Note: it is a hack.
|
||||
classNames.forceAssign(descriptor, name.swiftName)
|
||||
}
|
||||
|
||||
fun ClassDescriptor.method(name: String) =
|
||||
this.unsubstitutedMemberScope.getContributedFunctions(
|
||||
@@ -453,6 +472,8 @@ private fun ObjCExportMapper.canHaveSameName(first: PropertyDescriptor, second:
|
||||
}
|
||||
|
||||
internal val ModuleDescriptor.namePrefix: String get() {
|
||||
if (this.isKonanStdlib()) return "Kotlin"
|
||||
|
||||
// <fooBar> -> FooBar
|
||||
val moduleName = this.name.asString()
|
||||
.let { it.substring(1, it.lastIndex) }
|
||||
|
||||
+3
@@ -12,6 +12,9 @@ object StubRenderer {
|
||||
stub.run {
|
||||
when (this) {
|
||||
is ObjCProtocol -> {
|
||||
attributes.forEach {
|
||||
+renderAttribute(it)
|
||||
}
|
||||
+renderProtocolHeader()
|
||||
+"@required"
|
||||
renderMembers(this)
|
||||
|
||||
+5
-3
@@ -15,12 +15,14 @@ open class Stub<out D : DeclarationDescriptor>(val name: String, val descriptor:
|
||||
abstract class ObjCClass<out D : DeclarationDescriptor>(name: String,
|
||||
descriptor: D?,
|
||||
val superProtocols: List<String>,
|
||||
val members: List<Stub<*>>) : Stub<D>(name, descriptor)
|
||||
val members: List<Stub<*>>,
|
||||
val attributes: List<String>) : Stub<D>(name, descriptor)
|
||||
|
||||
class ObjCProtocol(name: String,
|
||||
descriptor: ClassDescriptor,
|
||||
superProtocols: List<String>,
|
||||
members: List<Stub<*>>) : ObjCClass<ClassDescriptor>(name, descriptor, superProtocols, members)
|
||||
members: List<Stub<*>>,
|
||||
attributes: List<String> = emptyList()) : ObjCClass<ClassDescriptor>(name, descriptor, superProtocols, members, attributes)
|
||||
|
||||
class ObjCInterface(name: String,
|
||||
val generics: List<String> = emptyList(),
|
||||
@@ -29,7 +31,7 @@ class ObjCInterface(name: String,
|
||||
superProtocols: List<String> = emptyList(),
|
||||
val categoryName: String? = null,
|
||||
members: List<Stub<*>> = emptyList(),
|
||||
val attributes: List<String> = emptyList()) : ObjCClass<ClassDescriptor>(name, descriptor, superProtocols, members)
|
||||
attributes: List<String> = emptyList()) : ObjCClass<ClassDescriptor>(name, descriptor, superProtocols, members, attributes)
|
||||
|
||||
class ObjCMethod(descriptor: DeclarationDescriptor?,
|
||||
val isInstanceMethod: Boolean,
|
||||
|
||||
@@ -57,8 +57,8 @@ class StdlibTests : TestProvider {
|
||||
*/
|
||||
func testEmptyDictionary() throws {
|
||||
let immutableEmptyDict = [String: Int]()
|
||||
try assertTrue(Stdlib.isEmpty(map: immutableEmptyDict), "Empty dictionary")
|
||||
let keys = Stdlib.getKeysAsSet(map: immutableEmptyDict)
|
||||
try assertTrue(StdlibKt.isEmpty(map: immutableEmptyDict), "Empty dictionary")
|
||||
let keys = StdlibKt.getKeysAsSet(map: immutableEmptyDict)
|
||||
try assertTrue(keys.isEmpty, "Should have empty set")
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class StdlibTests : TestProvider {
|
||||
* Tests usage of a map with generics.
|
||||
*/
|
||||
func testGenericMapUsage() throws {
|
||||
let map = Stdlib.createLinkedMap()
|
||||
let map = StdlibKt.createLinkedMap()
|
||||
map[1] = "One"
|
||||
map[10] = "Ten"
|
||||
map[11] = "Eleven"
|
||||
@@ -82,7 +82,7 @@ class StdlibTests : TestProvider {
|
||||
* Checks order of the underlying LinkedHashMap.
|
||||
*/
|
||||
func testOrderedMapStored() throws {
|
||||
let pair = Stdlib.createPair()
|
||||
let pair = StdlibKt.createPair()
|
||||
let map = pair.first as? NSMutableDictionary
|
||||
|
||||
map?[1] = "One"
|
||||
@@ -90,7 +90,7 @@ class StdlibTests : TestProvider {
|
||||
map?[11] = "Eleven"
|
||||
map?["10"] = "Ten as string"
|
||||
|
||||
let gen = pair.second as! StdlibGenericExtensionClass
|
||||
let gen = pair.second as! GenericExtensionClass
|
||||
let value: String? = gen.getFirstValue() as? String
|
||||
try assertEquals(actual: value!, expected: "One", "First value of the map")
|
||||
|
||||
@@ -102,7 +102,7 @@ class StdlibTests : TestProvider {
|
||||
* Tests typed map created in Kotlin.
|
||||
*/
|
||||
func testTypedMapUsage() throws {
|
||||
let map = Stdlib.createTypedMutableMap()
|
||||
let map = StdlibKt.createTypedMutableMap()
|
||||
map[1] = "One"
|
||||
map[1.0 as Float] = "Float"
|
||||
map[11] = "Eleven"
|
||||
@@ -116,11 +116,11 @@ class StdlibTests : TestProvider {
|
||||
* Get first element of the collection.
|
||||
*/
|
||||
func testFirstElement() throws {
|
||||
let m = Stdlib.createTypedMutableMap()
|
||||
let m = StdlibKt.createTypedMutableMap()
|
||||
m[10] = "Str"
|
||||
try assertEquals(actual: Stdlib.getFirstElement(collection: m.allKeys) as! Int, expected: 10, "First key")
|
||||
try assertEquals(actual: StdlibKt.getFirstElement(collection: m.allKeys) as! Int, expected: 10, "First key")
|
||||
|
||||
try assertEquals(actual: Stdlib.getFirstElement(collection: Stdlib.getKeysAsList(map: m as! Dictionary)) as! Int,
|
||||
try assertEquals(actual: StdlibKt.getFirstElement(collection: StdlibKt.getKeysAsList(map: m as! Dictionary)) as! Int,
|
||||
expected: 10, "First key from a list")
|
||||
}
|
||||
|
||||
@@ -129,35 +129,35 @@ class StdlibTests : TestProvider {
|
||||
*/
|
||||
func testAddDictionary() throws {
|
||||
let m = [ "ABC": 10, "CDE": 12, "FGH": 3 ]
|
||||
Stdlib.addSomeElementsToMap(map: StdlibMutableDictionary(dictionary: m))
|
||||
StdlibKt.addSomeElementsToMap(map: KotlinMutableDictionary(dictionary: m))
|
||||
for (k, v) in m {
|
||||
print("MAP: \(k) - \(v)")
|
||||
}
|
||||
|
||||
var smd = StdlibMutableDictionary<NSString, StdlibInt>()
|
||||
var smd = KotlinMutableDictionary<NSString, KotlinInt>()
|
||||
smd.setObject(333, forKey: "333" as NSString)
|
||||
try assertEquals(actual: smd.object(forKey: "333" as NSString) as! Int, expected: 333, "Add element to dict")
|
||||
|
||||
Stdlib.addSomeElementsToMap(map: smd)
|
||||
StdlibKt.addSomeElementsToMap(map: smd)
|
||||
for (k, v) in smd {
|
||||
print("MAP: \(k) - \(v)")
|
||||
}
|
||||
try assertEquals(actual: smd.object(forKey: "XYZ" as NSString) as! Int, expected: 321, "Get element from Kotlin")
|
||||
}
|
||||
|
||||
func zeroTo(_ n: Int32) -> StdlibStdlibArray { return StdlibStdlibArray(size: n) { $0 } }
|
||||
func zeroTo(_ n: Int32) -> KotlinArray { return KotlinArray(size: n) { $0 } }
|
||||
|
||||
func testList() throws {
|
||||
let elements = zeroTo(5)
|
||||
elements.set(index: 1, value: nil)
|
||||
let list = Stdlib.list(elements: elements) as! NSArray
|
||||
let list = StdlibKt.list(elements: elements) as! NSArray
|
||||
try assertEquals(actual: list.object(at: 2) as! NSNumber, expected: NSNumber(value: 2))
|
||||
try assertEquals(actual: list.object(at: 1) as! NSNull, expected: NSNull())
|
||||
try assertEquals(actual: list.count, expected: 5)
|
||||
}
|
||||
|
||||
func testMutableList() throws {
|
||||
let kotlinList = Stdlib.emptyMutableList() as! NSMutableArray
|
||||
let kotlinList = StdlibKt.emptyMutableList() as! NSMutableArray
|
||||
let nsList = NSMutableArray()
|
||||
|
||||
func apply<T : Equatable>(op: (NSMutableArray)->T) throws {
|
||||
@@ -191,7 +191,7 @@ class StdlibTests : TestProvider {
|
||||
}
|
||||
|
||||
func testMutableSet() throws {
|
||||
let kotlinSet = Stdlib.emptyMutableSet() as! NSMutableSet
|
||||
let kotlinSet = StdlibKt.emptyMutableSet() as! NSMutableSet
|
||||
let nsSet = NSMutableSet()
|
||||
|
||||
func apply<T : Equatable>(op: (NSMutableSet)->T) throws {
|
||||
@@ -214,10 +214,10 @@ class StdlibTests : TestProvider {
|
||||
try applyVoid { $0.add("bar") }
|
||||
try applyVoid { $0.remove("baz") }
|
||||
try applyVoid { $0.add("baz") }
|
||||
try applyVoid { $0.add(StdlibTripleVals(first: 1, second: 2, third: 3)) }
|
||||
try apply { $0.member(StdlibTripleVals(first: 1, second: 2, third: 3)) as! StdlibTripleVals }
|
||||
try applyVoid { $0.add(TripleVals(first: 1, second: 2, third: 3)) }
|
||||
try apply { $0.member(TripleVals(first: 1, second: 2, third: 3)) as! TripleVals }
|
||||
try apply { $0.member(42) == nil }
|
||||
try applyVoid { $0.remove(StdlibTripleVals(first: 1, second: 2, third: 3)) }
|
||||
try applyVoid { $0.remove(TripleVals(first: 1, second: 2, third: 3)) }
|
||||
|
||||
let NULL0: Any? = nil
|
||||
let NULL = NULL0 as Any
|
||||
@@ -235,7 +235,7 @@ class StdlibTests : TestProvider {
|
||||
|
||||
func testMutableMap() throws {
|
||||
// TODO: test KotlinMutableSet/Dictionary constructors
|
||||
let kotlinMap = Stdlib.emptyMutableMap() as! NSMutableDictionary
|
||||
let kotlinMap = StdlibKt.emptyMutableMap() as! NSMutableDictionary
|
||||
let nsMap = NSMutableDictionary()
|
||||
|
||||
func apply<T : Equatable>(op: (NSMutableDictionary)->T) throws {
|
||||
@@ -257,7 +257,7 @@ class StdlibTests : TestProvider {
|
||||
try apply { $0.object(forKey: 42) == nil }
|
||||
try applyVoid { $0.setObject(42, forKey: 42 as NSNumber) }
|
||||
try applyVoid { $0.setObject(17, forKey: "foo" as NSString) }
|
||||
let triple = StdlibTripleVals(first: 3, second: 2, third: 1)
|
||||
let triple = TripleVals(first: 3, second: 2, third: 1)
|
||||
try applyVoid { $0.setObject("bar", forKey: triple) }
|
||||
try applyVoid { $0.removeObject(forKey: 42) }
|
||||
try apply { $0.count }
|
||||
@@ -312,10 +312,10 @@ class StdlibTests : TestProvider {
|
||||
}
|
||||
|
||||
func testSet() throws {
|
||||
let elements = StdlibStdlibArray(size: 2) { index in nil }
|
||||
let elements = KotlinArray(size: 2) { index in nil }
|
||||
elements.set(index: 0, value: nil)
|
||||
elements.set(index: 1, value: 42)
|
||||
let set = Stdlib.set(elements: elements) as! NSSet
|
||||
let set = StdlibKt.set(elements: elements) as! NSSet
|
||||
try assertEquals(actual: set.count, expected: 2)
|
||||
try assertEquals(actual: set.member(NSNull()) as! NSNull, expected: NSNull())
|
||||
try assertEquals(actual: set.member(42) as! NSNumber, expected: NSNumber(value: 42 as Int32))
|
||||
@@ -329,7 +329,7 @@ class StdlibTests : TestProvider {
|
||||
}
|
||||
|
||||
func testMap() throws {
|
||||
let elements = StdlibStdlibArray(size: 6) { index in nil }
|
||||
let elements = KotlinArray(size: 6) { index in nil }
|
||||
elements.set(index: 0, value: nil)
|
||||
elements.set(index: 1, value: 42)
|
||||
elements.set(index: 2, value: "foo")
|
||||
@@ -337,7 +337,7 @@ class StdlibTests : TestProvider {
|
||||
elements.set(index: 4, value: 42)
|
||||
elements.set(index: 5, value: nil)
|
||||
|
||||
let map = Stdlib.map(keysAndValues: elements) as! NSDictionary
|
||||
let map = StdlibKt.map(keysAndValues: elements) as! NSDictionary
|
||||
try assertEquals(actual: map.count, expected: 3)
|
||||
|
||||
try assertEquals(actual: map.object(forKey: NSNull()) as! NSNumber, expected: NSNumber(value: 42))
|
||||
|
||||
@@ -21,10 +21,10 @@ import Values
|
||||
|
||||
func testVals() throws {
|
||||
print("Values from Swift")
|
||||
let dbl = Values.dbl
|
||||
let flt = Values.flt
|
||||
let int = Values.integer
|
||||
let long = Values.longInt
|
||||
let dbl = ValuesKt.dbl
|
||||
let flt = ValuesKt.flt
|
||||
let int = ValuesKt.integer
|
||||
let long = ValuesKt.longInt
|
||||
|
||||
print(dbl)
|
||||
print(flt)
|
||||
@@ -39,9 +39,9 @@ func testVals() throws {
|
||||
|
||||
func testVars() throws {
|
||||
print("Variables from Swift")
|
||||
var intVar = Values.intVar
|
||||
var strVar = Values.str
|
||||
var strAsId = Values.strAsAny
|
||||
var intVar = ValuesKt.intVar
|
||||
var strVar = ValuesKt.str
|
||||
var strAsId = ValuesKt.strAsAny
|
||||
|
||||
print(intVar)
|
||||
print(strVar)
|
||||
@@ -52,133 +52,133 @@ func testVars() throws {
|
||||
try assertEquals(actual: strAsId as! String, expected: "Kotlin String as Any")
|
||||
|
||||
strAsId = "Swift str"
|
||||
Values.strAsAny = strAsId
|
||||
print(Values.strAsAny)
|
||||
try assertEquals(actual: Values.strAsAny as! String, expected: strAsId as! String)
|
||||
ValuesKt.strAsAny = strAsId
|
||||
print(ValuesKt.strAsAny)
|
||||
try assertEquals(actual: ValuesKt.strAsAny as! String, expected: strAsId as! String)
|
||||
|
||||
// property with custom getter/setter backed by the Kotlin's var
|
||||
var intProp : Int32 {
|
||||
get {
|
||||
return Values.intVar * 2
|
||||
return ValuesKt.intVar * 2
|
||||
}
|
||||
set(value) {
|
||||
Values.intVar = 123 + value
|
||||
ValuesKt.intVar = 123 + value
|
||||
}
|
||||
}
|
||||
intProp += 10
|
||||
intProp += 10
|
||||
print(intProp)
|
||||
print(Values.intVar)
|
||||
try assertEquals(actual: Values.intVar * 2, expected: intProp, "Property backed by var")
|
||||
print(ValuesKt.intVar)
|
||||
try assertEquals(actual: ValuesKt.intVar * 2, expected: intProp, "Property backed by var")
|
||||
}
|
||||
|
||||
func testDoubles() throws {
|
||||
print("Doubles in Swift")
|
||||
let minDouble = Values.minDoubleVal as! Double
|
||||
let maxDouble = Values.maxDoubleVal as! NSNumber
|
||||
let minDouble = ValuesKt.minDoubleVal as! Double
|
||||
let maxDouble = ValuesKt.maxDoubleVal as! NSNumber
|
||||
|
||||
print(minDouble)
|
||||
print(maxDouble)
|
||||
print(Values.nanDoubleVal)
|
||||
print(Values.nanFloatVal)
|
||||
print(Values.infDoubleVal)
|
||||
print(Values.infFloatVal)
|
||||
print(ValuesKt.nanDoubleVal)
|
||||
print(ValuesKt.nanFloatVal)
|
||||
print(ValuesKt.infDoubleVal)
|
||||
print(ValuesKt.infFloatVal)
|
||||
|
||||
try assertEquals(actual: minDouble, expected: Double.leastNonzeroMagnitude, "Min double")
|
||||
try assertEquals(actual: maxDouble, expected: Double.greatestFiniteMagnitude as NSNumber, "Max double")
|
||||
try assertTrue(Values.nanDoubleVal.isNaN, "NaN double")
|
||||
try assertTrue(Values.nanFloatVal.isNaN, "NaN float")
|
||||
try assertEquals(actual: Values.infDoubleVal, expected: Double.infinity, "Inf double")
|
||||
try assertEquals(actual: Values.infFloatVal, expected: -Float.infinity, "-Inf float")
|
||||
try assertTrue(ValuesKt.nanDoubleVal.isNaN, "NaN double")
|
||||
try assertTrue(ValuesKt.nanFloatVal.isNaN, "NaN float")
|
||||
try assertEquals(actual: ValuesKt.infDoubleVal, expected: Double.infinity, "Inf double")
|
||||
try assertEquals(actual: ValuesKt.infFloatVal, expected: -Float.infinity, "-Inf float")
|
||||
}
|
||||
|
||||
func testNumbers() throws {
|
||||
try assertEquals(actual: ValuesBoolean(value: true).boolValue, expected: true)
|
||||
try assertEquals(actual: ValuesBoolean(value: false).intValue, expected: 0)
|
||||
try assertEquals(actual: ValuesBoolean(value: true), expected: true)
|
||||
try assertFalse(ValuesBoolean(value: false) as! Bool)
|
||||
try assertEquals(actual: KotlinBoolean(value: true).boolValue, expected: true)
|
||||
try assertEquals(actual: KotlinBoolean(value: false).intValue, expected: 0)
|
||||
try assertEquals(actual: KotlinBoolean(value: true), expected: true)
|
||||
try assertFalse(KotlinBoolean(value: false) as! Bool)
|
||||
|
||||
try assertEquals(actual: ValuesByte(value: -1).int8Value, expected: -1)
|
||||
try assertEquals(actual: ValuesByte(value: -1).int32Value, expected: -1)
|
||||
try assertEquals(actual: ValuesByte(value: -1).doubleValue, expected: -1.0)
|
||||
try assertEquals(actual: ValuesByte(value: -1), expected: NSNumber(value: Int64(-1)))
|
||||
try assertFalse(ValuesByte(value: -1) == NSNumber(value: -1.5))
|
||||
try assertEquals(actual: ValuesByte(value: -1), expected: -1)
|
||||
try assertTrue(ValuesByte(value: -1) == -1)
|
||||
try assertFalse(ValuesByte(value: -1) == 1)
|
||||
try assertEquals(actual: ValuesByte(value: -1) as! Int32, expected: -1)
|
||||
try assertEquals(actual: KotlinByte(value: -1).int8Value, expected: -1)
|
||||
try assertEquals(actual: KotlinByte(value: -1).int32Value, expected: -1)
|
||||
try assertEquals(actual: KotlinByte(value: -1).doubleValue, expected: -1.0)
|
||||
try assertEquals(actual: KotlinByte(value: -1), expected: NSNumber(value: Int64(-1)))
|
||||
try assertFalse(KotlinByte(value: -1) == NSNumber(value: -1.5))
|
||||
try assertEquals(actual: KotlinByte(value: -1), expected: -1)
|
||||
try assertTrue(KotlinByte(value: -1) == -1)
|
||||
try assertFalse(KotlinByte(value: -1) == 1)
|
||||
try assertEquals(actual: KotlinByte(value: -1) as! Int32, expected: -1)
|
||||
|
||||
try assertEquals(actual: ValuesShort(value: 111).int16Value, expected: 111)
|
||||
try assertEquals(actual: ValuesShort(value: -15) as! Int16, expected: -15)
|
||||
try assertEquals(actual: ValuesShort(value: 47), expected: 47)
|
||||
try assertEquals(actual: KotlinShort(value: 111).int16Value, expected: 111)
|
||||
try assertEquals(actual: KotlinShort(value: -15) as! Int16, expected: -15)
|
||||
try assertEquals(actual: KotlinShort(value: 47), expected: 47)
|
||||
|
||||
try assertEquals(actual: ValuesInt(value: 99).int32Value, expected: 99)
|
||||
try assertEquals(actual: ValuesInt(value: -1) as! Int32, expected: -1)
|
||||
try assertEquals(actual: ValuesInt(value: 72), expected: 72)
|
||||
try assertEquals(actual: KotlinInt(value: 99).int32Value, expected: 99)
|
||||
try assertEquals(actual: KotlinInt(value: -1) as! Int32, expected: -1)
|
||||
try assertEquals(actual: KotlinInt(value: 72), expected: 72)
|
||||
|
||||
try assertEquals(actual: ValuesLong(value: 65).int64Value, expected: 65)
|
||||
try assertEquals(actual: ValuesLong(value: 10000000000) as! Int64, expected: 10000000000)
|
||||
try assertEquals(actual: ValuesLong(value: 8), expected: 8)
|
||||
try assertEquals(actual: KotlinLong(value: 65).int64Value, expected: 65)
|
||||
try assertEquals(actual: KotlinLong(value: 10000000000) as! Int64, expected: 10000000000)
|
||||
try assertEquals(actual: KotlinLong(value: 8), expected: 8)
|
||||
|
||||
try assertEquals(actual: ValuesUByte(value: 17).uint8Value, expected: 17)
|
||||
try assertEquals(actual: ValuesUByte(value: 42) as! UInt8, expected: 42)
|
||||
try assertEquals(actual: 88, expected: ValuesUByte(value: 88))
|
||||
try assertEquals(actual: KotlinUByte(value: 17).uint8Value, expected: 17)
|
||||
try assertEquals(actual: KotlinUByte(value: 42) as! UInt8, expected: 42)
|
||||
try assertEquals(actual: 88, expected: KotlinUByte(value: 88))
|
||||
|
||||
try assertEquals(actual: ValuesUShort(value: 40000).uint16Value, expected: 40000)
|
||||
try assertEquals(actual: ValuesUShort(value: 1) as! UInt16, expected: UInt16(1))
|
||||
try assertEquals(actual: ValuesUShort(value: 65000), expected: 65000)
|
||||
try assertEquals(actual: KotlinUShort(value: 40000).uint16Value, expected: 40000)
|
||||
try assertEquals(actual: KotlinUShort(value: 1) as! UInt16, expected: UInt16(1))
|
||||
try assertEquals(actual: KotlinUShort(value: 65000), expected: 65000)
|
||||
|
||||
try assertEquals(actual: ValuesUInt(value: 3).uint32Value, expected: 3)
|
||||
try assertEquals(actual: ValuesUInt(value: UInt32.max) as! UInt32, expected: UInt32.max)
|
||||
try assertEquals(actual: ValuesUInt(value: 2), expected: 2)
|
||||
try assertEquals(actual: KotlinUInt(value: 3).uint32Value, expected: 3)
|
||||
try assertEquals(actual: KotlinUInt(value: UInt32.max) as! UInt32, expected: UInt32.max)
|
||||
try assertEquals(actual: KotlinUInt(value: 2), expected: 2)
|
||||
|
||||
try assertEquals(actual: ValuesULong(value: 55).uint64Value, expected: 55)
|
||||
try assertEquals(actual: ValuesULong(value: 0) as! UInt64, expected: 0)
|
||||
try assertEquals(actual: ValuesULong(value: 7), expected: 7)
|
||||
try assertEquals(actual: KotlinULong(value: 55).uint64Value, expected: 55)
|
||||
try assertEquals(actual: KotlinULong(value: 0) as! UInt64, expected: 0)
|
||||
try assertEquals(actual: KotlinULong(value: 7), expected: 7)
|
||||
|
||||
try assertEquals(actual: ValuesFloat(value: 1.0).floatValue, expected: 1.0)
|
||||
try assertEquals(actual: ValuesFloat(value: 22.0) as! Float, expected: 22)
|
||||
try assertEquals(actual: ValuesFloat(value: 41.0), expected: 41)
|
||||
try assertEquals(actual: ValuesFloat(value: -5.5), expected: -5.5)
|
||||
try assertEquals(actual: KotlinFloat(value: 1.0).floatValue, expected: 1.0)
|
||||
try assertEquals(actual: KotlinFloat(value: 22.0) as! Float, expected: 22)
|
||||
try assertEquals(actual: KotlinFloat(value: 41.0), expected: 41)
|
||||
try assertEquals(actual: KotlinFloat(value: -5.5), expected: -5.5)
|
||||
|
||||
try assertEquals(actual: ValuesDouble(value: 0.5).doubleValue, expected: 0.5)
|
||||
try assertEquals(actual: ValuesDouble(value: 45.0) as! Double, expected: 45)
|
||||
try assertEquals(actual: ValuesDouble(value: 89.0), expected: 89)
|
||||
try assertEquals(actual: ValuesDouble(value: -3.7), expected: -3.7)
|
||||
try assertEquals(actual: KotlinDouble(value: 0.5).doubleValue, expected: 0.5)
|
||||
try assertEquals(actual: KotlinDouble(value: 45.0) as! Double, expected: 45)
|
||||
try assertEquals(actual: KotlinDouble(value: 89.0), expected: 89)
|
||||
try assertEquals(actual: KotlinDouble(value: -3.7), expected: -3.7)
|
||||
|
||||
Values.ensureEqualBooleans(actual: ValuesBoolean(value: true), expected: true)
|
||||
Values.ensureEqualBooleans(actual: false, expected: false)
|
||||
ValuesKt.ensureEqualBooleans(actual: KotlinBoolean(value: true), expected: true)
|
||||
ValuesKt.ensureEqualBooleans(actual: false, expected: false)
|
||||
|
||||
Values.ensureEqualBytes(actual: ValuesByte(value: 42), expected: 42)
|
||||
Values.ensureEqualBytes(actual: -11, expected: -11)
|
||||
ValuesKt.ensureEqualBytes(actual: KotlinByte(value: 42), expected: 42)
|
||||
ValuesKt.ensureEqualBytes(actual: -11, expected: -11)
|
||||
|
||||
Values.ensureEqualShorts(actual: ValuesShort(value: 256), expected: 256)
|
||||
Values.ensureEqualShorts(actual: -1, expected: -1)
|
||||
ValuesKt.ensureEqualShorts(actual: KotlinShort(value: 256), expected: 256)
|
||||
ValuesKt.ensureEqualShorts(actual: -1, expected: -1)
|
||||
|
||||
Values.ensureEqualInts(actual: ValuesInt(value: 100000), expected: 100000)
|
||||
Values.ensureEqualInts(actual: -7, expected: -7)
|
||||
ValuesKt.ensureEqualInts(actual: KotlinInt(value: 100000), expected: 100000)
|
||||
ValuesKt.ensureEqualInts(actual: -7, expected: -7)
|
||||
|
||||
Values.ensureEqualLongs(actual: ValuesLong(value: Int64.max), expected: Int64.max)
|
||||
Values.ensureEqualLongs(actual: 17, expected: 17)
|
||||
ValuesKt.ensureEqualLongs(actual: KotlinLong(value: Int64.max), expected: Int64.max)
|
||||
ValuesKt.ensureEqualLongs(actual: 17, expected: 17)
|
||||
|
||||
Values.ensureEqualUBytes(actual: ValuesUByte(value: 6), expected: 6)
|
||||
Values.ensureEqualUBytes(actual: 255, expected: 255)
|
||||
ValuesKt.ensureEqualUBytes(actual: KotlinUByte(value: 6), expected: 6)
|
||||
ValuesKt.ensureEqualUBytes(actual: 255, expected: 255)
|
||||
|
||||
Values.ensureEqualUShorts(actual: ValuesUShort(value: 300), expected: 300)
|
||||
Values.ensureEqualUShorts(actual: 65535, expected: UInt16.max)
|
||||
ValuesKt.ensureEqualUShorts(actual: KotlinUShort(value: 300), expected: 300)
|
||||
ValuesKt.ensureEqualUShorts(actual: 65535, expected: UInt16.max)
|
||||
|
||||
Values.ensureEqualUInts(actual: ValuesUInt(value: 70000), expected: 70000)
|
||||
Values.ensureEqualUInts(actual: 48, expected: 48)
|
||||
ValuesKt.ensureEqualUInts(actual: KotlinUInt(value: 70000), expected: 70000)
|
||||
ValuesKt.ensureEqualUInts(actual: 48, expected: 48)
|
||||
|
||||
Values.ensureEqualULongs(actual: ValuesULong(value: UInt64.max), expected: UInt64.max)
|
||||
Values.ensureEqualULongs(actual: 39, expected: 39)
|
||||
ValuesKt.ensureEqualULongs(actual: KotlinULong(value: UInt64.max), expected: UInt64.max)
|
||||
ValuesKt.ensureEqualULongs(actual: 39, expected: 39)
|
||||
|
||||
Values.ensureEqualFloats(actual: ValuesFloat(value: 36.6), expected: 36.6)
|
||||
Values.ensureEqualFloats(actual: 49.5, expected: 49.5)
|
||||
Values.ensureEqualFloats(actual: 18, expected: 18.0)
|
||||
ValuesKt.ensureEqualFloats(actual: KotlinFloat(value: 36.6), expected: 36.6)
|
||||
ValuesKt.ensureEqualFloats(actual: 49.5, expected: 49.5)
|
||||
ValuesKt.ensureEqualFloats(actual: 18, expected: 18.0)
|
||||
|
||||
Values.ensureEqualDoubles(actual: ValuesDouble(value: 12.34), expected: 12.34)
|
||||
Values.ensureEqualDoubles(actual: 56.78, expected: 56.78)
|
||||
Values.ensureEqualDoubles(actual: 3, expected: 3)
|
||||
ValuesKt.ensureEqualDoubles(actual: KotlinDouble(value: 12.34), expected: 12.34)
|
||||
ValuesKt.ensureEqualDoubles(actual: 56.78, expected: 56.78)
|
||||
ValuesKt.ensureEqualDoubles(actual: 3, expected: 3)
|
||||
|
||||
func checkBox<T: Equatable, B : NSObject>(_ value: T, _ boxFunction: (T) -> B?) throws {
|
||||
let box = boxFunction(value)!
|
||||
@@ -188,27 +188,27 @@ func testNumbers() throws {
|
||||
try assertTrue(box.isKind(of: B.self))
|
||||
}
|
||||
|
||||
try checkBox(true, Values.box)
|
||||
try checkBox(Int8(-1), Values.box)
|
||||
try checkBox(Int16(-2), Values.box)
|
||||
try checkBox(Int32(-3), Values.box)
|
||||
try checkBox(Int64(-4), Values.box)
|
||||
try checkBox(UInt8(5), Values.box)
|
||||
try checkBox(UInt16(6), Values.box)
|
||||
try checkBox(UInt32(7), Values.box)
|
||||
try checkBox(UInt64(8), Values.box)
|
||||
try checkBox(Float(8.7), Values.box)
|
||||
try checkBox(Double(9.4), Values.box)
|
||||
try checkBox(true, ValuesKt.box)
|
||||
try checkBox(Int8(-1), ValuesKt.box)
|
||||
try checkBox(Int16(-2), ValuesKt.box)
|
||||
try checkBox(Int32(-3), ValuesKt.box)
|
||||
try checkBox(Int64(-4), ValuesKt.box)
|
||||
try checkBox(UInt8(5), ValuesKt.box)
|
||||
try checkBox(UInt16(6), ValuesKt.box)
|
||||
try checkBox(UInt32(7), ValuesKt.box)
|
||||
try checkBox(UInt64(8), ValuesKt.box)
|
||||
try checkBox(Float(8.7), ValuesKt.box)
|
||||
try checkBox(Double(9.4), ValuesKt.box)
|
||||
}
|
||||
|
||||
func testLists() throws {
|
||||
let numbersList = Values.numbersList
|
||||
let numbersList = ValuesKt.numbersList
|
||||
let gold = [1, 2, 13]
|
||||
for i in 0..<gold.count {
|
||||
try assertEquals(actual: gold[i], expected: Int(numbersList[i] as! NSNumber), "Numbers list")
|
||||
}
|
||||
|
||||
let anyList = Values.anyList
|
||||
let anyList = ValuesKt.anyList
|
||||
for i in anyList {
|
||||
print(i)
|
||||
}
|
||||
@@ -216,7 +216,7 @@ func testLists() throws {
|
||||
}
|
||||
|
||||
func testLazyVal() throws {
|
||||
let lazyVal = Values.lazyVal
|
||||
let lazyVal = ValuesKt.lazyVal
|
||||
print(lazyVal)
|
||||
try assertEquals(actual: lazyVal, expected: "Lazily initialized string", "lazy value")
|
||||
}
|
||||
@@ -224,7 +224,7 @@ func testLazyVal() throws {
|
||||
let goldenArray = ["Delegated", "global", "array", "property"]
|
||||
|
||||
func testDelegatedProp() throws {
|
||||
let delegatedGlobalArray = Values.delegatedGlobalArray
|
||||
let delegatedGlobalArray = ValuesKt.delegatedGlobalArray
|
||||
guard Int(delegatedGlobalArray.size) == goldenArray.count else {
|
||||
throw TestError.assertFailed("Size differs")
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func testDelegatedProp() throws {
|
||||
}
|
||||
|
||||
func testGetterDelegate() throws {
|
||||
let delegatedList = Values.delegatedList
|
||||
let delegatedList = ValuesKt.delegatedList
|
||||
guard delegatedList.count == goldenArray.count else {
|
||||
throw TestError.assertFailed("Size differs")
|
||||
}
|
||||
@@ -244,16 +244,16 @@ func testGetterDelegate() throws {
|
||||
}
|
||||
|
||||
func testNulls() throws {
|
||||
let nilVal : Any? = Values.nullVal
|
||||
let nilVal : Any? = ValuesKt.nullVal
|
||||
try assertTrue(nilVal == nil, "Null value")
|
||||
|
||||
Values.nullVar = nil
|
||||
var nilVar : Any? = Values.nullVar
|
||||
ValuesKt.nullVar = nil
|
||||
var nilVar : Any? = ValuesKt.nullVar
|
||||
try assertTrue(nilVar == nil, "Null variable")
|
||||
}
|
||||
|
||||
func testAnyVar() throws {
|
||||
let anyVar : Any = Values.anyValue
|
||||
let anyVar : Any = ValuesKt.anyValue
|
||||
print(anyVar)
|
||||
if let str = anyVar as? String {
|
||||
print(str)
|
||||
@@ -264,19 +264,19 @@ func testAnyVar() throws {
|
||||
}
|
||||
|
||||
func testFunctions() throws {
|
||||
let _: Any? = Values.emptyFun()
|
||||
let _: Any? = ValuesKt.emptyFun()
|
||||
|
||||
let str = Values.strFun()
|
||||
let str = ValuesKt.strFun()
|
||||
try assertEquals(actual: str, expected: "fooStr")
|
||||
|
||||
try assertEquals(actual: Values.argsFun(i: 10, l: 20, d: 3.5, s: "res") as! String,
|
||||
try assertEquals(actual: ValuesKt.argsFun(i: 10, l: 20, d: 3.5, s: "res") as! String,
|
||||
expected: "res10203.5")
|
||||
}
|
||||
|
||||
func testFuncType() throws {
|
||||
let s = "str"
|
||||
let fFunc: () -> String = { return s }
|
||||
try assertEquals(actual: Values.funArgument(foo: fFunc), expected: s, "Using function type arguments failed")
|
||||
try assertEquals(actual: ValuesKt.funArgument(foo: fFunc), expected: s, "Using function type arguments failed")
|
||||
}
|
||||
|
||||
func testGenericsFoo() throws {
|
||||
@@ -284,48 +284,48 @@ func testGenericsFoo() throws {
|
||||
// wrap lambda to workaround issue with type conversion inability:
|
||||
// (Int) -> String can't be cast to (Any?) -> Any?
|
||||
let wrapper = { (t: Any?) -> Any? in return fun(t as! Int) }
|
||||
let res = Values.genericFoo(t: 42, foo: wrapper)
|
||||
let res = ValuesKt.genericFoo(t: 42, foo: wrapper)
|
||||
try assertEquals(actual: res as! String, expected: "S 42")
|
||||
}
|
||||
|
||||
func testVararg() throws {
|
||||
let ktArray = ValuesStdlibArray(size: 3, init: { (_) -> Int in return 42 })
|
||||
let arr: [Int] = Values.varargToList(args: ktArray) as! [Int]
|
||||
let ktArray = KotlinArray(size: 3, init: { (_) -> Int in return 42 })
|
||||
let arr: [Int] = ValuesKt.varargToList(args: ktArray) as! [Int]
|
||||
try assertEquals(actual: arr, expected: [42, 42, 42])
|
||||
}
|
||||
|
||||
func testStrExtFun() throws {
|
||||
try assertEquals(actual: Values.subExt("String", i: 2), expected: "r")
|
||||
try assertEquals(actual: Values.subExt("A", i: 2), expected: "nothing")
|
||||
try assertEquals(actual: ValuesKt.subExt("String", i: 2), expected: "r")
|
||||
try assertEquals(actual: ValuesKt.subExt("A", i: 2), expected: "nothing")
|
||||
}
|
||||
|
||||
func testAnyToString() throws {
|
||||
try assertEquals(actual: Values.toString(nil), expected: "null")
|
||||
try assertEquals(actual: Values.toString(42), expected: "42")
|
||||
try assertEquals(actual: ValuesKt.toString(nil), expected: "null")
|
||||
try assertEquals(actual: ValuesKt.toString(42), expected: "42")
|
||||
}
|
||||
|
||||
func testAnyPrint() throws {
|
||||
print("BEGIN")
|
||||
Values.print(nil)
|
||||
Values.print("Print")
|
||||
Values.print(123456789)
|
||||
Values.print(3.14)
|
||||
Values.print([3, 2, 1])
|
||||
ValuesKt.print(nil)
|
||||
ValuesKt.print("Print")
|
||||
ValuesKt.print(123456789)
|
||||
ValuesKt.print(3.14)
|
||||
ValuesKt.print([3, 2, 1])
|
||||
print("END")
|
||||
}
|
||||
|
||||
func testLambda() throws {
|
||||
try assertEquals(actual: Values.sumLambda(3, 4), expected: 7)
|
||||
try assertEquals(actual: ValuesKt.sumLambda(3, 4), expected: 7)
|
||||
}
|
||||
|
||||
// -------- Tests for classes and interfaces -------
|
||||
class ValIEmptyExt : ValuesI {
|
||||
class ValIEmptyExt : I {
|
||||
func iFun() -> String {
|
||||
return "ValIEmptyExt::iFun"
|
||||
}
|
||||
}
|
||||
|
||||
class ValIExt : ValuesI {
|
||||
class ValIExt : I {
|
||||
func iFun() -> String {
|
||||
return "ValIExt::iFun"
|
||||
}
|
||||
@@ -337,19 +337,19 @@ func testInterfaceExtension() throws {
|
||||
}
|
||||
|
||||
func testClassInstances() throws {
|
||||
try assertEquals(actual: ValuesOpenClassI().iFun(), expected: "OpenClassI::iFun")
|
||||
try assertEquals(actual: ValuesDefaultInterfaceExt().iFun(), expected: "I::iFun")
|
||||
try assertEquals(actual: ValuesFinalClassExtOpen().iFun(), expected: "FinalClassExtOpen::iFun")
|
||||
try assertEquals(actual: ValuesMultiExtClass().iFun(), expected: "PI::iFun")
|
||||
try assertEquals(actual: ValuesMultiExtClass().piFun() as! Int, expected: 42)
|
||||
try assertEquals(actual: ValuesConstrClass(i: 1, s: "str", a: "Any").iFun(), expected: "OpenClassI::iFun")
|
||||
try assertEquals(actual: ValuesExtConstrClass(i: 123).iFun(), expected: "ExtConstrClass::iFun::123-String-AnyS")
|
||||
try assertEquals(actual: OpenClassI().iFun(), expected: "OpenClassI::iFun")
|
||||
try assertEquals(actual: DefaultInterfaceExt().iFun(), expected: "I::iFun")
|
||||
try assertEquals(actual: FinalClassExtOpen().iFun(), expected: "FinalClassExtOpen::iFun")
|
||||
try assertEquals(actual: MultiExtClass().iFun(), expected: "PI::iFun")
|
||||
try assertEquals(actual: MultiExtClass().piFun() as! Int, expected: 42)
|
||||
try assertEquals(actual: ConstrClass(i: 1, s: "str", a: "Any").iFun(), expected: "OpenClassI::iFun")
|
||||
try assertEquals(actual: ExtConstrClass(i: 123).iFun(), expected: "ExtConstrClass::iFun::123-String-AnyS")
|
||||
}
|
||||
|
||||
func testEnum() throws {
|
||||
try assertEquals(actual: Values.passEnum().enumValue, expected: 42)
|
||||
try assertEquals(actual: Values.passEnum().name, expected: "ANSWER")
|
||||
Values.receiveEnum(e: 1)
|
||||
try assertEquals(actual: ValuesKt.passEnum().enumValue, expected: 42)
|
||||
try assertEquals(actual: ValuesKt.passEnum().name, expected: "ANSWER")
|
||||
ValuesKt.receiveEnum(e: 1)
|
||||
}
|
||||
|
||||
func testDataClass() throws {
|
||||
@@ -357,13 +357,13 @@ func testDataClass() throws {
|
||||
let s = "2"
|
||||
let t = "3"
|
||||
|
||||
let tripleVal = ValuesTripleVals(first: f, second: s, third: t)
|
||||
let tripleVal = TripleVals(first: f, second: s, third: t)
|
||||
try assertEquals(actual: tripleVal.first as! String, expected: f, "Data class' value")
|
||||
try assertEquals(actual: tripleVal.component2() as! String, expected: s, "Data class' component")
|
||||
print(tripleVal)
|
||||
try assertEquals(actual: String(describing: tripleVal), expected: "TripleVals(first=\(f), second=\(s), third=\(t))")
|
||||
|
||||
let tripleVar = ValuesTripleVars(first: f, second: s, third: t)
|
||||
let tripleVar = TripleVars(first: f, second: s, third: t)
|
||||
try assertEquals(actual: tripleVar.first as! String, expected: f, "Data class' value")
|
||||
try assertEquals(actual: tripleVar.component2() as! String, expected: s, "Data class' component")
|
||||
print(tripleVar)
|
||||
@@ -377,31 +377,31 @@ func testDataClass() throws {
|
||||
}
|
||||
|
||||
func testCompanionObj() throws {
|
||||
try assertEquals(actual: ValuesWithCompanionAndObjectCompanion().str, expected: "String")
|
||||
try assertEquals(actual: Values.getCompanionObject().str, expected: "String")
|
||||
try assertEquals(actual: WithCompanionAndObjectCompanion().str, expected: "String")
|
||||
try assertEquals(actual: ValuesKt.getCompanionObject().str, expected: "String")
|
||||
|
||||
let namedFromCompanion = Values.getCompanionObject().named
|
||||
let named = Values.getNamedObject()
|
||||
let namedFromCompanion = ValuesKt.getCompanionObject().named
|
||||
let named = ValuesKt.getNamedObject()
|
||||
try assertTrue(named === namedFromCompanion, "Should be the same Named object")
|
||||
|
||||
try assertEquals(actual: Values.getNamedObjectInterface().iFun(), expected: named.iFun(), "Named object's method")
|
||||
try assertEquals(actual: ValuesKt.getNamedObjectInterface().iFun(), expected: named.iFun(), "Named object's method")
|
||||
}
|
||||
|
||||
func testInlineClasses() throws {
|
||||
let ic1: Int32 = 42
|
||||
let ic1N = Values.box(ic1: 17)
|
||||
let ic1N = ValuesKt.box(ic1: 17)
|
||||
let ic2 = "foo"
|
||||
let ic2N = "bar"
|
||||
let ic3 = ValuesTripleVals(first: 1, second: 2, third: 3)
|
||||
let ic3N = Values.box(ic3: nil)
|
||||
let ic3 = TripleVals(first: 1, second: 2, third: 3)
|
||||
let ic3N = ValuesKt.box(ic3: nil)
|
||||
|
||||
try assertEquals(
|
||||
actual: Values.concatenateInlineClassValues(ic1: ic1, ic1N: ic1N, ic2: ic2, ic2N: ic2N, ic3: ic3, ic3N: ic3N),
|
||||
actual: ValuesKt.concatenateInlineClassValues(ic1: ic1, ic1N: ic1N, ic2: ic2, ic2N: ic2N, ic3: ic3, ic3N: ic3N),
|
||||
expected: "42 17 foo bar TripleVals(first=1, second=2, third=3) null"
|
||||
)
|
||||
|
||||
try assertEquals(
|
||||
actual: Values.concatenateInlineClassValues(ic1: ic1, ic1N: nil, ic2: ic2, ic2N: nil, ic3: nil, ic3N: nil),
|
||||
actual: ValuesKt.concatenateInlineClassValues(ic1: ic1, ic1N: nil, ic2: ic2, ic2N: nil, ic3: nil, ic3N: nil),
|
||||
expected: "42 null foo null null null"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class ViewController: UIViewController, UITextViewDelegate, UICollectionViewData
|
||||
@IBOutlet var input: UITextView!
|
||||
@IBOutlet var numpad: UICollectionView!
|
||||
|
||||
private let parser = KAPPartialParser(composer: KAPCalculator(), partialComposer: PartialRenderer())
|
||||
private let parser = PartialParser(composer: Calculator(), partialComposer: PartialRenderer())
|
||||
|
||||
@IBAction func numpadButtonPressed(_ sender: UIButton) {
|
||||
let title = sender.currentTitle!
|
||||
@@ -112,7 +112,7 @@ private extension String {
|
||||
}
|
||||
}
|
||||
|
||||
private class PartialRenderer: NSObject, KAPPartialExpressionComposer {
|
||||
private class PartialRenderer: NSObject, PartialExpressionComposer {
|
||||
func missing() -> Any {
|
||||
return "... ".toAttributed()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user