<commit_before>/*
 * Copyright LWJGL. All rights reserved.
 * License terms: https://www.lwjgl.org/license
 */
package org.lwjgl.generator

import java.io.*
import java.lang.Math.*
import java.nio.file.*

const val EXT_FLAG = ""

enum class CallingConvention(val method: String) {
    DEFAULT("invoke"),
    STDCALL("call") // __stdcall on Windows, default on other systems
}

enum class APICapabilities {
    NONE,
    JNI_CAPABILITIES,
    JAVA_CAPABILITIES,
    PARAM_CAPABILITIES
}

/**
 * The Generator can be customized with binding-specific overrides using this class. This class must implemented for bindings that are loaded dynamically. It
 * is not necessary for libraries that are static compiled/linked into the LWJGL natives.
 */
abstract class APIBinding(
    packageName: String,
    className: String,
    val apiCapabilities: APICapabilities = APICapabilities.NONE,
    val callingConvention: CallingConvention = CallingConvention.STDCALL
) : GeneratorTarget(packageName, className) {

    init {
        javaImport(
            "org.lwjgl.system.*",
            "java.util.Set"
        )
    }

    private val _classes: MutableList<NativeClass> = ArrayList()

    protected fun getClasses(
        comparator: (NativeClass, NativeClass) -> Int = { o1, o2 -> o1.templateName.compareTo(o2.templateName, ignoreCase = true) }
    ): List<NativeClass> {
        val classes = ArrayList(_classes)
        classes.sortWith(Comparator { o1, o2 -> comparator(o1, o2) })
        return classes
    }

    fun addClass(clazz: NativeClass) {
        _classes.add(clazz)
    }

    override fun getLastModified(root: String): Long = max(
        super.getLastModified(root),
        Paths.get(root, "templates").lastModified()
    )

    abstract fun generateFunctionAddress(writer: PrintWriter, function: Func)

    abstract fun PrintWriter.generateFunctionSetup(nativeClass: NativeClass)

    // OVERRIDES

    open fun getFunctionOrdinal(function: Func): Int = 0

    /** Can be overriden to generate binding-specific alternative methods. */
    open fun generateAlternativeMethods(
        writer: PrintWriter,
        function: Func,
        transforms: MutableMap<QualifiedType, Transform>
    ) = Unit

    /** Can be overriden to generate binding-specific javadoc. If this function returns false, the default javadoc will be generated. */
    open fun printCustomJavadoc(writer: PrintWriter, function: Func, documentation: String) = false

    /** Can be overriden to implement a custom condition for checking the function address. */
    open fun shouldCheckFunctionAddress(function: Func) = apiCapabilities.ordinal > 1

    /** Can be overriden to add custom parameter checks. */
    open fun addParameterChecks(
        checks: MutableList<String>,
        mode: GenerationMode,
        parameter: Parameter,
        hasTransform: Parameter.(FunctionTransform<Parameter>) -> Boolean
    ) = Unit

}

/** An APIBinding without an associated capabilities class.  */
abstract class SimpleBinding(
    private val libraryExpression: String,
    callingConvention: CallingConvention
) : APIBinding("n/a", "n/a", callingConvention = callingConvention) {
    override fun PrintWriter.generateJava() = Unit
    override fun generateFunctionAddress(writer: PrintWriter, function: Func) {
        writer.println("$t${t}long ${if (function has Address) RESULT else FUNCTION_ADDRESS} = Functions.${function.simpleName};")
    }

    protected fun PrintWriter.generateFunctionsClass(nativeClass: NativeClass) {
        val bindingFunctions = nativeClass.functions.filter { !it.hasExplicitFunctionAddress && !it.has<Macro>() }
        if (bindingFunctions.isEmpty())
            return

        val alignment = bindingFunctions.map { it.simpleName.length }.max()!!

        println("""
    public static final class Functions {

        private Functions() {}

        /** Function address. */
        public static final long
            ${bindingFunctions.joinToString(separator = ",\n$t$t$t", postfix = ";") {
            "${it.simpleName}${" ".repeat(alignment - it.simpleName.length)} = ${if (it has IgnoreMissing)
                "$libraryExpression.getFunctionAddress(${it.functionAddress})"
            else
                "apiGetFunctionAddress($libraryExpression, ${it.functionAddress})"}"
        }}

    }""")
    }
}

