Rework primitive types handling in interop stub generation

Use libclang API to get correct size and spelling.
This should improve support for e.g. 32-bit platforms.
This commit is contained in:
Svyatoslav Scherbina
2017-03-22 16:54:41 +07:00
committed by SvyatoslavScherbina
parent d6ba399e1e
commit 8ec4cb48f9
3 changed files with 75 additions and 75 deletions
@@ -93,27 +93,14 @@ interface Type
interface PrimitiveType : Type interface PrimitiveType : Type
object VoidType : Type
object CharType : PrimitiveType object CharType : PrimitiveType
object Int8Type : PrimitiveType data class IntegerType(val size: Int, val isSigned: Boolean, val spelling: String) : PrimitiveType
object UInt8Type : PrimitiveType
object Int16Type : PrimitiveType // TODO: floating type is not actually defined entirely by its size.
object UInt16Type : PrimitiveType data class FloatingType(val size: Int, val spelling: String) : PrimitiveType
object Int32Type : PrimitiveType object VoidType : Type
object UInt32Type : PrimitiveType
object IntPtrType : PrimitiveType
object UIntPtrType : PrimitiveType
object Int64Type : PrimitiveType
object UInt64Type : PrimitiveType
object Float32Type : PrimitiveType
object Float64Type : PrimitiveType
data class RecordType(val decl: StructDecl) : Type data class RecordType(val decl: StructDecl) : Type
@@ -19,28 +19,38 @@ internal fun CValue<CXString>.convertAndDispose(): String {
internal fun getCursorSpelling(cursor: CValue<CXCursor>) = internal fun getCursorSpelling(cursor: CValue<CXCursor>) =
clang_getCursorSpelling(cursor).convertAndDispose() clang_getCursorSpelling(cursor).convertAndDispose()
internal fun CValue<CXType>.getSize(): Long {
val size = clang_Type_getSizeOf(this)
if (size < 0) {
throw Error(size.toString())
}
return size
}
internal fun convertUnqualifiedPrimitiveType(type: CValue<CXType>): Type = when (type.kind) { internal fun convertUnqualifiedPrimitiveType(type: CValue<CXType>): Type = when (type.kind) {
// TODO: is e.g. CXType_Int guaranteed to be int32_t? CXTypeKind.CXType_Char_U, CXTypeKind.CXType_Char_S -> {
assert(type.getSize() == 1L)
CharType
}
CXTypeKind.CXType_Char_U, CXTypeKind.CXType_Char_S -> CharType CXTypeKind.CXType_UChar, CXTypeKind.CXType_UShort,
CXTypeKind.CXType_UInt, CXTypeKind.CXType_ULong, CXTypeKind.CXType_ULongLong -> IntegerType(
size = type.getSize().toInt(),
isSigned = false,
spelling = clang_getTypeSpelling(type).convertAndDispose()
)
CXTypeKind.CXType_UChar -> UInt8Type CXTypeKind.CXType_SChar, CXTypeKind.CXType_Short,
CXTypeKind.CXType_SChar -> Int8Type CXTypeKind.CXType_Int, CXTypeKind.CXType_Long, CXTypeKind.CXType_LongLong -> IntegerType(
size = type.getSize().toInt(),
isSigned = true,
spelling = clang_getTypeSpelling(type).convertAndDispose()
)
CXTypeKind.CXType_UShort -> UInt16Type CXTypeKind.CXType_Float, CXTypeKind.CXType_Double -> FloatingType(
CXTypeKind.CXType_Short -> Int16Type size = type.getSize().toInt(),
spelling = clang_getTypeSpelling(type).convertAndDispose()
CXTypeKind.CXType_UInt -> UInt32Type )
CXTypeKind.CXType_Int -> Int32Type
CXTypeKind.CXType_ULong -> UIntPtrType
CXTypeKind.CXType_Long -> IntPtrType
CXTypeKind.CXType_ULongLong -> UInt64Type
CXTypeKind.CXType_LongLong -> Int64Type
CXTypeKind.CXType_Float -> Float32Type
CXTypeKind.CXType_Double -> Float64Type
else -> UnsupportedType else -> UnsupportedType
} }
@@ -171,21 +171,10 @@ class StubGenerator(
*/ */
fun Type.getStringRepresentation(): String { fun Type.getStringRepresentation(): String {
return when (this) { return when (this) {
is VoidType -> "void" is VoidType -> "void"
is CharType -> "char" is CharType -> "char"
is Int8Type -> "signed char" is IntegerType -> this.spelling
is UInt8Type -> "unsigned char" is FloatingType -> this.spelling
is Int16Type -> "short"
is UInt16Type -> "unsigned short"
is Int32Type -> "int"
is UInt32Type -> "unsigned int"
is IntPtrType -> "intptr_t"
is UIntPtrType -> "uintptr_t"
is Int64Type -> "int64_t"
is UInt64Type -> "uint64_t"
is Float32Type -> "float"
is Float64Type -> "double"
is PointerType -> { is PointerType -> {
val pointeeType = this.pointeeType val pointeeType = this.pointeeType
@@ -214,14 +203,22 @@ class StubGenerator(
val PrimitiveType.kotlinType: String val PrimitiveType.kotlinType: String
get() = when (this) { get() = when (this) {
is CharType -> "Byte"
is CharType, is Int8Type, is UInt8Type -> "Byte" // TODO: C primitive types should probably be generated as type aliases for Kotlin types.
is Int16Type, is UInt16Type -> "Short" is IntegerType -> when (this.size) {
is Int32Type, is UInt32Type -> "Int" 1 -> "Byte"
is IntPtrType, is UIntPtrType, // TODO: 64-bit specific 2 -> "Short"
is Int64Type, is UInt64Type -> "Long" 4 -> "Int"
is Float32Type -> "Float" 8 -> "Long"
is Float64Type -> "Double" else -> TODO(this.toString())
}
is FloatingType -> when (this.size) {
4 -> "Float"
8 -> "Double"
else -> TODO(this.toString())
}
else -> throw NotImplementedError() else -> throw NotImplementedError()
} }
@@ -327,13 +324,19 @@ class StubGenerator(
private fun mirror(type: PrimitiveType): TypeMirror.ByValue { private fun mirror(type: PrimitiveType): TypeMirror.ByValue {
val varTypeName = when (type) { val varTypeName = when (type) {
is CharType, is Int8Type, is UInt8Type -> "CInt8Var" is CharType -> "CInt8Var"
is Int16Type, is UInt16Type -> "CInt16Var" is IntegerType -> when (type.size) {
is Int32Type, is UInt32Type -> "CInt32Var" 1 -> "CInt8Var"
is IntPtrType, is UIntPtrType, // TODO: 64-bit specific 2 -> "CInt16Var"
is Int64Type, is UInt64Type -> "CInt64Var" 4 -> "CInt32Var"
is Float32Type -> "CFloat32Var" 8 -> "CInt64Var"
is Float64Type -> "CFloat64Var" else -> TODO(type.toString())
}
is FloatingType -> when (type.size) {
4 -> "CFloat32Var"
8 -> "CFloat64Var"
else -> TODO(type.toString())
}
else -> TODO(type.toString()) else -> TODO(type.toString())
} }
@@ -845,17 +848,15 @@ class StubGenerator(
private fun getFfiType(type: Type): String { private fun getFfiType(type: Type): String {
return when(type) { return when(type) {
is VoidType -> "Void" is VoidType -> "Void"
is CharType, is Int8Type -> "SInt8" is CharType -> "SInt8" // TODO: libffi has separate representation for char type.
// TODO: libffi has separate representation for char type. is IntegerType -> when (type.size) {
is UInt8Type -> "UInt8" 1 -> if (type.isSigned) "SInt8" else "UInt8"
is Int16Type -> "SInt16" 2 -> if (type.isSigned) "SInt16" else "UInt16"
is UInt16Type -> "UInt16" 4 -> if (type.isSigned) "SInt32" else "UInt32"
is Int32Type -> "SInt32" 8 -> if (type.isSigned) "SInt64" else "UInt64"
is UInt32Type -> "UInt32" else -> TODO(type.toString())
is IntPtrType, is UIntPtrType, // TODO }
is PointerType -> "Pointer" is PointerType -> "Pointer"
is Int64Type -> "SInt64"
is UInt64Type -> "UInt64"
is ConstArrayType -> getFfiStructType( is ConstArrayType -> getFfiStructType(
Array(type.length.toInt(), { type.elemType }).toList() Array(type.length.toInt(), { type.elemType }).toList()
) )
@@ -992,13 +993,15 @@ class StubGenerator(
} }
private fun floatingLiteral(type: Type, value: Double): String? { private fun floatingLiteral(type: Type, value: Double): String? {
return when (type.unwrapTypedefs()) { val unwrappedType = type.unwrapTypedefs()
Float32Type -> { if (unwrappedType !is FloatingType) return null
return when (unwrappedType.size) {
4 -> {
val floatValue = value.toFloat() val floatValue = value.toFloat()
val bits = java.lang.Float.floatToRawIntBits(floatValue) val bits = java.lang.Float.floatToRawIntBits(floatValue)
"bitsToFloat($bits) /* == $floatValue */" "bitsToFloat($bits) /* == $floatValue */"
} }
Float64Type -> { 8 -> {
val bits = java.lang.Double.doubleToRawLongBits(value) val bits = java.lang.Double.doubleToRawLongBits(value)
"bitsToDouble($bits) /* == $value */" "bitsToDouble($bits) /* == $value */"
} }