Skip to content

Commit

Permalink
feat(generator): [NFD] Update generator; add static invocation
Browse files Browse the repository at this point in the history
  • Loading branch information
squid233 committed Dec 2, 2024
1 parent 42e75d9 commit 4cf3be5
Show file tree
Hide file tree
Showing 15 changed files with 959 additions and 183 deletions.
154 changes: 150 additions & 4 deletions generators/nfd/src/main/java/overrungl/nfd/NFDGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ package overrungl.nfd
import com.palantir.javapoet.*
import overrungl.gen.*
import java.lang.foreign.SegmentAllocator
import java.nio.file.Files
import javax.lang.model.element.Modifier
import kotlin.io.path.Path

val nfdfiltersize_t by int
val nfdversion_t by size_t
val nfdresult_t by int
val const_nfdpathset_t_ptr_ptr = address c "const nfdpathset_t**"
val const_nfdpathset_t_ptr = address c "const nfdpathset_t*"
val nfdpathsetsize_t_ptr = address c "nfdpathsetsize_t*"
val nfdpathsetsize_t = jlong c "nfdpathsetsize_t"
val nfdpathsetenum_t_ptr = address c "nfdpathsetenum_t*"

class CharVariant(
val uppercaseName: String,
Expand Down Expand Up @@ -322,7 +328,7 @@ fun main() {
"""
Multiple file open dialog
<p>
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree${variant.uppercaseName}} if this function
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree} if this function
returns NFD_OKAY.
""".trimIndent()
)
Expand Down Expand Up @@ -358,7 +364,7 @@ fun main() {
"""
Multiple file open dialog, with additional parameters.
<p>
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree${variant.uppercaseName}} if this function
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree} if this function
returns NFD_OKAY. See documentation of {@link NFDOpenDialog${variant.uppercaseName}Args} for details.
""".trimIndent()
)
Expand Down Expand Up @@ -504,7 +510,7 @@ fun main() {
"""
Select multiple folder dialog
<p>
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree${variant.uppercaseName}} if this function
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree} if this function
returns NFD_OKAY.
""".trimIndent()
)
Expand Down Expand Up @@ -540,7 +546,7 @@ fun main() {
"""
Multiple file open dialog, with additional parameters.
<p>
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree${variant.uppercaseName}} if this function
It is the caller's responsibility to free {@code outPaths} via {@link #pathSetFree} if this function
returns NFD_OKAY. See documentation of {@link NFDPickFolder${variant.uppercaseName}Args} for details.
""".trimIndent()
)
Expand Down Expand Up @@ -574,5 +580,145 @@ fun main() {
typeSpecBuilder.addMethod(getError_.toBuilder().setName("getError").returns(String::class.java).build())

"clearError"(void, entrypoint = "NFD_ClearError", javadoc = { add("Clear the error.") })

"pathSetGetCount"(
nfdresult_t,
const_nfdpathset_t_ptr("pathSet"),
nfdpathsetsize_t_ptr("count"),
entrypoint = "NFD_PathSet_GetCount",
javadoc = {
add(
"""
Get the number of entries stored in pathSet.
<p>
Note: some paths might be invalid (NFD_ERROR will be returned by NFD_PathSet_GetPath),
so we might not actually have this number of usable paths.
""".trimIndent()
)
}
)

fun pathSetGetPath(variant: CharVariant, pathType: String) {
"pathSetGetPath${variant.uppercaseName}"(
nfdresult_t,
const_nfdpathset_t_ptr("pathSet"),
nfdpathsetsize_t("index"),
variant.nfdchar_t_ptr_ptr("outPath"),
entrypoint = "NFD_PathSet_GetPath${variant.uppercaseName}",
javadoc = {
add(
"""
Get the $pathType path at offset index.
<p>
It is the caller's responsibility to free `outPath` via {@link #pathSetFreePath${variant.uppercaseName}} if this function
returns NFD_OKAY.
""".trimIndent()
)
}
)
}
pathSetGetPath(Nchar, "native")
pathSetGetPath(U8char, "UTF-8")

fun pathSetFreePath(variant: CharVariant) {
"pathSetFreePath${variant.uppercaseName}"(
void,
variant.const_nfdchar_t_ptr("filePath"),
entrypoint = "NFD_PathSet_FreePath${variant.uppercaseName}",
javadoc = { add("Free the path gotten by {@link #pathSetGetPath${variant.uppercaseName}}.") }
)
}
pathSetFreePath(Nchar)
pathSetFreePath(U8char)

"pathSetGetEnum"(
nfdresult_t,
const_nfdpathset_t_ptr("pathSet"),
nfdpathsetenum_t_ptr("outEnumerator"),
entrypoint = "NFD_PathSet_GetEnum",
javadoc = {
add(
"""
Gets an enumerator of the path set.
<p>
It is the caller's responsibility to free {@code enumerator} via {@link #pathSetFreeEnum}
if this function returns NFD_OKAY, and it should be freed before freeing the pathset.
""".trimIndent()
)
}
)
"pathSetFreeEnum"(
void,
nfdpathsetenum_t_ptr("enumerator"),
entrypoint = "NFD_PathSet_FreeEnum",
javadoc = { add("Frees an enumerator of the path set.") }
)

fun pathSetEnumNext(variant: CharVariant) {
"pathSetEnumNext${variant.uppercaseName}"(
nfdresult_t,
nfdpathsetenum_t_ptr("enumerator"),
variant.nfdchar_t_ptr_ptr("outPath"),
entrypoint = "NFD_PathSet_EnumNext${variant.uppercaseName}",
javadoc = {
add(
"""
Gets the next item from the path set enumerator.
<p>
If there are no more items, then *outPaths will be set to null.
It is the caller's responsibility to free {@code *outPath} via {@link #pathSetFreePath${variant.uppercaseName}}
if this function returns NFD_OKAY and {@code *outPath} is not null.
""".trimIndent()
)
}
)
}
pathSetEnumNext(Nchar)
pathSetEnumNext(U8char)

"pathSetFree"(
void,
const_nfdpathset_t_ptr("pathSet"),
entrypoint = "NFD_PathSet_Free",
javadoc = { add("Free the pathSet") }
)
}.also {
// TODO
val path = Path("overrungl", "nfd", "NFDstatic.java")
val content = Files.readString(path)
check(content.indexOf(GENERATOR_BEGIN) != -1 && content.indexOf(GENERATOR_END) != -1) { "Generator region not found" }
val split = content.split(GENERATOR_BEGIN, GENERATOR_END)
val codeBuilder = CodeBlock.builder()
it.fieldSpecs().forEach { s ->
codeBuilder.add(
"$1L",
FieldSpec.builder(s.type(), s.name())
.addJavadoc(s.javadoc())
.addModifiers(*s.modifiers().toTypedArray())
.initializer("$1N.$2N", "CNFD", s).build()
)
}
it.methodSpecs().forEach { s ->
codeBuilder.add(
"$1L",
MethodSpec.methodBuilder(s.name())
.addJavadoc(s.javadoc())
.addAnnotations(s.annotations())
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(s.returnType())
.addParameters(s.parameters())
.addStatement(
"${if (s.returnType() == TypeName.VOID) "" else "return "}getInstance().$1N($2L)",
s,
s.parameters().joinToString(separator = ", ") { ps -> ps.name() })
.build()
)
}
Files.writeString(
path,
"${split[0]}$GENERATOR_BEGIN\n${
codeBuilder.build().toString().prependIndent(" ")
}\n $GENERATOR_END${split[2]}"
)
}
}
3 changes: 3 additions & 0 deletions generators/src/main/kotlin/overrungl/gen/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
This file is auto-generated. DO NOT EDIT!"""

const val GENERATOR_BEGIN = "// ---[BEGIN GENERATOR BEGIN]---"
const val GENERATOR_END = "// ---[END GENERATOR END]---"
32 changes: 13 additions & 19 deletions generators/src/main/kotlin/overrungl/gen/CustomTypeSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import kotlin.reflect.KProperty
data class CustomTypeSpec(
val carrier: TypeName,
val cType: String? = null,
val canonicalType: String? = null,
val layout: CodeBlock
) {
infix fun c(cType: String?): CustomTypeSpec = copy(cType = cType)
Expand All @@ -36,8 +35,6 @@ data class CustomTypeSpec(

val MemorySegment_: ClassName = ClassName.get(MemorySegment::class.java)

val CanonicalLayouts = ClassName.get("overrun.marshal", "CanonicalLayouts")
val CanonicalType = ClassName.get("overrun.marshal.gen", "CanonicalType")
val CType = ClassName.get("overrun.marshal.gen", "CType")
val DirectAccess = ClassName.get("overrun.marshal", "DirectAccess")
val Entrypoint = ClassName.get("overrun.marshal.gen", "Entrypoint")
Expand All @@ -49,24 +46,9 @@ val Struct = ClassName.get("overrun.marshal.struct", "Struct")
val StructAllocator = ClassName.get("overrun.marshal.struct", "StructAllocator")
val Unmarshal = ClassName.get("overrun.marshal", "Unmarshal")

private fun cPrimitive(carrier: TypeName, name: String, layoutName: String): CustomTypeSpec =
CustomTypeSpec(carrier, name, name, CodeBlock.of("\$T.\$L", CanonicalLayouts, layoutName))

private fun javaPrimitive(carrier: TypeName, layoutName: String): CustomTypeSpec =
CustomTypeSpec(carrier, layout = CodeBlock.of("\$T.\$L", ValueLayout::class.java, layoutName))

val bool = cPrimitive(TypeName.BOOLEAN, "bool", "BOOL")
val char = cPrimitive(TypeName.BYTE, "char", "CHAR")
val short = cPrimitive(TypeName.SHORT, "short", "SHORT")
val int = cPrimitive(TypeName.INT, "int", "INT")
val long = cPrimitive(TypeName.LONG, "long", "LONG")
val long_long = cPrimitive(TypeName.LONG, "long long", "LONG_LONG")
val float = cPrimitive(TypeName.FLOAT, "float", "FLOAT")
val double = cPrimitive(TypeName.DOUBLE, "double", "DOUBLE")
val void_ptr = cPrimitive(MemorySegment_, "void*", "VOID_POINTER")
val size_t = cPrimitive(TypeName.LONG, "size_t", "SIZE_T")
val wchar_t = cPrimitive(TypeName.CHAR, "wchar_t", "WCHART_T")

val jboolean = javaPrimitive(TypeName.BOOLEAN, "JAVA_BOOLEAN")
val jchar = javaPrimitive(TypeName.CHAR, "JAVA_CHAR")
val jbyte = javaPrimitive(TypeName.BYTE, "JAVA_BYTE")
Expand All @@ -78,6 +60,18 @@ val jdouble = javaPrimitive(TypeName.DOUBLE, "JAVA_DOUBLE")
val void = CustomTypeSpec(TypeName.VOID, layout = CodeBlock.of(""))

val address = javaPrimitive(MemorySegment_, "ADDRESS")
val string = CustomTypeSpec(MemorySegment_, null, null, CodeBlock.of("\$T.STR_LAYOUT", Unmarshal))
val string = CustomTypeSpec(MemorySegment_, null, CodeBlock.of("\$T.STR_LAYOUT", Unmarshal))

val bool = jboolean c "bool"
val char = jbyte c "char"
val short = jshort c "short"
val int = jint c "int"
val long = jlong c "long"
val long_long = jlong c "long long"
val float = jfloat c "float"
val double = jdouble c "double"
val void_ptr = address c "void*"
val size_t = jlong c "size_t"
val wchar_t = jint c "wchar_t"

val const_char_ptr = string c "const char*"
14 changes: 5 additions & 9 deletions generators/src/main/kotlin/overrungl/gen/DowncallSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ class DowncallSpec(private val packageName: String, className: String, javadoc:
.returns(returnType.carrier)
.also {
it.addModifiers(if (default) Modifier.DEFAULT else Modifier.ABSTRACT)
returnType.canonicalType?.also { s ->
it.addAnnotation(
AnnotationSpec.builder(CanonicalType).addMember("value", "$1S", s).build()
)
}
returnType.cType?.also { s ->
it.addAnnotation(
AnnotationSpec.builder(CType).addMember("value", "$1S", s).build()
Expand All @@ -98,8 +93,9 @@ class DowncallSpec(private val packageName: String, className: String, javadoc:
.also(typeSpecBuilder::addMethod)
}

fun generate() {
JavaFile.builder(packageName, typeSpecBuilder.build()).addFileComment(fileHeader).build().writeTo(Path("."))
fun generate(): TypeSpec {
return typeSpecBuilder.build()
.also { JavaFile.builder(packageName, it).addFileComment(fileHeader).build().writeTo(Path(".")) }
}
}

Expand All @@ -108,8 +104,8 @@ fun downcall(
className: String,
javadoc: (JavadocProvider.() -> Unit)? = null,
action: DowncallSpec.() -> Unit
) {
DowncallSpec(packageName, className, javadoc?.let { JavadocProvider().also(it) })
): TypeSpec {
return DowncallSpec(packageName, className, javadoc?.let { JavadocProvider().also(it) })
.also(action)
.generate()
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ class NamedParameterSpec(val type: CustomTypeSpec, val name: String, val javadoc

fun toSpec(): ParameterSpec = ParameterSpec.builder(type.carrier, name)
.also {
type.canonicalType?.also { s ->
it.addAnnotation(
AnnotationSpec.builder(CanonicalType).addMember("value", "$1S", s).build()
)
}
type.cType?.also { s ->
it.addAnnotation(
AnnotationSpec.builder(CType).addMember("value", "$1S", s).build()
Expand Down
1 change: 0 additions & 1 deletion generators/src/main/kotlin/overrungl/gen/StructSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class StructSpec(
CustomTypeSpec(
MemorySegment_,
cType,
null,
CodeBlock.of("\$T.OF.layout()", selfClassName)
)
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jdkEnablePreview=true
#jdkEarlyAccessDoc=jdk23
kotlinTargetJdkVersion=21

overrunMarshalVersion=0.1.0-alpha.36-jdk23
overrunMarshalVersion=0.1.0-alpha.37-jdk23
overrunPlatformVersion=1.0.0
jomlVersion=1.10.8
junitVersion=5.11.0
Loading

0 comments on commit 4cf3be5

Please sign in to comment.