Interop/StubGenerator: attempt to handle anonymous enums
This commit is contained in:
+9
-1
@@ -209,7 +209,15 @@ private class NativeIndexImpl : NativeIndex() {
|
|||||||
val name = entityName!!
|
val name = entityName!!
|
||||||
val value = clang_getEnumConstantDeclValue(info.cursor)
|
val value = clang_getEnumConstantDeclValue(info.cursor)
|
||||||
|
|
||||||
getEnumDefAt(container.cursor).values.add(EnumValue(name, value))
|
val values = getEnumDefAt(container.cursor).values
|
||||||
|
val existingValue = values.find { it.name == name }
|
||||||
|
if (existingValue == null) {
|
||||||
|
values.add(EnumValue(name, value))
|
||||||
|
} else {
|
||||||
|
// in some cases Clang may index the same definition multiple times; ignore redeclaration
|
||||||
|
// TODO: implement the same fix for structs
|
||||||
|
assert (existingValue.value == value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+74
-19
@@ -32,6 +32,17 @@ class StubGenerator(
|
|||||||
return if (strippedCName !in forbiddenStructNames) strippedCName else (strippedCName + "Struct")
|
return if (strippedCName !in forbiddenStructNames) strippedCName else (strippedCName + "Struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val EnumDef.isAnonymous: Boolean
|
||||||
|
get() = spelling.contains("(anonymous ") // TODO: it is a hack
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this enum should be represented as Kotlin enum.
|
||||||
|
*/
|
||||||
|
val EnumDef.isKotlinEnum: Boolean
|
||||||
|
// TODO: if an anonymous enum defines e.g. a function return value or struct field type,
|
||||||
|
// then it probably should be represented as Kotlin enum
|
||||||
|
get() = !isAnonymous
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name to be used for this enum in Kotlin
|
* The name to be used for this enum in Kotlin
|
||||||
*/
|
*/
|
||||||
@@ -39,12 +50,16 @@ class StubGenerator(
|
|||||||
get() = if (spelling.startsWith("enum ")) {
|
get() = if (spelling.startsWith("enum ")) {
|
||||||
spelling.substringAfter(' ')
|
spelling.substringAfter(' ')
|
||||||
} else {
|
} else {
|
||||||
|
assert (!isAnonymous)
|
||||||
spelling
|
spelling
|
||||||
}
|
}
|
||||||
|
|
||||||
val RecordType.kotlinName: String
|
val RecordType.kotlinName: String
|
||||||
get() = decl.kotlinName
|
get() = decl.kotlinName
|
||||||
|
|
||||||
|
val EnumType.isKotlinEnum: Boolean
|
||||||
|
get() = def.isKotlinEnum
|
||||||
|
|
||||||
val EnumType.kotlinName: String
|
val EnumType.kotlinName: String
|
||||||
get() = def.kotlinName
|
get() = def.kotlinName
|
||||||
|
|
||||||
@@ -116,7 +131,11 @@ class StubGenerator(
|
|||||||
|
|
||||||
is ArrayType -> "void*" // TODO
|
is ArrayType -> "void*" // TODO
|
||||||
|
|
||||||
is EnumType -> this.def.spelling
|
is EnumType -> if (this.def.isAnonymous) {
|
||||||
|
this.def.baseType.getStringRepresentation()
|
||||||
|
} else {
|
||||||
|
this.def.spelling
|
||||||
|
}
|
||||||
|
|
||||||
else -> throw kotlin.NotImplementedError()
|
else -> throw kotlin.NotImplementedError()
|
||||||
}
|
}
|
||||||
@@ -155,7 +174,11 @@ class StubGenerator(
|
|||||||
|
|
||||||
is RecordType -> NativeRefType("${type.kotlinName}")
|
is RecordType -> NativeRefType("${type.kotlinName}")
|
||||||
|
|
||||||
is EnumType -> NativeRefType("${type.kotlinName}.ref")
|
is EnumType -> if (type.isKotlinEnum) {
|
||||||
|
NativeRefType("${type.kotlinName}.ref")
|
||||||
|
} else {
|
||||||
|
getKotlinTypeForRefTo(type.def.baseType)
|
||||||
|
}
|
||||||
|
|
||||||
is PointerType -> {
|
is PointerType -> {
|
||||||
if (type.pointeeType is VoidType || type.pointeeType is FunctionType) {
|
if (type.pointeeType is VoidType || type.pointeeType is FunctionType) {
|
||||||
@@ -247,11 +270,15 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is EnumType -> OutValueBinding(
|
is EnumType -> if (type.isKotlinEnum) {
|
||||||
kotlinType = type.kotlinName,
|
OutValueBinding(
|
||||||
kotlinConv = { "$it.value" },
|
kotlinType = type.kotlinName,
|
||||||
kotlinJniBridgeType = type.def.baseType.kotlinType
|
kotlinConv = { "$it.value" },
|
||||||
)
|
kotlinJniBridgeType = type.def.baseType.kotlinType
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
getOutValueBinding(type.def.baseType)
|
||||||
|
}
|
||||||
|
|
||||||
is ArrayType -> outValueRefBinding(getKotlinTypeForRefTo(type))
|
is ArrayType -> outValueRefBinding(getKotlinTypeForRefTo(type))
|
||||||
|
|
||||||
@@ -289,11 +316,15 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is EnumType -> InValueBinding(
|
is EnumType -> if (type.isKotlinEnum) {
|
||||||
kotlinJniBridgeType = type.def.baseType.kotlinType,
|
InValueBinding(
|
||||||
conv = { "${type.kotlinName}.byValue($it)" },
|
kotlinJniBridgeType = type.def.baseType.kotlinType,
|
||||||
kotlinType = type.kotlinName
|
conv = { "${type.kotlinName}.byValue($it)" },
|
||||||
)
|
kotlinType = type.kotlinName
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
getInValueBinding(type.def.baseType)
|
||||||
|
}
|
||||||
|
|
||||||
is ArrayType -> inValueRefBinding(getKotlinTypeForRefTo(type))
|
is ArrayType -> inValueRefBinding(getKotlinTypeForRefTo(type))
|
||||||
|
|
||||||
@@ -313,10 +344,10 @@ class StubGenerator(
|
|||||||
/**
|
/**
|
||||||
* Produces to [out] the definition of Kotlin class representing the reference to given struct.
|
* Produces to [out] the definition of Kotlin class representing the reference to given struct.
|
||||||
*/
|
*/
|
||||||
private fun generateKotlinStruct(decl: StructDecl) {
|
private fun generateStruct(decl: StructDecl) {
|
||||||
val def = decl.def
|
val def = decl.def
|
||||||
if (def == null) {
|
if (def == null) {
|
||||||
generateKotlinForwardStruct(decl)
|
generateForwardStruct(decl)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +375,7 @@ class StubGenerator(
|
|||||||
/**
|
/**
|
||||||
* Produces to [out] the definition of Kotlin class representing the reference to given forward (incomplete) struct.
|
* Produces to [out] the definition of Kotlin class representing the reference to given forward (incomplete) struct.
|
||||||
*/
|
*/
|
||||||
private fun generateKotlinForwardStruct(s: StructDecl) {
|
private fun generateForwardStruct(s: StructDecl) {
|
||||||
val className = s.kotlinName
|
val className = s.kotlinName
|
||||||
out("class $className(ptr: NativePtr) : NativeRef(ptr) {")
|
out("class $className(ptr: NativePtr) : NativeRef(ptr) {")
|
||||||
out(" companion object : Type<$className>(::$className)")
|
out(" companion object : Type<$className>(::$className)")
|
||||||
@@ -352,9 +383,14 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces to [out] the definition of Kotlin class representing the value of given enum.
|
* Produces to [out] the Kotlin definitions for given enum.
|
||||||
*/
|
*/
|
||||||
private fun generateKotlinEnum(e: EnumDef) {
|
private fun generateEnum(e: EnumDef) {
|
||||||
|
if (!e.isKotlinEnum) {
|
||||||
|
generateEnumAsValues(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val baseRefType = getKotlinTypeForRefTo(e.baseType)
|
val baseRefType = getKotlinTypeForRefTo(e.baseType)
|
||||||
|
|
||||||
out("enum class ${e.kotlinName}(val value: ${e.baseType.kotlinType}) {")
|
out("enum class ${e.kotlinName}(val value: ${e.baseType.kotlinType}) {")
|
||||||
@@ -379,6 +415,25 @@ class StubGenerator(
|
|||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the Kotlin definitions for given enum which shouldn't be represented as Kotlin enum.
|
||||||
|
*
|
||||||
|
* @see isKotlinEnum
|
||||||
|
*/
|
||||||
|
private fun generateEnumAsValues(e: EnumDef) {
|
||||||
|
// TODO: if this enum defines e.g. a type of struct field, then it should be generated inside the struct class
|
||||||
|
// to prevent name clashing
|
||||||
|
|
||||||
|
if (e.values.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out("// ${e.spelling}")
|
||||||
|
e.values.forEach {
|
||||||
|
out("val ${it.name}: ${e.baseType.kotlinType} = ${it.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs [InValueBinding] for return value of Kotlin binding for given C function.
|
* Constructs [InValueBinding] for return value of Kotlin binding for given C function.
|
||||||
*/
|
*/
|
||||||
@@ -508,7 +563,7 @@ class StubGenerator(
|
|||||||
nativeIndex.structs.forEach { s ->
|
nativeIndex.structs.forEach { s ->
|
||||||
try {
|
try {
|
||||||
transaction {
|
transaction {
|
||||||
generateKotlinStruct(s)
|
generateStruct(s)
|
||||||
out("")
|
out("")
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
@@ -517,7 +572,7 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
nativeIndex.enums.forEach { e ->
|
nativeIndex.enums.forEach { e ->
|
||||||
generateKotlinEnum(e)
|
generateEnum(e)
|
||||||
out("")
|
out("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user