Allow passing interop types to C API, refactoring.

This commit is contained in:
Nikolay Igotti
2018-01-18 16:21:00 +03:00
committed by Nikolay Igotti
parent 76834dc7ce
commit 1599eddfe1
3 changed files with 33 additions and 19 deletions
@@ -94,6 +94,13 @@ private val cnameAnnotation = FqName("konan.internal.CName")
private fun org.jetbrains.kotlin.types.KotlinType.isGeneric() = private fun org.jetbrains.kotlin.types.KotlinType.isGeneric() =
constructor.declarationDescriptor is TypeParameterDescriptor constructor.declarationDescriptor is TypeParameterDescriptor
private val ClassDescriptor.isString
get() = fqNameSafe.asString() == "kotlin.String"
private val ClassDescriptor.isValueType
get() = this.defaultType.correspondingValueType != null
private fun isExportedFunction(descriptor: FunctionDescriptor): Boolean { private fun isExportedFunction(descriptor: FunctionDescriptor): Boolean {
if (!descriptor.isEffectivelyPublicApi || !descriptor.kind.isReal) if (!descriptor.isEffectivelyPublicApi || !descriptor.kind.isReal)
return false return false
@@ -329,9 +336,8 @@ private class ExportedElement(val kind: ElementKind,
private fun translateArgument(name: String, clazz: ClassDescriptor, direction: Direction, private fun translateArgument(name: String, clazz: ClassDescriptor, direction: Direction,
builder: StringBuilder): String { builder: StringBuilder): String {
val fqName = clazz.fqNameSafe.asString()
return when { return when {
fqName == "kotlin.String" -> clazz.isString ->
if (direction == Direction.C_TO_KOTLIN) { if (direction == Direction.C_TO_KOTLIN) {
builder.append(" KObjHolder ${name}_holder;\n") builder.append(" KObjHolder ${name}_holder;\n")
"CreateStringFromCString($name, ${name}_holder.slot())" "CreateStringFromCString($name, ${name}_holder.slot())"
@@ -345,7 +351,10 @@ private class ExportedElement(val kind: ElementKind,
} else { } else {
"((${owner.translateType(clazz)}){ .pinned = CreateStablePointer(${name})})" "((${owner.translateType(clazz)}){ .pinned = CreateStablePointer(${name})})"
} }
else -> name else -> {
assert(clazz.isValueType)
name
}
} }
} }
@@ -830,23 +839,24 @@ internal class CAdapterGenerator(
) )
private val primitiveTypeMapping = mapOf( private val primitiveTypeMapping = mapOf(
"kotlin.Byte" to "${prefix}_KByte", ValueType.BOOLEAN to "${prefix}_KByte",
"kotlin.Short" to "${prefix}_KShort", ValueType.SHORT to "${prefix}_KShort",
"kotlin.Int" to "${prefix}_KInt", ValueType.INT to "${prefix}_KInt",
"kotlin.Long" to "${prefix}_KLong", ValueType.LONG to "${prefix}_KLong",
"kotlin.Float" to "${prefix}_KFloat", ValueType.FLOAT to "${prefix}_KFloat",
"kotlin.Double" to "${prefix}_KDouble", ValueType.DOUBLE to "${prefix}_KDouble",
"kotlin.Boolean" to "${prefix}_KBoolean", ValueType.CHAR to "${prefix}_KChar",
"kotlin.Char" to "${prefix}_KChar" ValueType.C_POINTER to "void*",
ValueType.NATIVE_PTR to "void*",
ValueType.NATIVE_POINTED to "void*"
) )
internal fun isMappedToString(descriptor: ClassDescriptor) = internal fun isMappedToString(descriptor: ClassDescriptor) =
descriptor.fqNameSafe.asString() == "kotlin.String" descriptor.fqNameSafe.asString() == "kotlin.String"
internal fun isMappedToReference(descriptor: ClassDescriptor): Boolean { internal fun isMappedToReference(descriptor: ClassDescriptor) =
val name = descriptor.fqNameSafe.asString() !descriptor.isUnit() && !isMappedToString(descriptor) &&
return !descriptor.isUnit() && name != "kotlin.String" && !primitiveTypeMapping.contains(name) !primitiveTypeMapping.contains(descriptor.defaultType.correspondingValueType)
}
internal fun isMappedToVoid(descriptor: ClassDescriptor): Boolean { internal fun isMappedToVoid(descriptor: ClassDescriptor): Boolean {
return descriptor.isUnit() return descriptor.isUnit()
@@ -862,10 +872,11 @@ internal class CAdapterGenerator(
private fun translateTypeFull(clazz: ClassDescriptor): Pair<String, String> { private fun translateTypeFull(clazz: ClassDescriptor): Pair<String, String> {
val fqName = clazz.fqNameSafe.asString() val fqName = clazz.fqNameSafe.asString()
val valueType = clazz.defaultType.correspondingValueType
return when { return when {
clazz.isUnit() -> "void" to "void" clazz.isUnit() -> "void" to "void"
fqName == "kotlin.String" -> "const char*" to "KObjHeader*" fqName == "kotlin.String" -> "const char*" to "KObjHeader*"
primitiveTypeMapping.contains(fqName) -> primitiveTypeMapping[fqName]!! to primitiveTypeMapping[fqName]!! valueType != null && primitiveTypeMapping.contains(valueType) -> primitiveTypeMapping[valueType]!! to primitiveTypeMapping[valueType]!!
else -> "${prefix}_kref_${translateTypeFqName(clazz.fqNameSafe.asString())}" to "KObjHeader*" else -> "${prefix}_kref_${translateTypeFqName(clazz.fqNameSafe.asString())}" to "KObjHeader*"
} }
} }
@@ -1,3 +1,4 @@
import kotlinx.cinterop.*
// Top level functions. // Top level functions.
fun hello() { fun hello() {
@@ -16,12 +17,14 @@ open class Base {
} }
// Top level functions.
@konan.internal.CName(fullName = "topLevelFunctionFromC", shortName = "topLevelFunctionFromCShort") @konan.internal.CName(fullName = "topLevelFunctionFromC", shortName = "topLevelFunctionFromCShort")
fun topLevelFunction(x1: Int, x2: Int) = x1 - x2 fun topLevelFunction(x1: Int, x2: Int) = x1 - x2
@konan.internal.CName("topLevelFunctionVoidFromC") @konan.internal.CName("topLevelFunctionVoidFromC")
fun topLevelFunctionVoid(x1: Int) { fun topLevelFunctionVoid(x1: Int, pointer: COpaquePointer?) {
assert(x1 == 42) assert(x1 == 42)
assert(pointer == null)
} }
// Enum. // Enum.
@@ -36,8 +36,8 @@ int main(void) {
printf("object = %d\n", __ kotlin.root.Codeable.asCode(object1)); printf("object = %d\n", __ kotlin.root.Codeable.asCode(object1));
topLevelFunctionVoidFromC(42); topLevelFunctionVoidFromC(42, 0);
__ kotlin.root.topLevelFunctionVoid(42); __ kotlin.root.topLevelFunctionVoid(42, 0);
printf("topLevel = %d %d\n", topLevelFunctionFromC(780, 3), __ kotlin.root.topLevelFunctionFromCShort(5, 2)); printf("topLevel = %d %d\n", topLevelFunctionFromC(780, 3), __ kotlin.root.topLevelFunctionFromCShort(5, 2));
__ DisposeString(string); __ DisposeString(string);