Skip to content
This repository was archived by the owner on Dec 19, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'temurin'

- name: Build with Gradle
Expand Down
34 changes: 29 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
/.gradle/
/.idea/
/build/
.gradle
**/build/
!src/**/build/

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties

# Cache of project
.gradletasknamecache

# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath

# IDEA
.idea

# HeaderOutput files
/header/
/originalData.json
/old
/old_
/config.toml
/config.json
/declareMap.json
16 changes: 16 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.9.0"
Expand All @@ -19,13 +20,19 @@ application {

repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}

dependencies {
implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-cli:0.3.5")
implementation("org.apache.logging.log4j:log4j-api:2.20.0")
implementation("org.apache.logging.log4j:log4j-core:2.20.0")
implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.20.0")
implementation("io.github.oshai:kotlin-logging-jvm:5.0.0")
implementation("cc.ekblad:4koma:1.2.0")

testImplementation(platform("org.junit:junit-bom:5.9.2"))
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
Expand All @@ -39,4 +46,13 @@ tasks.getByName<ShadowJar>("shadowJar") {
minimize()
}

tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
}

tasks.withType<JavaCompile> {
sourceCompatibility = JavaVersion.VERSION_17.toString()
targetCompatibility = JavaVersion.VERSION_17.toString()
}

tasks.build { dependsOn(tasks.named("shadowJar")) }
18 changes: 0 additions & 18 deletions config.json

This file was deleted.

56 changes: 31 additions & 25 deletions src/main/kotlin/com/liteldev/headeroutput/HeaderGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ package com.liteldev.headeroutput

import com.liteldev.headeroutput.config.GeneratorConfig
import com.liteldev.headeroutput.entity.BaseType
import io.github.oshai.kotlinlogging.KotlinLogging
import java.io.File

object HeaderGenerator {

const val HEADER_SUFFIX = "h"
private const val PREDEFINE_FILE_NAME = "_HeaderOutputPredefine.$HEADER_SUFFIX"

private val HEADER_TEMPLATE = """
#pragma once


""".trimIndent()
private const val HEADER_TEMPLATE = "#pragma once\n\n"
private val logger = KotlinLogging.logger { }

fun generate() {
File(GeneratorConfig.generatePath).mkdirs()
Expand All @@ -36,16 +33,15 @@ object HeaderGenerator {
} else {
sb.appendLine(type.generateTypeDefine())
}
val file = File(GeneratorConfig.generatePath, type.getPath())
val file = File(GeneratorConfig.generatePath, type.path)
file.parentFile.mkdirs()
file.writeText(
HEADER_TEMPLATE + """
#include "${type.getPath().relativePathTo(PREDEFINE_FILE_NAME)}"

// auto generated inclusion list
${type.includeList.sorted().joinToString("\n") { "#include \"$it\"" }}


""".trimIndent() + sb.toString()
buildString {
append(HEADER_TEMPLATE)
append("#include \"${type.path.relativePathTo(PREDEFINE_FILE_NAME)}\"\n\n")
append(generateIncludes(type))
append(sb.toString())
}
)
}
}
Expand All @@ -54,26 +50,36 @@ ${type.includeList.sorted().joinToString("\n") { "#include \"$it\"" }}
private fun generateNamespace(type: BaseType) {
assert(type.isNamespace()) { "${type.name} is not namespace" }

val file = File(GeneratorConfig.generatePath, type.getPath())
val file = File(GeneratorConfig.generatePath, type.path)
file.parentFile.mkdirs()
file.writeText(
HEADER_TEMPLATE + """
#include "${type.getPath().relativePathTo(PREDEFINE_FILE_NAME)}"

// auto generated inclusion list
${type.includeList.sorted().joinToString("\n") { "#include \"$it\"" }}


""".trimIndent() + type.generateTypeDefine()
buildString {
append(HEADER_TEMPLATE)
append("#include \"${type.path.relativePathTo(PREDEFINE_FILE_NAME)}\"\n\n")
append(generateIncludes(type))
append(type.generateTypeDefine())
}
)

if (type.innerTypes.isNotEmpty()) {
File(GeneratorConfig.generatePath, type.getPath().removeSuffix(".$HEADER_SUFFIX")).also { it.mkdirs() }
type.innerTypes.forEach { innerType ->
generate(innerType)
}
}
}