/** Creates a simple APIBinding that stores the shared library and function pointers inside the binding class. The shared library is never unloaded. */
fun simpleBinding(
    libraryName: String,
    libraryExpression: String = "\"$libraryName\"",
    callingConvention: CallingConvention = CallingConvention.DEFAULT,
    bundledWithLWJGL: Boolean = false
) = object : SimpleBinding(libraryName.toUpperCase(), callingConvention) {
    override fun PrintWriter.generateFunctionSetup(nativeClass: NativeClass) {
        val libraryReference = libraryName.toUpperCase()

        println("\n${t}private static final SharedLibrary $libraryReference = Library.loadNative(${nativeClass.className}.class, $libraryExpression${if (bundledWithLWJGL) ", true" else ""});\n")
        print("$t/** Contains the function pointers loaded from the $libraryName {@link SharedLibrary}. */")
        generateFunctionsClass(nativeClass)
        println("""
    /** Returns the $libraryName {@link SharedLibrary}. */
    public static SharedLibrary getLibrary() {
        return $libraryReference;
    }""")
    }
}

/** Creates a simple APIBinding that delegates function pointer loading to this APIBinding. */
fun APIBinding.delegate(
    libraryExpression: String
) = object : SimpleBinding(libraryExpression, callingConvention) {
    override fun PrintWriter.generateFunctionSetup(nativeClass: NativeClass) {
        print("\n$t/** Contains the function pointers loaded from {@code $libraryExpression}. */")
        generateFunctionsClass(nativeClass)
    }
}

// TODO: Remove if KT-7859 is fixed.
private fun APIBinding.generateFunctionSetup(writer: PrintWriter, nativeClass: NativeClass) = writer.generateFunctionSetup(nativeClass)

