Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Build] Initial implementation with API generation #132

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
10 changes: 9 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import tool.generator.ast.task.GenerateAst

import java.text.SimpleDateFormat

ext {
Expand All @@ -20,7 +22,7 @@ allprojects {
}

manifest {
attributes (
attributes(
'Implementation-Title': project.name,
'Implementation-Version': project.version,
'Build-Timestamp': new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(System.currentTimeMillis()),
Expand All @@ -45,3 +47,9 @@ tasks.register('buildAll') { t ->
}
}
}

tasks.register('generateAst', GenerateAst) {
headerFiles = [
file('include/imgui/imgui.h'),
]
}
18 changes: 0 additions & 18 deletions buildSrc/build.gradle

This file was deleted.

26 changes: 26 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
plugins {
groovy
`kotlin-dsl`
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
}
}

repositories {
mavenCentral()
}

dependencies {
implementation(gradleApi())
implementation(localGroovy())

implementation("com.badlogicgames.gdx:gdx-jnigen:2.4.0")
implementation("org.reflections:reflections:0.10.2")
implementation("com.lordcodes.turtle:turtle:0.6.0")

implementation("com.fasterxml.jackson.core:jackson-core:2.14.2")
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.2")
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GenerateLibs extends DefaultTask {
private final boolean isLocal = System.properties.containsKey('local')
private final boolean withFreeType = Boolean.valueOf(System.properties.getProperty('freetype', 'false'))

private final String sourceDir = project.file('src/main/java')
private final String sourceDir = project.file('src/generated/java')
private final String classpath = project.file('build/classes/java/main')
private final String jniDir = (isLocal ? project.buildDir.path : '/tmp/imgui') + '/jni'
private final String tmpFolder = (isLocal ? project.buildDir.path : '/tmp/imgui') + '/tmp'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tool.generator.api.definition

import org.reflections.Reflections
import tool.generator.api.definition.node.DefinitionNode

/**
* Interface to implement definition provider.
*/
interface Definition {
companion object {
private const val PACKAGE_POINT = "._package"
private val ROOT_PATH: String = Definition::class.java.`package`.name
val PACKAGE_PATH: String = ROOT_PATH + PACKAGE_POINT
val ROOT_REFLECTION: Reflections = Reflections(ROOT_PATH)
}

/**
* A list of all definition nodes. This is the thing which is used to render definitions.
*/
fun getNodes(): Collection<DefinitionNode>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package tool.generator.api.definition

import org.reflections.Reflections

/**
* Class collects and provides definitions map collected with the usage of reflection.
* It basically reads everything under the [tool.generator.api.definition._package] package
* and instantiates collected classes to read definitions from the map.
*/
class DefinitionMap private constructor() {
companion object {
fun create(): DefinitionMap {
return DefinitionMap().apply {
Reflections(Definition.PACKAGE_PATH)
.getSubTypesOf(Definition::class.java)
.map { it.getDeclaredConstructor().newInstance() }
.forEach { definition ->
val packageName = getPackageName(definition)
val className = definition::class.java.simpleName
packageNameToDefinition["$packageName.$className"] = definition
}
}
}
}

private val packageNameToDefinition = mutableMapOf<String, Definition>()

private fun getPackageName(definition: Definition): String {
return stripDefinitionPackageName(getDefinitionPackageName(definition))
}

private fun getDefinitionPackageName(definition: Definition): String {
return definition.javaClass.`package`.name
}

private fun stripDefinitionPackageName(apiPackageName: String): String {
return apiPackageName.removePrefix("${Definition.PACKAGE_PATH}.")
}

operator fun get(packageName: String): Definition? = packageNameToDefinition[packageName]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package tool.generator.api.definition

import tool.generator.api.definition.node.render.NodeRenderer

/**
* Renderer for [Definition] class.
*/
class DefinitionRenderer {
private val nodeRenderer = NodeRenderer()

fun render(definition: Definition): String {
return buildString {
definition.getNodes().map(nodeRenderer::render).toSet().forEach {
appendLine(it)
appendLine() // This adds an empty line between rendered nodes.
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package tool.generator.api.definition

data class DefinitionVirtualContent(
val packageName: String,
val contentName: String,
val javaDoc: String = "",
val isFinal: Boolean = false,
val type: Type = Type.CLASS,
val extends: String = "",
val implements: Set<String> = emptySet(),
) {
enum class Type {
CLASS,
ENUM
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package tool.generator.api.definition

/**
* Disables definition from generating.
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class DisableDefinition
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package tool.generator.api.definition._package.imgui

import tool.generator.api.definition.Definition
import tool.generator.api.definition._package.imgui.binding.ImGuiApi
import tool.generator.api.definition.dsl.define
import tool.generator.api.definition.dsl.defines
import tool.generator.api.definition.node.DefinitionNode
import tool.generator.api.definition.node.type.method.MethodDefinitionNode
import tool.generator.api.definition.node.type.method.ext.*
import tool.generator.api.definition.node.type.method.ext.ret.ReturnTypeGeneral

class ImGui : Definition {
companion object {
private const val API_FIELD_NAME = "api"
}

private val excludedMethods = setOf(
"preInputText",
)

override fun getNodes(): Collection<DefinitionNode> {
return defines(
define {
line(
"""
/**
* Field with generated {@link ${getApiClass()}} to use Dear ImGui API.
* Can be replaced with custom API implementation if required.
*/
public static ${getApiClass()} $API_FIELD_NAME = new ${getApiClass()}();
""".trimIndent())
},
collectImGuiApiMethods()
)
}

private fun getApiClass(): String {
return ImGuiApi::class.java.name.removePrefix(Definition.PACKAGE_PATH + '.')
}

private fun collectImGuiApiMethods(): Collection<DefinitionNode> {
return ImGuiApi().getNodes()
.filterIsInstance<MethodDefinitionNode>()
.filterNot { it.signature.isNative }
.filterNot { excludedMethods.contains(it.signature.name) }
.map { method ->
method.signature.isStatic = true
method.body.lines = listOf(
buildString {
if (method.returnType.type != ReturnTypeGeneral.VOID) {
append("return ")
}

append(API_FIELD_NAME)
append('.')
append(method.signature.name)
append('(')
append(method.signature.argsList.joinToString { it.name })
append(')')
append(';')
}
)

method
}
}
}
Loading
Loading