mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
ffi: explicit parameter type conversion
This commit is contained in:
parent
4053c5825a
commit
260c9f437d
@ -3,7 +3,8 @@ package gay.pizza.pork.ffi
|
|||||||
class FfiFunctionDefinition(
|
class FfiFunctionDefinition(
|
||||||
val library: String,
|
val library: String,
|
||||||
val function: String,
|
val function: String,
|
||||||
val returnType: String
|
val returnType: String,
|
||||||
|
val parameters: List<String>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(def: String): FfiFunctionDefinition {
|
fun parse(def: String): FfiFunctionDefinition {
|
||||||
@ -15,7 +16,13 @@ class FfiFunctionDefinition(
|
|||||||
"but '${def}' was specified")
|
"but '${def}' was specified")
|
||||||
}
|
}
|
||||||
val (library, function, returnType) = parts
|
val (library, function, returnType) = parts
|
||||||
return FfiFunctionDefinition(library, function, returnType)
|
val parametersString = if (parts.size == 4) parts[3] else ""
|
||||||
|
return FfiFunctionDefinition(
|
||||||
|
library,
|
||||||
|
function,
|
||||||
|
returnType,
|
||||||
|
parametersString.split(",")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package gay.pizza.pork.ffi
|
package gay.pizza.pork.ffi
|
||||||
|
|
||||||
import com.sun.jna.Function
|
import com.sun.jna.Function
|
||||||
|
import com.sun.jna.Pointer
|
||||||
import gay.pizza.pork.ast.ArgumentSpec
|
import gay.pizza.pork.ast.ArgumentSpec
|
||||||
import gay.pizza.pork.evaluator.CallableFunction
|
import gay.pizza.pork.evaluator.CallableFunction
|
||||||
import gay.pizza.pork.evaluator.NativeProvider
|
import gay.pizza.pork.evaluator.NativeProvider
|
||||||
@ -12,20 +13,22 @@ class JnaNativeProvider : NativeProvider {
|
|||||||
return CallableFunction { functionArgs ->
|
return CallableFunction { functionArgs ->
|
||||||
val ffiArgs = mutableListOf<Any?>()
|
val ffiArgs = mutableListOf<Any?>()
|
||||||
for ((index, spec) in arguments.withIndex()) {
|
for ((index, spec) in arguments.withIndex()) {
|
||||||
|
val ffiType = functionDefinition.parameters[index]
|
||||||
if (spec.multiple) {
|
if (spec.multiple) {
|
||||||
val variableArguments = functionArgs.values
|
val variableArguments = functionArgs.values
|
||||||
.subList(index, functionArgs.values.size)
|
.subList(index, functionArgs.values.size)
|
||||||
ffiArgs.addAll(variableArguments)
|
ffiArgs.addAll(variableArguments)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
ffiArgs.add(functionArgs.values[index])
|
val converted = convert(ffiType, functionArgs.values[index])
|
||||||
|
ffiArgs.add(converted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invoke(function, ffiArgs.toTypedArray(), functionDefinition.returnType)
|
invoke(function, ffiArgs.toTypedArray(), functionDefinition.returnType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invoke(function: Function, values: Array<Any?>, type: String): Any = when (type) {
|
private fun invoke(function: Function, values: Array<Any?>, type: String): Any = when (rewriteType(type)) {
|
||||||
"void*" -> function.invokePointer(values)
|
"void*" -> function.invokePointer(values)
|
||||||
"int" -> function.invokeInt(values)
|
"int" -> function.invokeInt(values)
|
||||||
"long" -> function.invokeLong(values)
|
"long" -> function.invokeLong(values)
|
||||||
@ -35,4 +38,48 @@ class JnaNativeProvider : NativeProvider {
|
|||||||
"char*" -> function.invokeString(values, false)
|
"char*" -> function.invokeString(values, false)
|
||||||
else -> throw RuntimeException("Unsupported ffi return type: $type")
|
else -> throw RuntimeException("Unsupported ffi return type: $type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun rewriteType(type: String): String = when (type) {
|
||||||
|
"size_t" -> "long"
|
||||||
|
else -> type
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convert(type: String, value: Any?): Any? = when (rewriteType(type)) {
|
||||||
|
"short" -> numberConvert(type, value) { toShort() }
|
||||||
|
"unsigned short" -> numberConvert(type, value) { toShort().toUShort() }
|
||||||
|
"int" -> numberConvert(type, value) { toInt() }
|
||||||
|
"unsigned int" -> numberConvert(type, value) { toInt().toUInt() }
|
||||||
|
"long" -> numberConvert(type, value) { toLong() }
|
||||||
|
"unsigned long" -> numberConvert(type, value) { toLong().toULong() }
|
||||||
|
"double" -> numberConvert(type, value) { toDouble() }
|
||||||
|
"float" -> numberConvert(type, value) { toFloat() }
|
||||||
|
"char*" -> notNullConvert(type, value) { toString() }
|
||||||
|
"void*" -> nullableConvert(type, value) { this as Pointer }
|
||||||
|
else -> throw RuntimeException("Unsupported ffi type: $type")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> notNullConvert(type: String, value: Any?, into: Any.() -> T): T {
|
||||||
|
if (value == null) {
|
||||||
|
throw RuntimeException("Null values cannot be used for converting to type $type")
|
||||||
|
}
|
||||||
|
return into(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> nullableConvert(type: String, value: Any?, into: Any.() -> T): T? {
|
||||||
|
if (value == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return into(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> numberConvert(type: String, value: Any?, into: Number.() -> T): T {
|
||||||
|
if (value == null) {
|
||||||
|
throw RuntimeException("Null values cannot be used for converting to numeric type $type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value !is Number) {
|
||||||
|
throw RuntimeException("Cannot convert value '$value' into type $type")
|
||||||
|
}
|
||||||
|
return into(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user