From 12cdc56dbbf466250b49324deefb0ac8fb498e0c Mon Sep 17 00:00:00 2001 From: Alexandre Mommers Date: Tue, 13 Feb 2024 18:28:43 +0100 Subject: [PATCH] Add `DeclarationOrigin` to native declarations This update introduces `DeclarationOrigin` information in various native declarations, such as `NativeFunction`, `NativeTypeAlias`, `NativeEnumeration`, and related classes. It provides a structure for noting where specific declarations originate from - be it from a platform-specific header, a library header or an unknown origin. This improves traceability, allows for more precise logging and debugging, and could enhance code generation based on origin information. --- .../kotlin/klang/DeclarationRepository.kt | 4 +++ .../klang/ObjectiveCDefaultDeclarations.kt | 3 +- .../kotlin/klang/domain/NativeDeclaration.kt | 32 ++++++++++++++++++- .../kotlin/klang/domain/NativeEnumeration.kt | 3 +- .../kotlin/klang/domain/NativeFunction.kt | 3 +- .../kotlin/klang/domain/NativeStructure.kt | 1 + .../kotlin/klang/domain/NativeTypeAlias.kt | 3 +- .../kotlin/klang/domain/NativeVariable.kt | 6 +++- .../kotlin/klang/domain/ObjectiveCCategory.kt | 3 +- .../kotlin/klang/domain/ObjectiveCClass.kt | 9 ++++-- .../kotlin/klang/domain/ObjectiveCProtocol.kt | 3 +- .../main/kotlin/klang/domain/PrimitiveType.kt | 6 ++-- .../parser/libclang/PanamaLibclangParser.kt | 23 +++++++------ .../libclang/panama/NativeEnumeration.kt | 6 ++-- .../parser/libclang/panama/NativeFunction.kt | 6 ++-- .../parser/libclang/panama/NativeStructure.kt | 6 ++-- .../parser/libclang/panama/NativeTypeAlias.kt | 5 +-- .../parser/libclang/panama/OriginProcessor.kt | 21 ++++++++++++ .../klang/parser/libclang/SDL2ItTest.kt | 13 +++++--- 19 files changed, 120 insertions(+), 36 deletions(-) create mode 100644 klang/klang/src/main/kotlin/klang/parser/libclang/panama/OriginProcessor.kt diff --git a/klang/klang/src/main/kotlin/klang/DeclarationRepository.kt b/klang/klang/src/main/kotlin/klang/DeclarationRepository.kt index 4b7bae9d..4e7c97ed 100644 --- a/klang/klang/src/main/kotlin/klang/DeclarationRepository.kt +++ b/klang/klang/src/main/kotlin/klang/DeclarationRepository.kt @@ -25,6 +25,10 @@ interface DeclarationRepository { fun findObjectiveCCategoryByName(name: String) = findDeclarationByName(name) + fun findLibraryDeclaration() = declarations.asSequence() + .filterIsInstance() + .filter { it.source is DeclarationOrigin.LibraryHeader } + .toList() } inline fun DeclarationRepository.findDeclarationByName(declarationName: String) = declarations diff --git a/klang/klang/src/main/kotlin/klang/ObjectiveCDefaultDeclarations.kt b/klang/klang/src/main/kotlin/klang/ObjectiveCDefaultDeclarations.kt index 42cf13f7..e266e202 100644 --- a/klang/klang/src/main/kotlin/klang/ObjectiveCDefaultDeclarations.kt +++ b/klang/klang/src/main/kotlin/klang/ObjectiveCDefaultDeclarations.kt @@ -1,11 +1,12 @@ package klang +import klang.domain.DeclarationOrigin import klang.domain.NameableDeclaration import klang.domain.ObjectiveCProtocol object ObjectiveCRootClass: NameableDeclaration { override val name: String = "NSObject" - + override val source: DeclarationOrigin = DeclarationOrigin.PlatformHeader } diff --git a/klang/klang/src/main/kotlin/klang/domain/NativeDeclaration.kt b/klang/klang/src/main/kotlin/klang/domain/NativeDeclaration.kt index 9a457026..bceeb590 100644 --- a/klang/klang/src/main/kotlin/klang/domain/NativeDeclaration.kt +++ b/klang/klang/src/main/kotlin/klang/domain/NativeDeclaration.kt @@ -30,10 +30,40 @@ sealed interface NativeDeclaration { } } -interface NameableDeclaration : NativeDeclaration { +/** + * This interface represents a nameable declaration. + */ +interface NameableDeclaration : SourceableDeclaration { val name: String } interface ResolvableDeclaration { fun DeclarationRepository.resolve() +} + +/** + * Represents the origin of a native declaration. + */ +sealed interface DeclarationOrigin { + + /** + * Represents an unknown origin of a native declaration. + */ + object UnknownOrigin : DeclarationOrigin + + /** + * Represents a platform-specific header used for native declarations, like libc. + */ + object PlatformHeader : DeclarationOrigin + + /** + * Represents a header file used for native declarations in a library. + * + * @property file The path to the header file. + */ + class LibraryHeader(val file: String) : DeclarationOrigin +} + +interface SourceableDeclaration : NativeDeclaration { + val source: DeclarationOrigin } \ No newline at end of file diff --git a/klang/klang/src/main/kotlin/klang/domain/NativeEnumeration.kt b/klang/klang/src/main/kotlin/klang/domain/NativeEnumeration.kt index 539379cf..960254b2 100644 --- a/klang/klang/src/main/kotlin/klang/domain/NativeEnumeration.kt +++ b/klang/klang/src/main/kotlin/klang/domain/NativeEnumeration.kt @@ -8,7 +8,8 @@ data class NativeEnumeration( override val name: String, var values: List> = emptyList(), //TODO add support for other types - var type: TypeRef = typeOf("int").unchecked("Type 'int' not found") + var type: TypeRef = typeOf("int").unchecked("Type 'int' not found"), + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ) : NameableDeclaration, ResolvableDeclaration { override fun merge(other: T) { diff --git a/klang/klang/src/main/kotlin/klang/domain/NativeFunction.kt b/klang/klang/src/main/kotlin/klang/domain/NativeFunction.kt index cdb91cc8..4b0e1a8c 100644 --- a/klang/klang/src/main/kotlin/klang/domain/NativeFunction.kt +++ b/klang/klang/src/main/kotlin/klang/domain/NativeFunction.kt @@ -5,7 +5,8 @@ import klang.DeclarationRepository data class NativeFunction( override val name: String, var returnType: TypeRef, - val arguments: List + val arguments: List, + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ): NameableDeclaration, NativeDeclaration, ResolvableDeclaration { data class Argument( diff --git a/klang/klang/src/main/kotlin/klang/domain/NativeStructure.kt b/klang/klang/src/main/kotlin/klang/domain/NativeStructure.kt index 3a74ac99..bc42cb0f 100644 --- a/klang/klang/src/main/kotlin/klang/domain/NativeStructure.kt +++ b/klang/klang/src/main/kotlin/klang/domain/NativeStructure.kt @@ -24,6 +24,7 @@ data class NativeStructure( override val name: String, var fields: List = listOf(), var isUnion: Boolean = false, + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin, ) : NameableDeclaration, ResolvableDeclaration { override fun merge(other: T) { if (other is NativeStructure) { diff --git a/klang/klang/src/main/kotlin/klang/domain/NativeTypeAlias.kt b/klang/klang/src/main/kotlin/klang/domain/NativeTypeAlias.kt index d59308bb..ebbc5c39 100644 --- a/klang/klang/src/main/kotlin/klang/domain/NativeTypeAlias.kt +++ b/klang/klang/src/main/kotlin/klang/domain/NativeTypeAlias.kt @@ -4,7 +4,8 @@ import klang.DeclarationRepository data class NativeTypeAlias( override val name: String, - var typeRef: TypeRef + var typeRef: TypeRef, + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ) :NameableDeclaration, NativeDeclaration, ResolvableDeclaration { override fun DeclarationRepository.resolve() { diff --git a/klang/klang/src/main/kotlin/klang/domain/NativeVariable.kt b/klang/klang/src/main/kotlin/klang/domain/NativeVariable.kt index e770d20b..b9136e59 100644 --- a/klang/klang/src/main/kotlin/klang/domain/NativeVariable.kt +++ b/klang/klang/src/main/kotlin/klang/domain/NativeVariable.kt @@ -1,3 +1,7 @@ package klang.domain -data class NativeVariable(override val name: String, val type: String): NameableDeclaration, NativeDeclaration \ No newline at end of file +data class NativeVariable( + override val name: String, + val type: String, + override val source: DeclarationOrigin +): NameableDeclaration, NativeDeclaration \ No newline at end of file diff --git a/klang/klang/src/main/kotlin/klang/domain/ObjectiveCCategory.kt b/klang/klang/src/main/kotlin/klang/domain/ObjectiveCCategory.kt index 8935eb61..87b20bdb 100644 --- a/klang/klang/src/main/kotlin/klang/domain/ObjectiveCCategory.kt +++ b/klang/klang/src/main/kotlin/klang/domain/ObjectiveCCategory.kt @@ -7,7 +7,8 @@ internal val AnonymousCategoryName = "AnonymousCategory" data class ObjectiveCCategory( override val name: String, var superType: TypeRef, - val methods: List + val methods: List, + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ) : NameableDeclaration, ResolvableDeclaration { override fun DeclarationRepository.resolve() { diff --git a/klang/klang/src/main/kotlin/klang/domain/ObjectiveCClass.kt b/klang/klang/src/main/kotlin/klang/domain/ObjectiveCClass.kt index 9397a29e..e655c28e 100644 --- a/klang/klang/src/main/kotlin/klang/domain/ObjectiveCClass.kt +++ b/klang/klang/src/main/kotlin/klang/domain/ObjectiveCClass.kt @@ -8,7 +8,8 @@ data class ObjectiveCClass( var protocols: Set, var properties: List, var methods: List, - var categories: Set = setOf() + var categories: Set = setOf(), + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ) : NameableDeclaration, ResolvableDeclaration { data class Property( @@ -17,14 +18,16 @@ data class ObjectiveCClass( val assign: Boolean? = null, val readwrite: Boolean? = null, val nonatomic: Boolean? = null, - val unsafe_unretained: Boolean? = null + val unsafe_unretained: Boolean? = null, + override val source: DeclarationOrigin= DeclarationOrigin.UnknownOrigin ) : NameableDeclaration data class Method( override val name: String, var returnType: TypeRef, val instance: Boolean, - val arguments: List = listOf() + val arguments: List = listOf(), + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ) : NameableDeclaration, ResolvableDeclaration { data class Argument( val name: String, diff --git a/klang/klang/src/main/kotlin/klang/domain/ObjectiveCProtocol.kt b/klang/klang/src/main/kotlin/klang/domain/ObjectiveCProtocol.kt index f500105b..bb7082d1 100644 --- a/klang/klang/src/main/kotlin/klang/domain/ObjectiveCProtocol.kt +++ b/klang/klang/src/main/kotlin/klang/domain/ObjectiveCProtocol.kt @@ -4,5 +4,6 @@ data class ObjectiveCProtocol( override val name: String, val protocols: Set, var properties: List, - var methods: List + var methods: List, + override val source: DeclarationOrigin = DeclarationOrigin.UnknownOrigin ) : NameableDeclaration \ No newline at end of file diff --git a/klang/klang/src/main/kotlin/klang/domain/PrimitiveType.kt b/klang/klang/src/main/kotlin/klang/domain/PrimitiveType.kt index b53d6e8b..8cf59ed4 100644 --- a/klang/klang/src/main/kotlin/klang/domain/PrimitiveType.kt +++ b/klang/klang/src/main/kotlin/klang/domain/PrimitiveType.kt @@ -4,13 +4,15 @@ sealed class PrimitiveType: NameableDeclaration data object VoidType: PrimitiveType() { override val name: String = "void" + override val source: DeclarationOrigin = DeclarationOrigin.PlatformHeader } -class FixeSizeType(val size: Int, override val name: String, val isFloating: Boolean = false): PrimitiveType() -class PlatformDependantSizeType(val size: IntRange, override val name: String): PrimitiveType() +class FixeSizeType(val size: Int, override val name: String, val isFloating: Boolean = false, override val source: DeclarationOrigin = DeclarationOrigin.PlatformHeader): PrimitiveType() +class PlatformDependantSizeType(val size: IntRange, override val name: String, override val source: DeclarationOrigin = DeclarationOrigin.PlatformHeader): PrimitiveType() data object StringType: PrimitiveType() { override val name: String = "char *" + override val source: DeclarationOrigin = DeclarationOrigin.PlatformHeader } diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/PanamaLibclangParser.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/PanamaLibclangParser.kt index 7e6669ca..735b5cae 100644 --- a/klang/klang/src/main/kotlin/klang/parser/libclang/PanamaLibclangParser.kt +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/PanamaLibclangParser.kt @@ -2,8 +2,10 @@ package klang.parser.libclang import klang.DeclarationRepository import klang.InMemoryDeclarationRepository +import klang.domain.DeclarationOrigin import klang.domain.NameableDeclaration import klang.parse +import klang.parser.libclang.panama.OriginProcessor.toOrigin import klang.parser.libclang.panama.toNativeEnumeration import klang.parser.libclang.panama.toNativeStructure import klang.parser.libclang.panama.toNativeTypeAlias @@ -37,10 +39,11 @@ fun parseFileWithPanama(file: String, filePath: Path?, headerPaths: Array) .asSequence() .filter { it.declarationIsOnFilePath(filePath) } .map { + val origin = it.pos().toOrigin(filePath) when (it) { - is Scoped -> it.scopedToLocalDeclaration() - is Typedef -> it.typeDefToLocalDeclaration() - is Declaration.Function -> it.toNativeTypeAlias() + is Scoped -> it.scopedToLocalDeclaration(origin = origin) + is Typedef -> it.typeDefToLocalDeclaration(origin) + is Declaration.Function -> it.toNativeTypeAlias(origin) else -> { logger.error { "not found $it" } null @@ -56,18 +59,18 @@ internal fun Declaration.declarationIsOnFilePath(filePath: Path?): Boolean = fil ?.pathString ?.let { pos().path().parent.pathString.contains(it) } ?: true -private fun Typedef.typeDefToLocalDeclaration(): NameableDeclaration? = type().let { type -> +private fun Typedef.typeDefToLocalDeclaration(origin: DeclarationOrigin): NameableDeclaration? = type().let { type -> when (type) { - is TypeImpl.DeclaredImpl -> type.tree().scopedToLocalDeclaration(name()) - else -> toNativeTypeAlias() + is TypeImpl.DeclaredImpl -> type.tree().scopedToLocalDeclaration(name(), origin) + else -> toNativeTypeAlias(origin) } } -private fun Scoped.scopedToLocalDeclaration(name: String? = null): NameableDeclaration? { +private fun Scoped.scopedToLocalDeclaration(name: String? = null, origin: DeclarationOrigin): NameableDeclaration? { return when (kind()) { - Declaration.Scoped.Kind.ENUM -> toNativeEnumeration(name) - Declaration.Scoped.Kind.STRUCT -> toNativeStructure(name) - Declaration.Scoped.Kind.UNION -> toNativeStructure(name, isUnion = true) + Declaration.Scoped.Kind.ENUM -> toNativeEnumeration(name, origin) + Declaration.Scoped.Kind.STRUCT -> toNativeStructure(name, origin = origin) + Declaration.Scoped.Kind.UNION -> toNativeStructure(name, isUnion = true, origin) else -> { logger.error { "not found ${kind()}" } diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeEnumeration.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeEnumeration.kt index 55728606..9f1e029a 100644 --- a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeEnumeration.kt +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeEnumeration.kt @@ -1,11 +1,13 @@ package klang.parser.libclang.panama +import klang.domain.DeclarationOrigin import klang.domain.NativeEnumeration import org.openjdk.jextract.Declaration -internal fun Declaration.Scoped.toNativeEnumeration(name: String?) = NativeEnumeration( +internal fun Declaration.Scoped.toNativeEnumeration(name: String?, origin: DeclarationOrigin) = NativeEnumeration( name ?: name(), - members().toEnumValues() + members().toEnumValues(), + source = origin ) private fun List.toEnumValues(): List> = filterIsInstance() diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeFunction.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeFunction.kt index 30a0e0c6..de26e119 100644 --- a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeFunction.kt +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeFunction.kt @@ -1,14 +1,16 @@ package klang.parser.libclang.panama +import klang.domain.DeclarationOrigin import klang.domain.NameableDeclaration import klang.domain.NativeFunction import org.openjdk.jextract.Declaration import org.openjdk.jextract.Declaration.Variable -internal fun Declaration.Function.toNativeTypeAlias(): NameableDeclaration = NativeFunction( +internal fun Declaration.Function.toNativeTypeAlias(origin: DeclarationOrigin): NameableDeclaration = NativeFunction( name(), returnType = type().toTypeRef(), - arguments = parameters().map { it.toArgument() } + arguments = parameters().map { it.toArgument() }, + source = origin ) private fun Variable.toArgument() = NativeFunction.Argument( diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeStructure.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeStructure.kt index fc9a4732..ef585121 100644 --- a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeStructure.kt +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeStructure.kt @@ -1,12 +1,13 @@ package klang.parser.libclang.panama +import klang.domain.DeclarationOrigin import klang.domain.NativeStructure import klang.domain.StructureField import klang.domain.TypeRefField import org.openjdk.jextract.Declaration import org.openjdk.jextract.impl.TypeImpl -internal fun Declaration.Scoped.toNativeStructure(name: String?, isUnion: Boolean = false) = Triple( +internal fun Declaration.Scoped.toNativeStructure(name: String?, isUnion: Boolean = false, origin: DeclarationOrigin) = Triple( name ?: name(), members().toStructureFields(), isUnion @@ -14,7 +15,8 @@ internal fun Declaration.Scoped.toNativeStructure(name: String?, isUnion: Boolea NativeStructure( name, fields, - isUnion + isUnion, + origin ) } diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeTypeAlias.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeTypeAlias.kt index 8d62f664..d5da3a88 100644 --- a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeTypeAlias.kt +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/NativeTypeAlias.kt @@ -1,8 +1,9 @@ package klang.parser.libclang.panama +import klang.domain.DeclarationOrigin import klang.domain.NameableDeclaration import klang.domain.NativeTypeAlias import org.openjdk.jextract.Declaration -internal fun Declaration.Typedef.toNativeTypeAlias(): NameableDeclaration? = (name() to type().toTypeRef()) - .let { (name, typeRef) -> NativeTypeAlias(name, typeRef) } +internal fun Declaration.Typedef.toNativeTypeAlias(origin: DeclarationOrigin): NameableDeclaration? = (name() to type().toTypeRef()) + .let { (name, typeRef) -> NativeTypeAlias(name, typeRef, origin) } diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/OriginProcessor.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/OriginProcessor.kt new file mode 100644 index 00000000..93547fd8 --- /dev/null +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/OriginProcessor.kt @@ -0,0 +1,21 @@ +package klang.parser.libclang.panama + +import klang.domain.DeclarationOrigin +import org.openjdk.jextract.Position +import java.nio.file.Path +import kotlin.io.path.absolutePathString + +object OriginProcessor { + + internal fun Position?.toOrigin(filePath: Path?): DeclarationOrigin = when { + filePath == null || this == null -> DeclarationOrigin.UnknownOrigin + else -> when { + isInFilePath(filePath) -> DeclarationOrigin.LibraryHeader(path().absolutePathString()) + else -> DeclarationOrigin.PlatformHeader + } + } + + private fun Position.isInFilePath(filePath: Path) = + path().absolutePathString().contains(filePath.absolutePathString()) + +} \ No newline at end of file diff --git a/klang/klang/src/test/kotlin/klang/parser/libclang/SDL2ItTest.kt b/klang/klang/src/test/kotlin/klang/parser/libclang/SDL2ItTest.kt index 080aa0e8..20db0ff2 100644 --- a/klang/klang/src/test/kotlin/klang/parser/libclang/SDL2ItTest.kt +++ b/klang/klang/src/test/kotlin/klang/parser/libclang/SDL2ItTest.kt @@ -1,6 +1,7 @@ package klang.parser.libclang -import klang.domain.NameableDeclaration +import klang.domain.DeclarationOrigin.LibraryHeader +import klang.domain.SourceableDeclaration import klang.helper.HeaderManager import klang.helper.HeaderManager.inferPlatformSuffix import klang.helper.unzipFromClasspath @@ -27,17 +28,19 @@ class SDL2ItTest : ParserTestCommon({ .also { it.resolveTypes { resolvableDeclaration -> when (resolvableDeclaration) { - is NameableDeclaration -> resolvableDeclaration.name.startsWith("_").not() - else -> true + is SourceableDeclaration -> (resolvableDeclaration.source is LibraryHeader) + else -> false } } } - + repository.findFunctionByName("SDL_Rect") + .let { println("SDL_Rect $it") } // Then repository.apply { - println(declarations.size) + val libraryDeclarations = findLibraryDeclaration() + println(libraryDeclarations.size) } }