private fun generateIncludes(type: BaseType): String {
if (type.includeList.isEmpty()) {
return ""
}
return buildString {
append("// auto generated inclusion list\n")
append(type.includeList.sorted()
.joinToString("\n") { "#include \"$it\"" })
append("\n\n")
}
}

private fun createPredefineFile() {
val file = File(GeneratorConfig.generatePath, PREDEFINE_FILE_NAME)
file.writeText(
Expand Down
39 changes: 23 additions & 16 deletions src/main/kotlin/com/liteldev/headeroutput/HeaderOutput.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.liteldev.headeroutput

import com.liteldev.headeroutput.config.GeneratorConfig
import com.liteldev.headeroutput.config.origindata.MemberTypeData
import com.liteldev.headeroutput.config.origindata.StorageClassType
import com.liteldev.headeroutput.config.origindata.SymbolNodeType
import com.liteldev.headeroutput.config.origindata.TypeData
import com.liteldev.headeroutput.data.MemberTypeData
import com.liteldev.headeroutput.data.StorageClassType
import com.liteldev.headeroutput.data.SymbolNodeType
import com.liteldev.headeroutput.data.TypeData
import com.liteldev.headeroutput.entity.BaseType
import com.liteldev.headeroutput.entity.ClassType
import com.liteldev.headeroutput.entity.NamespaceType
import com.liteldev.headeroutput.entity.StructType
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.cli.ArgParser
import kotlinx.cli.ArgType
import kotlinx.cli.default
Expand All @@ -19,6 +21,8 @@ import java.io.File
private val json = Json { explicitNulls = false }

object HeaderOutput {
private val logger = KotlinLogging.logger { }

private lateinit var originData: JsonObject
private lateinit var classNameList: MutableSet<String>
private lateinit var structNameList: MutableSet<String>
Expand All @@ -39,39 +43,44 @@ object HeaderOutput {
TypeManager.initInclusionList()

HeaderGenerator.generate()

logger.warn { "These types are not sorted by any rules or declare map: ${BaseType.notSortedTypes.sorted()}" }
}

private fun readCommandLineArgs(args: Array<String>): Boolean {
val parser = ArgParser("HeaderOutput")
val configPath by parser.option(ArgType.String, "config", "c", "The config file path").default("./config.json")
val configPath by parser.option(ArgType.String, "config", "c", "The config file path").default("./config.toml")
val declareMapFile by parser.option(ArgType.String, "declare-map", "d", "The declare map file path")
.default("./declareMap.json")
val generatePath by parser.option(ArgType.String, "output-dir", "o", "The header output path")
.default("./header")
val jsonPath by parser.option(ArgType.String, "input", "i", "The original data json file path")
.default("./header.json")
.default("./originalData.json")
parser.parse(args)
GeneratorConfig.configPath = configPath
GeneratorConfig.generatePath = generatePath
GeneratorConfig.jsonPath = jsonPath
GeneratorConfig.declareMapPath = declareMapFile
if (!File(GeneratorConfig.configPath).isFile) {
println("Invalid config file path")
logger.error { "Invalid config file path" }
return false
}
if (!File(GeneratorConfig.generatePath).isDirectory) {
if (!File(GeneratorConfig.generatePath).mkdirs()) {
println("Fail to create generate header files path")
logger.error { "Fail to create generate header files path" }
return false
}
}
if (!File(GeneratorConfig.jsonPath).isFile) {
println("Invalid original data json file path")
logger.error { "Invalid original data json file path" }
return false
}
return true
}


private fun loadOriginData() {
println("Loading origin data...")
logger.info { "Loading origin data..." }
val configText = File(GeneratorConfig.jsonPath).readText()
originData = Json.parseToJsonElement(configText).jsonObject
typeDataMap = originData["classes"]?.jsonObject?.mapValues { entry ->
Expand All @@ -96,7 +105,7 @@ object HeaderOutput {

private fun constructTypes() {
val notIdentifiedTypes = mutableSetOf<String>()
println("Loading types...")
logger.info { "Loading types..." }
typeDataMap
.filterNot { (k, _) -> GeneratorConfig.isExcludedFromGeneration(k) }
.forEach { (typeName, type) ->
Expand All @@ -113,11 +122,11 @@ object HeaderOutput {
}
)
}
println("Warning: can not determine these types' type. Treat them as class type\n$notIdentifiedTypes")
logger.warn { "Can not determine these types' type. Treat them as class type\n$notIdentifiedTypes" }
}

private fun loadIdentifiedTypes() {
println("Loading identifier...")
logger.info { "Loading identifier..." }
val identifier = originData["identifier"]?.jsonObject
classNameList =
(identifier?.get("class")?.jsonArray).orEmpty().map { it.jsonPrimitive.content }.toMutableSet()
Expand All @@ -135,9 +144,7 @@ object HeaderOutput {
}

if (referencedTypes.isNotEmpty()) {
println(
"Warning: these types are referenced from other types but not identified. Treat them as class type\n$referencedTypes"
)
logger.warn { "These types are referenced from other types but not identified. Treat them as class type\n$referencedTypes" }
classNameList.addAll(referencedTypes)
}
}
Expand Down
19 changes: 11 additions & 8 deletions src/main/kotlin/com/liteldev/headeroutput/TypeManager.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package com.liteldev.headeroutput

import com.liteldev.headeroutput.config.GeneratorConfig
import com.liteldev.headeroutput.config.origindata.TypeData
import com.liteldev.headeroutput.entity.BaseType
import com.liteldev.headeroutput.data.TypeData
import com.liteldev.headeroutput.entity.*
import com.liteldev.headeroutput.entity.BaseType.TypeKind
import com.liteldev.headeroutput.entity.ClassType
import com.liteldev.headeroutput.entity.EnumType
import com.liteldev.headeroutput.entity.StructType
import io.github.oshai.kotlinlogging.KotlinLogging

object TypeManager {
private val logger = KotlinLogging.logger { }
private val typeMap = hashMapOf<String, BaseType>()

val nestingMap = hashMapOf<String, BaseType>()
val template = hashSetOf<String>()
val template = hashMapOf<String, String>()

fun addType(fullName: String, type: BaseType) {
typeMap[fullName] = type
Expand Down Expand Up @@ -67,7 +66,7 @@ object TypeManager {
allNestingType.addAll(nestingMap.values)
val allType = typeMap.values.toSet()
val notNestingType = allType - allNestingType
println("Warning: these class has no nesting relationship\n${notNestingType.map { it.name }}")
logger.warn { "These class has no nesting relationship\n${notNestingType.map { it.name }}" }
// generate a dummy class for each not nesting class
notNestingType.forEach {
val parentName = it.name.substringBeforeLast("::")
Expand All @@ -90,13 +89,17 @@ object TypeManager {
return null
}

val dummyClass = when (type) {
var dummyClass = when (type) {
TypeKind.CLASS -> ClassType(name, TypeData.empty(), template.contains(name))
TypeKind.STRUCT -> StructType(name, TypeData.empty(), template.contains(name))
TypeKind.ENUM -> EnumType(name)
TypeKind.NAMESPACE -> NamespaceType(name, TypeData.empty())
else -> throw IllegalArgumentException("type $type is not supported")
}

if (type == TypeKind.CLASS && typeMap.any { (n, t) -> n.startsWith(dummyClass.name + "::") && t.isNamespace() })
dummyClass = NamespaceType(name, TypeData.empty())

if (name.contains("::")) {
val parentName = name.substringBeforeLast("::")
if (!hasType(parentName)) {
Expand Down
Loading