diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt new file mode 100644 index 0000000..3464aea --- /dev/null +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt @@ -0,0 +1,30 @@ +package gay.pizza.pork.ffi + +import gay.pizza.pork.evaluator.None + +enum class FfiPrimitiveType( + val id: kotlin.String, + override val size: kotlin.Int, + val numberConvert: (Number.() -> Number)? = null, + val nullableConversion: (Any?.() -> Any)? = null, + val notNullConversion: (Any.() -> Any)? = null +) : FfiType { + Byte("byte", 1, numberConvert = { toByte() }), + UnsignedByte("unsigned byte", 1, numberConvert = { toByte()}), + Short("short", 2, numberConvert = { toShort() }), + UnsignedShort("unsigned short", 2, numberConvert = { toShort() }), + Int("int", 4, numberConvert = { toInt() }), + UnsignedInt("unsigned int", 4, numberConvert = { toInt() }), + Float("float", 4, numberConvert = { toFloat() }), + Long("long", 8, numberConvert = { toLong() }), + UnsignedLong("unsigned long", 8, numberConvert = { toLong() }), + Double("double", 8, numberConvert = { toDouble() }), + String("char*", 8, nullableConversion = { toString() }), + Pointer("void*", 8, nullableConversion = { + if (this is kotlin.Long) { + com.sun.jna.Pointer(this) + } else if (this == None) { + com.sun.jna.Pointer.NULL + } else this as com.sun.jna.Pointer + }) +} diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt new file mode 100644 index 0000000..58109fe --- /dev/null +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt @@ -0,0 +1,14 @@ +package gay.pizza.pork.ffi + +class FfiStruct : FfiType { + private val fields = mutableListOf() + + data class FfiStructField(val name: String, val type: FfiType) + + fun add(field: String, type: FfiType) { + fields.add(FfiStructField(field, type)) + } + + override val size: Int + get() = fields.sumOf { it.type.size } +} diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiType.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiType.kt new file mode 100644 index 0000000..55ab5a7 --- /dev/null +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiType.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.ffi + +interface FfiType { + val size: Int +} diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt index 7953c4f..77382e4 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt @@ -2,7 +2,6 @@ package gay.pizza.pork.ffi import com.sun.jna.Function import com.sun.jna.NativeLibrary -import com.sun.jna.Pointer import gay.pizza.pork.ast.ArgumentSpec import gay.pizza.pork.evaluator.CallableFunction import gay.pizza.pork.evaluator.NativeProvider @@ -48,24 +47,23 @@ class JnaNativeProvider : NativeProvider { else -> type } - private fun convert(type: String, value: Any?): Any? = when (rewriteType(type)) { - "short" -> numberConvert(type, value) { toShort() } - "unsigned short" -> numberConvert(type, value) { toShort() } - "int" -> numberConvert(type, value) { toInt() } - "unsigned int" -> numberConvert(type, value) { toInt() } - "long" -> numberConvert(type, value) { toLong() } - "unsigned long" -> numberConvert(type, value) { toLong() } - "double" -> numberConvert(type, value) { toDouble() } - "float" -> numberConvert(type, value) { toFloat() } - "char*" -> notNullConvert(type, value) { toString() } - "void*" -> nullableConvert(value) { - if (value is Long) { - Pointer(value) - } else { - value as Pointer - } + private fun convert(type: String, value: Any?): Any? { + val rewritten = rewriteType(type) + val primitive = FfiPrimitiveType.entries.firstOrNull { it.id == rewritten } + ?: throw RuntimeException("Unsupported ffi type: $type") + if (primitive.numberConvert != null) { + return numberConvert(type, value, primitive.numberConvert) } - else -> throw RuntimeException("Unsupported ffi type: $type") + + if (primitive.notNullConversion != null) { + return notNullConvert(type, value, primitive.notNullConversion) + } + + if (primitive.nullableConversion != null) { + return nullableConvert(value, primitive.nullableConversion) + } + + return value } private fun notNullConvert(type: String, value: Any?, into: Any.() -> T): T { diff --git a/gradle.properties b/gradle.properties index 2b17698..3135fdb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ org.gradle.warning.mode=none kotlin.stdlib.default.dependency=false +kotlin.experimental.tryK2=true