Use NSNumber subclasses for Kotlin numbers when producing framework (#1956)

This commit is contained in:
SvyatoslavScherbina
2018-08-29 22:28:41 +03:00
committed by GitHub
parent 838956f4df
commit aac798e5ac
9 changed files with 994 additions and 15 deletions
@@ -20,7 +20,7 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
return load(selectorRef.llvm)
}
fun FunctionGenerationContext.genGetSystemClass(name: String): LLVMValueRef {
fun FunctionGenerationContext.genGetLinkedClass(name: String): LLVMValueRef {
val classRef = dataGenerator.genClassRef(name)
return load(classRef.llvm)
}
@@ -169,6 +169,9 @@ internal class ObjCExportCodeGenerator(
dataGenerator.emitEmptyClass(namer.getPackageName(fqName), namer.kotlinAnyName)
}
NSNumberKind.values().mapNotNull { it.mappedKotlinClassId }.forEach {
dataGenerator.exportClass("Kotlin${it.shortClassName}")
}
dataGenerator.exportClass("KotlinMutableSet")
dataGenerator.exportClass("KotlinMutableDictionary")
@@ -345,7 +348,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverters() {
emitBoxConverter(irBuiltIns.shortClass, ObjCValueType.SHORT, "numberWithShort:")
emitBoxConverter(irBuiltIns.intClass, ObjCValueType.INT, "numberWithInt:")
emitBoxConverter(irBuiltIns.longClass, ObjCValueType.LONG_LONG, "numberWithLongLong:")
emitBoxConverter(symbols.uByte, ObjCValueType.UNSIGNED_CHAR, "numberWithUnsignedChar")
emitBoxConverter(symbols.uByte, ObjCValueType.UNSIGNED_CHAR, "numberWithUnsignedChar:")
emitBoxConverter(symbols.uShort, ObjCValueType.UNSIGNED_SHORT, "numberWithUnsignedShort:")
emitBoxConverter(symbols.uInt, ObjCValueType.UNSIGNED_INT, "numberWithUnsignedInt:")
emitBoxConverter(symbols.uLong, ObjCValueType.UNSIGNED_LONG_LONG, "numberWithUnsignedLongLong:")
@@ -371,8 +374,8 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(
val value = kotlinToObjC(kotlinValue, objCValueType)
val nsNumber = genGetSystemClass("NSNumber")
ret(genSendMessage(int8TypePtr, nsNumber, nsNumberFactorySelector, value))
val nsNumberSubclass = genGetLinkedClass("Kotlin${boxClass.name}")
ret(genSendMessage(int8TypePtr, nsNumberSubclass, nsNumberFactorySelector, value))
}
LLVMSetLinkage(converter, LLVMLinkage.LLVMPrivateLinkage)
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
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
@@ -44,6 +45,16 @@ abstract class ObjCExportHeaderGenerator(
internal val generatedClasses = mutableSetOf<ClassDescriptor>()
internal val topLevel = mutableMapOf<FqName, MutableList<CallableMemberDescriptor>>()
private val mappedToNSNumber: List<ClassDescriptor> = with(builtIns) {
val result = mutableListOf(boolean, byte, short, int, long, float, double)
UnsignedType.values().mapTo(result) { unsignedType ->
moduleDescriptor.findClassAcrossModuleDependencies(unsignedType.classId)!!
}
result
}
private val customTypeMappers: Map<ClassDescriptor, CustomTypeMapper> = with(builtIns) {
val result = mutableListOf<CustomTypeMapper>()
@@ -56,16 +67,13 @@ abstract class ObjCExportHeaderGenerator(
result += CustomTypeMapper.Collection(generator, map, "NSDictionary")
result += CustomTypeMapper.Collection(generator, mutableMap, namer.mutableMapName)
for (descriptor in listOf(boolean, byte, short, int, long, float, double)) {
// TODO: Kotlin code doesn't have any checkcasts on unboxing,
// so it is possible that it expects boxed number of other type and unboxes it incorrectly.
NSNumberKind.values().forEach {
// TODO: NSNumber seem to have different equality semantics.
result += CustomTypeMapper.Simple(descriptor, "NSNumber")
}
if (it.mappedKotlinClassId != null) {
val descriptor = moduleDescriptor.findClassAcrossModuleDependencies(it.mappedKotlinClassId)!!
result += CustomTypeMapper.Simple(descriptor, namer.numberBoxName(descriptor))
}
for (unsignedType in UnsignedType.values()) {
val descriptor = moduleDescriptor.findClassAcrossModuleDependencies(unsignedType.classId)!!
result += CustomTypeMapper.Simple(descriptor, "NSNumber")
}
result += CustomTypeMapper.Simple(string, "NSString")
@@ -121,7 +129,7 @@ abstract class ObjCExportHeaderGenerator(
namer.mutableSetName,
generics = listOf("ObjectType"),
superClass = "NSMutableSet<ObjectType>",
attributes = listOf("objc_runtime_name(\"KotlinMutableSet\")")
attributes = listOf(objcRuntimeNameAttribute("KotlinMutableSet"))
))
// TODO: only if appears
@@ -129,13 +137,15 @@ abstract class ObjCExportHeaderGenerator(
namer.mutableMapName,
generics = listOf("KeyType", "ObjectType"),
superClass = "NSMutableDictionary<KeyType, ObjectType>",
attributes = listOf("objc_runtime_name(\"KotlinMutableDictionary\")")
attributes = listOf(objcRuntimeNameAttribute("KotlinMutableDictionary"))
))
stubs.add(ObjCInterface("NSError", categoryName = "NSErrorKotlinException", members = buildMembers {
+ObjCProperty("kotlinException", null, ObjCNullableReferenceType(ObjCIdType), listOf("readonly"))
}))
genKotlinNumbers()
val packageFragments = moduleDescriptor.getPackageFragments()
packageFragments.forEach { packageFragment ->
@@ -195,6 +205,67 @@ abstract class ObjCExportHeaderGenerator(
return stubs
}
private fun genKotlinNumbers() {
val members = buildMembers {
NSNumberKind.values().forEach {
+nsNumberFactory(it, listOf("unavailable"))
}
NSNumberKind.values().forEach {
+nsNumberInit(it, listOf("unavailable"))
}
}
stubs.add(ObjCInterface(
namer.kotlinNumberName,
superClass = "NSNumber",
members = members,
attributes = listOf(objcRuntimeNameAttribute("KotlinNumber"))
))
NSNumberKind.values().forEach {
if (it.mappedKotlinClassId != null) {
stubs += genKotlinNumber(it.mappedKotlinClassId, it)
}
}
}
private fun genKotlinNumber(kotlinClassId: ClassId, kind: NSNumberKind): ObjCInterface {
val descriptor = moduleDescriptor.findClassAcrossModuleDependencies(kotlinClassId)!!
val name = namer.numberBoxName(descriptor)
val members = buildMembers {
+nsNumberFactory(kind)
+nsNumberInit(kind)
}
return ObjCInterface(
name,
superClass = namer.kotlinNumberName,
members = members,
attributes = listOf(objcRuntimeNameAttribute("Kotlin${kotlinClassId.shortClassName}"))
)
}
private fun nsNumberInit(kind: NSNumberKind, attributes: List<String> = emptyList()): ObjCMethod {
return ObjCMethod(
null,
false,
ObjCInstanceType,
listOf(kind.factorySelector),
listOf(ObjCParameter("value", null, kind.objCType)),
attributes
)
}
private fun nsNumberFactory(kind: NSNumberKind, attributes: List<String> = emptyList()): ObjCMethod {
return ObjCMethod(
null,
true,
ObjCInstanceType,
listOf(kind.initSelector),
listOf(ObjCParameter("value", null, kind.objCType)),
attributes
)
}
private fun translateClassName(descriptor: ClassDescriptor): String = classOrInterfaceToName.getOrPut(descriptor) {
assert(mapper.shouldBeExposed(descriptor))
val forwardDeclarations = if (descriptor.isInterface) protocolForwardDeclarations else classForwardDeclarations
@@ -549,6 +620,7 @@ abstract class ObjCExportHeaderGenerator(
}
private fun swiftNameAttribute(swiftName: String) = "swift_name(\"$swiftName\")"
private fun objcRuntimeNameAttribute(name: String) = "objc_runtime_name(\"$name\")"
private val methodsWithThrowAnnotationConsidered = mutableSetOf<FunctionDescriptor>()
@@ -12,8 +12,11 @@ import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
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.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -215,3 +218,49 @@ internal fun ObjCExportMapper.bridgePropertyType(descriptor: PropertyDescriptor)
return bridgeType(descriptor.type)
}
internal enum class NSNumberKind(val mappedKotlinClassId: ClassId?, val objCType: ObjCType) {
CHAR(PrimitiveType.BYTE, "char"),
UNSIGNED_CHAR(UnsignedType.UBYTE, "unsigned char"),
SHORT(PrimitiveType.SHORT, "short"),
UNSIGNED_SHORT(UnsignedType.USHORT, "unsigned short"),
INT(PrimitiveType.INT, "int"),
UNSIGNED_INT(UnsignedType.UINT, "unsigned int"),
LONG("long"),
UNSIGNED_LONG("unsigned long"),
LONG_LONG(PrimitiveType.LONG, "long long"),
UNSIGNED_LONG_LONG(UnsignedType.ULONG, "unsigned long long"),
FLOAT(PrimitiveType.FLOAT, "float"),
DOUBLE(PrimitiveType.DOUBLE, "double"),
BOOL(PrimitiveType.BOOLEAN, "BOOL"),
INTEGER("NSInteger"),
UNSIGNED_INTEGER("NSUInteger")
;
// UNSIGNED_SHORT -> unsignedShort
private val kindName = this.name.split('_')
.joinToString("") { it.toLowerCase().capitalize() }.decapitalize()
val valueSelector = kindName // unsignedShort
val initSelector = "initWith${kindName.capitalize()}:" // initWithUnsignedShort:
val factorySelector = "numberWith${kindName.capitalize()}:" // numberWithUnsignedShort:
constructor(
mappedKotlinClassId: ClassId?,
objCPrimitiveTypeName: String
) : this(mappedKotlinClassId, ObjCPrimitiveType(objCPrimitiveTypeName))
constructor(
primitiveType: PrimitiveType,
objCPrimitiveTypeName: String
) : this(ClassId.topLevel(primitiveType.typeFqName), objCPrimitiveTypeName)
constructor(
unsignedType: UnsignedType,
objCPrimitiveTypeName: String
) : this(unsignedType.classId, objCPrimitiveTypeName)
constructor(objCPrimitiveTypeName: String) : this(null, ObjCPrimitiveType(objCPrimitiveTypeName))
}
@@ -29,6 +29,9 @@ internal class ObjCExportNamer(val moduleDescriptor: ModuleDescriptor,
val mutableSetName = "${topLevelNamePrefix}MutableSet"
val mutableMapName = "${topLevelNamePrefix}MutableDictionary"
fun numberBoxName(descriptor: ClassDescriptor): String = "$topLevelNamePrefix${descriptor.name.asString()}"
val kotlinNumberName = "${topLevelNamePrefix}Number"
private val methodSelectors = object : Mapping<FunctionDescriptor, String>() {
// Try to avoid clashing with critical NSObject instance methods:
@@ -134,7 +134,7 @@ class StdlibTests : TestProvider {
print("MAP: \(k) - \(v)")
}
var smd = StdlibMutableDictionary<NSString, NSNumber>()
var smd = StdlibMutableDictionary<NSString, StdlibInt>()
smd.setObject(333, forKey: "333" as NSString)
try assertEquals(actual: smd.object(forKey: "333" as NSString) as! Int, expected: 333, "Add element to dict")
@@ -32,6 +32,37 @@ val nanFloatVal: Float = Float.NaN
val infDoubleVal: Double = Double.POSITIVE_INFINITY
val infFloatVal: Float = Float.NEGATIVE_INFINITY
private fun <T> T.toNullable(): T? = this
fun box(booleanValue: Boolean) = booleanValue.toNullable()
fun box(byteValue: Byte) = byteValue.toNullable()
fun box(shortValue: Short) = shortValue.toNullable()
fun box(intValue: Int) = intValue.toNullable()
fun box(longValue: Long) = longValue.toNullable()
fun box(uByteValue: UByte) = uByteValue.toNullable()
fun box(uShortValue: UShort) = uShortValue.toNullable()
fun box(uIntValue: UInt) = uIntValue.toNullable()
fun box(uLongValue: ULong) = uLongValue.toNullable()
fun box(floatValue: Float) = floatValue.toNullable()
fun box(doubleValue: Double) = doubleValue.toNullable()
private inline fun <reified T> ensureEquals(actual: T?, expected: T) {
if (actual !is T) error(T::class)
if (actual != expected) error(T::class)
}
fun ensureEqualBooleans(actual: Boolean?, expected: Boolean) = ensureEquals(actual, expected)
fun ensureEqualBytes(actual: Byte?, expected: Byte) = ensureEquals(actual, expected)
fun ensureEqualShorts(actual: Short?, expected: Short) = ensureEquals(actual, expected)
fun ensureEqualInts(actual: Int?, expected: Int) = ensureEquals(actual, expected)
fun ensureEqualLongs(actual: Long?, expected: Long) = ensureEquals(actual, expected)
fun ensureEqualUBytes(actual: UByte?, expected: UByte) = ensureEquals(actual, expected)
fun ensureEqualUShorts(actual: UShort?, expected: UShort) = ensureEquals(actual, expected)
fun ensureEqualUInts(actual: UInt?, expected: UInt) = ensureEquals(actual, expected)
fun ensureEqualULongs(actual: ULong?, expected: ULong) = ensureEquals(actual, expected)
fun ensureEqualFloats(actual: Float?, expected: Float) = ensureEquals(actual, expected)
fun ensureEqualDoubles(actual: Double?, expected: Double) = ensureEquals(actual, expected)
// Boolean
val boolVal: Boolean = true
val boolAnyVal: Any = false
@@ -91,6 +91,116 @@ func testDoubles() throws {
try assertEquals(actual: Values.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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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)
Values.ensureEqualBooleans(actual: ValuesBoolean(value: true), expected: true)
Values.ensureEqualBooleans(actual: false, expected: false)
Values.ensureEqualBytes(actual: ValuesByte(value: 42), expected: 42)
Values.ensureEqualBytes(actual: -11, expected: -11)
Values.ensureEqualShorts(actual: ValuesShort(value: 256), expected: 256)
Values.ensureEqualShorts(actual: -1, expected: -1)
Values.ensureEqualInts(actual: ValuesInt(value: 100000), expected: 100000)
Values.ensureEqualInts(actual: -7, expected: -7)
Values.ensureEqualLongs(actual: ValuesLong(value: Int64.max), expected: Int64.max)
Values.ensureEqualLongs(actual: 17, expected: 17)
Values.ensureEqualUBytes(actual: ValuesUByte(value: 6), expected: 6)
Values.ensureEqualUBytes(actual: 255, expected: 255)
Values.ensureEqualUShorts(actual: ValuesUShort(value: 300), expected: 300)
Values.ensureEqualUShorts(actual: 65535, expected: UInt16.max)
Values.ensureEqualUInts(actual: ValuesUInt(value: 70000), expected: 70000)
Values.ensureEqualUInts(actual: 48, expected: 48)
Values.ensureEqualULongs(actual: ValuesULong(value: UInt64.max), expected: UInt64.max)
Values.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)
Values.ensureEqualDoubles(actual: ValuesDouble(value: 12.34), expected: 12.34)
Values.ensureEqualDoubles(actual: 56.78, expected: 56.78)
Values.ensureEqualDoubles(actual: 3, expected: 3)
func checkBox<T: Equatable, B : NSObject>(_ value: T, _ boxFunction: (T) -> B?) throws {
let box = boxFunction(value)!
try assertEquals(actual: box as! T, expected: value)
print(type(of: box))
print(B.self)
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)
}
func testLists() throws {
let numbersList = Values.numbersList
let gold = [1, 2, 13]
@@ -307,6 +417,7 @@ class ValuesTests : TestProvider {
TestCase(name: "TestValues", method: withAutorelease(testVals)),
TestCase(name: "TestVars", method: withAutorelease(testVars)),
TestCase(name: "TestDoubles", method: withAutorelease(testDoubles)),
TestCase(name: "TestNumbers", method: withAutorelease(testNumbers)),
TestCase(name: "TestLists", method: withAutorelease(testLists)),
TestCase(name: "TestLazyValues", method: withAutorelease(testLazyVal)),
TestCase(name: "TestDelegatedProperties", method: withAutorelease(testDelegatedProp)),
+710
View File
@@ -0,0 +1,710 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if KONAN_OBJC_INTEROP
#import <Foundation/NSDictionary.h>
#import <Foundation/NSError.h>
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
#import "ObjCExport.h"
#import "Runtime.h"
#import "Utils.h"
extern "C" {
OBJ_GETTER(Kotlin_boxBoolean, KBoolean value);
OBJ_GETTER(Kotlin_boxByte, KByte value);
OBJ_GETTER(Kotlin_boxShort, KShort value);
OBJ_GETTER(Kotlin_boxInt, KInt value);
OBJ_GETTER(Kotlin_boxLong, KLong value);
OBJ_GETTER(Kotlin_boxUByte, KUByte value);
OBJ_GETTER(Kotlin_boxUShort, KUShort value);
OBJ_GETTER(Kotlin_boxUInt, KUInt value);
OBJ_GETTER(Kotlin_boxULong, KULong value);
OBJ_GETTER(Kotlin_boxFloat, KFloat value);
OBJ_GETTER(Kotlin_boxDouble, KDouble value);
}
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
@interface KotlinNumber : NSNumber
@end;
[[ noreturn ]] static void incorrectNumberInitialization(KotlinNumber* self, SEL _cmd) {
[NSException raise:NSGenericException format:@"%@ can't be initialized with %s, use properly typed initialized",
NSStringFromClass([self class]), sel_getName(_cmd)];
abort();
}
[[ noreturn ]] static void incorrectNumberFactory(Class self, SEL _cmd) {
[NSException raise:NSGenericException format:@"%@ can't be created with %s, use properly typed factory",
NSStringFromClass(self), sel_getName(_cmd)];
abort();
}
@implementation KotlinNumber : NSNumber
- (NSNumber *)initWithBool:(BOOL)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithChar:(char)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithShort:(short)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithInt:(int)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithInteger:(NSInteger)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithLong:(long)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithLongLong:(long long)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithUnsignedChar:(unsigned char)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithUnsignedShort:(unsigned short)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithUnsignedInt:(unsigned int)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithUnsignedInteger:(NSUInteger)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithUnsignedLong:(unsigned long)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithUnsignedLongLong:(unsigned long long)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithFloat:(float)value { incorrectNumberInitialization(self, _cmd); }
- (NSNumber *)initWithDouble:(double)value { incorrectNumberInitialization(self, _cmd); }
+ (NSNumber *)numberWithBool:(BOOL)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithChar:(char)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithShort:(short)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithInt:(int)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithInteger:(NSInteger)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithLong:(long)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithLongLong:(long long)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithUnsignedChar:(unsigned char)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithUnsignedShort:(unsigned short)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithUnsignedInt:(unsigned int)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithUnsignedLong:(unsigned long)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithFloat:(float)value { incorrectNumberFactory(self, _cmd); }
+ (NSNumber *)numberWithDouble:(double)value { incorrectNumberFactory(self, _cmd); }
@end;
/*
The code below is generated by:
fun main(args: Array<String>) {
println(genBoolean())
println(genInteger("Byte", "c", "char"))
println(genInteger("Short", "s", "short"))
println(genInteger("Int", "i", "int"))
println(genInteger("Long", "q", "long long"))
println(genInteger("UByte", "C", "unsigned char"))
println(genInteger("UShort", "S", "unsigned short"))
println(genInteger("UInt", "I", "unsigned int"))
println(genInteger("ULong", "Q", "unsigned long long"))
println(genFloating("Float", "f", "float"))
println(genFloating("Double", "d", "double"))
}
private fun genBoolean(): String = """
@interface KotlinBoolean : KotlinNumber
@end;
@implementation KotlinBoolean {
BOOL value_;
}
- (instancetype)initWithBool:(BOOL)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithBool:(BOOL)value {
KotlinBoolean* result = [[self new] autorelease];
result->value_ = value;
return result;
}
- (BOOL)boolValue {
return value_;
}
- (char)charValue {
return value_;
}
- (const char *)objCType {
return "c";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxBoolean, value_);
}
@end;
""".trimIndent()
private fun genInteger(
name: String,
encoding: String,
cType: String,
kind: String = getNSNumberKind(cType)
) = """
@interface Kotlin$name : KotlinNumber
@end;
@implementation Kotlin$name {
$cType value_;
}
- (instancetype)initWith${kind.capitalize()}:($cType)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWith${kind.capitalize()}:($cType)value {
Kotlin$name* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- ($cType)${kind}Value {
return value_;
}
- (const char *)objCType {
return "$encoding";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_box$name, value_);
}
@end;
""".trimIndent()
private fun getNSNumberKind(cType: String) =
cType.split(' ').joinToString("") { it.capitalize() }.decapitalize()
private fun genFloating(
name: String,
encoding: String,
cType: String,
kind: String = getNSNumberKind(cType)
): String = """
@interface Kotlin$name : KotlinNumber
@end;
@implementation Kotlin$name {
$cType value_;
}
- (instancetype)initWith${kind.capitalize()}:($cType)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWith${kind.capitalize()}:($cType)value {
Kotlin$name* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
${if (cType != "double") """
// Required to convert Swift floating literals.
- (instancetype)initWithDouble:(double)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
""" else ""}
- ($cType)${kind}Value {
return value_;
}
- (const char *)objCType {
return "$encoding";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_box$name, value_);
}
@end;
""".trimIndent()
*/
// TODO: consider generating it by compiler.
@interface KotlinBoolean : KotlinNumber
@end;
@implementation KotlinBoolean {
BOOL value_;
}
- (instancetype)initWithBool:(BOOL)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithBool:(BOOL)value {
KotlinBoolean* result = [[self new] autorelease];
result->value_ = value;
return result;
}
- (BOOL)boolValue {
return value_;
}
- (char)charValue {
return value_;
}
- (const char *)objCType {
return "c";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxBoolean, value_);
}
@end;
@interface KotlinByte : KotlinNumber
@end;
@implementation KotlinByte {
char value_;
}
- (instancetype)initWithChar:(char)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithChar:(char)value {
KotlinByte* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (char)charValue {
return value_;
}
- (const char *)objCType {
return "c";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxByte, value_);
}
@end;
@interface KotlinShort : KotlinNumber
@end;
@implementation KotlinShort {
short value_;
}
- (instancetype)initWithShort:(short)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithShort:(short)value {
KotlinShort* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (short)shortValue {
return value_;
}
- (const char *)objCType {
return "s";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxShort, value_);
}
@end;
@interface KotlinInt : KotlinNumber
@end;
@implementation KotlinInt {
int value_;
}
- (instancetype)initWithInt:(int)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithInt:(int)value {
KotlinInt* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (int)intValue {
return value_;
}
- (const char *)objCType {
return "i";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxInt, value_);
}
@end;
@interface KotlinLong : KotlinNumber
@end;
@implementation KotlinLong {
long long value_;
}
- (instancetype)initWithLongLong:(long long)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithLongLong:(long long)value {
KotlinLong* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (long long)longLongValue {
return value_;
}
- (const char *)objCType {
return "q";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxLong, value_);
}
@end;
@interface KotlinUByte : KotlinNumber
@end;
@implementation KotlinUByte {
unsigned char value_;
}
- (instancetype)initWithUnsignedChar:(unsigned char)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithUnsignedChar:(unsigned char)value {
KotlinUByte* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (unsigned char)unsignedCharValue {
return value_;
}
- (const char *)objCType {
return "C";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxUByte, value_);
}
@end;
@interface KotlinUShort : KotlinNumber
@end;
@implementation KotlinUShort {
unsigned short value_;
}
- (instancetype)initWithUnsignedShort:(unsigned short)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithUnsignedShort:(unsigned short)value {
KotlinUShort* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (unsigned short)unsignedShortValue {
return value_;
}
- (const char *)objCType {
return "S";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxUShort, value_);
}
@end;
@interface KotlinUInt : KotlinNumber
@end;
@implementation KotlinUInt {
unsigned int value_;
}
- (instancetype)initWithUnsignedInt:(unsigned int)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithUnsignedInt:(unsigned int)value {
KotlinUInt* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (unsigned int)unsignedIntValue {
return value_;
}
- (const char *)objCType {
return "I";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxUInt, value_);
}
@end;
@interface KotlinULong : KotlinNumber
@end;
@implementation KotlinULong {
unsigned long long value_;
}
- (instancetype)initWithUnsignedLongLong:(unsigned long long)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithUnsignedLongLong:(unsigned long long)value {
KotlinULong* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (unsigned long long)unsignedLongLongValue {
return value_;
}
- (const char *)objCType {
return "Q";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxULong, value_);
}
@end;
@interface KotlinFloat : KotlinNumber
@end;
@implementation KotlinFloat {
float value_;
}
- (instancetype)initWithFloat:(float)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithFloat:(float)value {
KotlinFloat* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
// Required to convert Swift floating literals.
- (instancetype)initWithDouble:(double)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (float)floatValue {
return value_;
}
- (const char *)objCType {
return "f";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxFloat, value_);
}
@end;
@interface KotlinDouble : KotlinNumber
@end;
@implementation KotlinDouble {
double value_;
}
- (instancetype)initWithDouble:(double)value {
self = [super init];
value_ = value;
return self;
}
+ (instancetype)numberWithDouble:(double)value {
KotlinDouble* result = [[self new] autorelease];
result->value_ = value;
return result;
}
// Required to convert Swift integer literals.
- (instancetype)initWithInteger:(NSInteger)value {
self = [super init];
value_ = value; // TODO: check fits.
return self;
}
- (double)doubleValue {
return value_;
}
- (const char *)objCType {
return "d";
}
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
RETURN_RESULT_OF(Kotlin_boxDouble, value_);
}
@end;
#endif // KONAN_OBJC_INTEROP