ffi: new native function format

This commit is contained in:
2023-09-22 00:26:24 -07:00
parent f60715dfb3
commit 83c24843a3
14 changed files with 75 additions and 57 deletions

View File

@ -7,21 +7,30 @@ class FfiFunctionDefinition(
val parameters: List<String>
) {
companion object {
fun parse(def: String): FfiFunctionDefinition {
val parts = def.split(":", limit = 4)
if (parts.size !in arrayOf(3, 4) || parts.any { it.trim().isEmpty() }) {
fun parse(library: String, def: String): FfiFunctionDefinition {
fun invalid(): Nothing {
throw RuntimeException(
"FFI function definition is invalid, " +
"accepted format is 'library:function:return-type:(optional)parameters' " +
"but '${def}' was specified")
"accepted format is 'return-type function-name(parameter, parameter...)' " +
"but '${def}' was specified")
}
val (library, function, returnType) = parts
val parametersString = if (parts.size == 4) parts[3] else ""
val parts = def.split(" ", limit = 2)
if (parts.size != 2) {
invalid()
}
val (returnType, functionNameAndParameters) = parts
var (functionName, parametersAndClosingParentheses) = functionNameAndParameters.split("(", limit = 2)
parametersAndClosingParentheses = parametersAndClosingParentheses.trim()
if (!parametersAndClosingParentheses.endsWith(")")) {
invalid()
}
val parameterString = parametersAndClosingParentheses.substring(0, parametersAndClosingParentheses.length - 1)
return FfiFunctionDefinition(
library,
function,
functionName,
returnType,
parametersString.split(",")
parameterString.split(",").map { it.trim() }
)
}
}

View File

@ -155,7 +155,7 @@ class JavaAutogen(val javaClass: Class<*>) {
)
private fun asNative(functionDefinition: JavaFunctionDefinition): Native =
Native(Symbol("java"), StringLiteral(functionDefinition.encode()))
Native(Symbol("java"), functionDefinition.encode().map { StringLiteral(it) })
private fun discriminate(parameter: Parameter): String =
parameter.type.simpleName.lowercase().replace("[]", "_array")

View File

@ -8,25 +8,25 @@ class JavaFunctionDefinition(
val parameters: List<String>
) {
companion object {
fun parse(def: String): JavaFunctionDefinition {
val parts = def.split(":", limit = 5)
if (!(parts.size == 4 || parts.size == 5) || parts.any { it.trim().isEmpty() }) {
fun parse(defs: List<String>): JavaFunctionDefinition {
if (defs.size != 4 && defs.size != 5) {
throw RuntimeException(
"Java function definition is invalid, " +
"accepted format is 'type:kind:symbol:return-type:(optional)parameters' " +
"but '${def}' was specified")
"but ${defs.joinToString(" ", prefix = "\"", postfix = "\"")} was specified")
}
val (type, kind, symbol, returnType) = parts
val parameters = if (parts.size > 4) parts[4].split(",") else emptyList()
val (type, kind, symbol, returnType) = defs
val parameterString = if (defs.size == 5) defs[4] else ""
val parameters = if (parameterString.isNotEmpty()) parameterString.split(",") else emptyList()
return JavaFunctionDefinition(type, kind, symbol, returnType, parameters)
}
}
fun encode(): String = buildString {
append("${type}:${kind}:${symbol}:${returnType}")
if (parameters.isNotEmpty()) {
append(":")
append(parameters.joinToString(","))
}
}
fun encode(): List<String> = listOf(
type,
kind,
symbol,
returnType,
parameters.joinToString(",")
)
}

View File

@ -10,8 +10,8 @@ import java.lang.invoke.MethodType
class JavaNativeProvider : NativeProvider {
private val lookup = MethodHandles.lookup()
override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
val functionDefinition = JavaFunctionDefinition.parse(definition)
override fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>): CallableFunction {
val functionDefinition = JavaFunctionDefinition.parse(definitions)
val javaClass = lookupClass(functionDefinition.type)
val returnTypeClass = lookupClass(functionDefinition.returnType)
val parameterClasses = functionDefinition.parameters.map { lookupClass(it) }

View File

@ -8,8 +8,8 @@ import gay.pizza.pork.evaluator.NativeProvider
import gay.pizza.pork.evaluator.None
class JnaNativeProvider : NativeProvider {
override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
val functionDefinition = FfiFunctionDefinition.parse(definition)
override fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>): CallableFunction {
val functionDefinition = FfiFunctionDefinition.parse(definitions[0], definitions[1])
val library = NativeLibrary.getInstance(functionDefinition.library)
val function = library.getFunction(functionDefinition.function)
?: throw RuntimeException("Failed to find function ${functionDefinition.function} in library ${functionDefinition.library}")