class NativeClass(
    packageName: String,
    className: String,
    nativeSubPath: String,
    val templateName: String = className,
    val prefix: String,
    val prefixMethod: String,
    val prefixConstant: String,
    val prefixTemplate: String,
    val postfix: String,
    val binding: APIBinding?,
    val library: String?
) : GeneratorTargetNative(packageName, className, nativeSubPath) {
    companion object {
        private val JDOC_LINK_PATTERN = """(?<!\p{javaJavaIdentifierPart}|[@#])#(\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*)""".toRegex()
    }
<commit_msg>fix(generator): formatting and javadoc in simple bindings<commit_after>/*
 * Copyright LWJGL. All rights reserved.
 * License terms: https://www.lwjgl.org/license
 */
package org.lwjgl.generator

import java.io.*
import java.lang.Math.*
import java.nio.file.*

const val EXT_FLAG = ""

enum class CallingConvention(val method: String) {
    DEFAULT("invoke"),
    STDCALL("call") // __stdcall on Windows, default on other systems
}

enum class APICapabilities {
    NONE,
    JNI_CAPABILITIES,
    JAVA_CAPABILITIES,
    PARAM_CAPABILITIES
}

/**
 * The Generator can be customized with binding-specific overrides using this class. This class must implemented for bindings that are loaded dynamically. It
 * is not necessary for libraries that are static compiled/linked into the LWJGL natives.
 */
abstract class APIBinding(
    packageName: String,
    className: String,
    val apiCapabilities: APICapabilities = APICapabilities.NONE,
    val callingConvention: CallingConvention = CallingConvention.STDCALL
) : GeneratorTarget(packageName, className) {

    init {
        javaImport(
            "org.lwjgl.system.*",
            "java.util.Set"
        )
    }

    private val _classes: MutableList<NativeClass> = ArrayList()

    protected fun getClasses(
        comparator: (NativeClass, NativeClass) -> Int = { o1, o2 -> o1.templateName.compareTo(o2.templateName, ignoreCase = true) }
    ): List<NativeClass> {
        val classes = ArrayList(_classes)
        classes.sortWith(Comparator { o1, o2 -> comparator(o1, o2) })
        return classes
    }

    fun addClass(clazz: NativeClass) {
        _classes.add(clazz)
    }

    override fun getLastModified(root: String): Long = max(
        super.getLastModified(root),
        Paths.get(root, "templates").lastModified()
    )

    abstract fun generateFunctionAddress(writer: PrintWriter, function: Func)

    abstract fun PrintWriter.generateFunctionSetup(nativeClass: NativeClass)

    // OVERRIDES

    open fun getFunctionOrdinal(function: Func): Int = 0

    /** Can be overriden to generate binding-specific alternative methods. */
    open fun generateAlternativeMethods(
        writer: PrintWriter,
        function: Func,
        transforms: MutableMap<QualifiedType, Transform>
    ) = Unit

    /** Can be overriden to generate binding-specific javadoc. If this function returns false, the default javadoc will be generated. */
    open fun printCustomJavadoc(writer: PrintWriter, function: Func, documentation: String) = false

    /** Can be overriden to implement a custom condition for checking the function address. */
    open fun shouldCheckFunctionAddress(function: Func) = apiCapabilities.ordinal > 1

    /** Can be overriden to add custom parameter checks. */
    open fun addParameterChecks(
        checks: MutableList<String>,
        mode: GenerationMode,
        parameter: Parameter,
        hasTransform: Parameter.(FunctionTransform<Parameter>) -> Boolean
    ) = Unit

}

/** An APIBinding without an associated capabilities class.  */
abstract class SimpleBinding(
    private val libraryExpression: String,
    callingConvention: CallingConvention
) : APIBinding("n/a", "n/a", callingConvention = callingConvention) {
    override fun PrintWriter.generateJava() = Unit
    override fun generateFunctionAddress(writer: PrintWriter, function: Func) {
        writer.println("$t${t}long ${if (function has Address) RESULT else FUNCTION_ADDRESS} = Functions.${function.simpleName};")
    }

    protected fun PrintWriter.generateFunctionsClass(nativeClass: NativeClass, javadoc: String) {
        val bindingFunctions = nativeClass.functions.filter { !it.hasExplicitFunctionAddress && !it.has<Macro>() }
        if (bindingFunctions.isEmpty())
            return

        print(javadoc)

        val alignment = bindingFunctions.map { it.simpleName.length }.max()!!

        println("""
    public static final class Functions {

        private Functions() {}

        /** Function address. */
        public static final long
            ${bindingFunctions.joinToString(separator = ",\n$t$t$t", postfix = ";") {
            "${it.simpleName}${" ".repeat(alignment - it.simpleName.length)} = ${if (it has IgnoreMissing)
                "$libraryExpression.getFunctionAddress(${it.functionAddress})"
            else
                "apiGetFunctionAddress($libraryExpression, ${it.functionAddress})"}"
        }}

    }""")
    }
}

/** Creates a simple APIBinding that stores the shared library and function pointers inside the binding class. The shared library is never unloaded. */
fun simpleBinding(
    libraryName: String,
    libraryExpression: String = "\"$libraryName\"",
    callingConvention: CallingConvention = CallingConvention.DEFAULT,
    bundledWithLWJGL: Boolean = false
) = object : SimpleBinding(libraryName.toUpperCase(), callingConvention) {
    override fun PrintWriter.generateFunctionSetup(nativeClass: NativeClass) {
        val libraryReference = libraryName.toUpperCase()

        println("\n${t}private static final SharedLibrary $libraryReference = Library.loadNative(${nativeClass.className}.class, $libraryExpression${if (bundledWithLWJGL) ", true" else ""});")
        generateFunctionsClass(nativeClass, "\n$t/** Contains the function pointers loaded from the $libraryName {@link SharedLibrary}. */")
        println("""
    /** Returns the $libraryName {@link SharedLibrary}. */
    public static SharedLibrary getLibrary() {
        return $libraryReference;
    }""")
    }
}

/** Creates a simple APIBinding that delegates function pointer loading to this APIBinding. */
fun APIBinding.delegate(
    libraryExpression: String
) = object : SimpleBinding(libraryExpression, callingConvention) {
    override fun PrintWriter.generateFunctionSetup(nativeClass: NativeClass) {
        generateFunctionsClass(nativeClass, "\n$t/** Contains the function pointers loaded from {@code $libraryExpression}. */")
    }
}

// TODO: Remove if KT-7859 is fixed.
private fun APIBinding.generateFunctionSetup(writer: PrintWriter, nativeClass: NativeClass) = writer.generateFunctionSetup(nativeClass)

class NativeClass(
    packageName: String,
    className: String,
    nativeSubPath: String,
    val templateName: String = className,
    val prefix: String,
    val prefixMethod: String,
    val prefixConstant: String,
    val prefixTemplate: String,
    val postfix: String,
    val binding: APIBinding?,
    val library: String?
) : GeneratorTargetNative(packageName, className, nativeSubPath) {
    companion object {
        private val JDOC_LINK_PATTERN = """(?<!\p{javaJavaIdentifierPart}|[@#])#(\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*)""".toRegex()
    }

{'fraction_non_alphanumeric': 0.10303484451105283, 'fraction_numerical': 0.002098164106406894, 'mean_word_length': 3.6068346565412495, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 25, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5936952', 'n_tokens_mistral': 3652, 'n_tokens_neox': 3543, 'n_words': 994}