Коммит ea0d9e95 создал по автору Ilya Pankratov's avatar Ilya Pankratov
Просмотр файлов

Implement Qt header generator

владелец d277d7b1
/**
* SPDX-FileCopyrightText: Copyright 2025 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: BSD-3-Clause
*/
package ru.aurora.kmp.qtbindings.ksp.gen
import ru.aurora.kmp.qtbindings.ksp.model.*
internal class QtHeaderGenerator(val cApi: CLibraryAPI) : QtBaseGenerator() {
override fun generate(file: QtFile): String {
return buildString {
val generators = mutableListOf<() -> Unit>()
if (file.classes.any()) generators.add {
file.classes.forEach { generateForwardDeclaration(it.name) }
}
if (file.functions.any()) generators.add {
file.functions.forEach { f ->
generateFunction(f.name, f.parameters, f.isAsync, f.isConst, f.returnType)
}
}
if (file.classes.any()) generators.add {
file.classes.forEachIndexed { index, cppClass ->
generateClass(cppClass)
// Add new line between classes
if (index != file.classes.lastIndex) appendLine()
}
}
generatedCodeWarning()
appendLine()
headerGuard(file.headerGuard) {
if (file.headerIncludes.any()) {
generateIncludes(file.headerIncludes)
appendLine()
}
namespace(file.namespace) {
// Generate top-level functions and classes
generators.forEachIndexed { index, generator ->
generator()
// Add new line between generators
if (index != generators.lastIndex) appendLine()
}
}
}
}
}
private fun StringBuilder.headerGuard(headerGuard: String, block: StringBuilder.() -> Unit) {
appendLine("#ifndef $headerGuard")
appendLine("#define $headerGuard")
appendLine()
block()
appendLine()
appendLine("#endif /* $headerGuard */")
}
private fun StringBuilder.generateForwardDeclaration(className: String) {
appendLine("class $className;")
}
private fun StringBuilder.generateFunction(
name: String, parameters: List<QtParameter>, isAsync: Boolean, isConst: Boolean, returnType: QtType? = null
) {
if (returnType != null) appendWithSpace(returnType.toReturnType(isAsync))
append(name)
append("(${parameters.joinToString { it.toFunctionParameter() }})")
if (isConst) append(" const")
appendLine(";")
}
private fun StringBuilder.generateClass(qtClass: QtClass) {
val generators = mutableListOf<StringBuilder.() -> Unit>()
val (constructors, methods) = qtClass.methods.partition { it.isConstructor }
if (constructors.any()) generators.add {
constructors.forEach { c ->
generateFunction(c.name, c.parameters, c.isAsync, c.isConst, null)
}
if (qtClass.hasCopyMethod) generateCopyConstructor(qtClass)
generateMoveConstructor(qtClass)
generateKotlinWrapperConstructor(qtClass)
generateDestructor(qtClass)
}
generators.add {
if (qtClass.hasCopyMethod) generateCopyOperator(qtClass)
generateMoveOperator(qtClass)
}
if (!methods.isEmpty()) generators.add {
methods.forEach { m ->
generateFunction(m.name, m.parameters, m.isAsync, m.isConst, m.returnType)
}
}
classBody(qtClass.name) {
public {
// Generate constructors, methods
generators.forEachIndexed { index, generator ->
generator()
appendLine()
}
generateUnsafeKotlinPointerMethod(qtClass)
}
private {
generateKotlinDPtr(qtClass)
}
}
}
private fun StringBuilder.generateCopyConstructor(qtClass: QtClass) {
appendLine("${qtClass.name}(const ${qtClass.name} &other);")
}
private fun StringBuilder.generateMoveConstructor(qtClass: QtClass) {
appendLine("${qtClass.name}(${qtClass.name} &&other);")
}
private fun StringBuilder.generateKotlinWrapperConstructor(qtClass: QtClass) {
appendLine("${qtClass.name}(${cApi.kotlin.className(qtClass.fqName)} ptr);")
}
private fun StringBuilder.generateCopyOperator(qtClass: QtClass) {
appendLine("${qtClass.name} &operator=(const ${qtClass.name} &other);")
}
private fun StringBuilder.generateMoveOperator(qtClass: QtClass) {
appendLine("${qtClass.name} &operator=(${qtClass.name} &&other);")
}
private fun StringBuilder.generateDestructor(qtClass: QtClass) {
appendLine("~${qtClass.name}();")
}
private fun StringBuilder.generateUnsafeKotlinPointerMethod(qtClass: QtClass) {
appendLine("${cApi.kotlin.className(qtClass.fqName)} unsafeKotlinPointer() const;")
}
private fun StringBuilder.generateKotlinDPtr(qtClass: QtClass) {
appendLine("${cApi.kotlin.className(qtClass.fqName)} d_ptr;")
}
private fun StringBuilder.classBody(className: String, block: StringBuilder.() -> Unit) {
appendLine("class $className")
appendLine("{")
block()
appendLine("};")
}
private fun StringBuilder.public(block: StringBuilder.() -> Unit) = visibility("public", block)
private fun StringBuilder.private(block: StringBuilder.() -> Unit) = visibility("private", block)
private fun StringBuilder.visibility(visibilityModifier: String, block: StringBuilder.() -> Unit) {
appendLine("$visibilityModifier:")
withIndent {
block()
}
}
}
private fun String.replaceInvalidCharsForHeader(): String {
return replace(Regex("[^A-Za-z0-9_]"), "_")
}
private fun List<String>.joinUppercase(separator: String = "_"): String {
return this.joinToString(separator = separator) { it.uppercase() }
}
private val QtFile.headerGuard
get() = (namespace.components + fileName.replaceInvalidCharsForHeader() + "HPP").joinUppercase()
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать