native: pass argument specs in order to support varadic ffi

This commit is contained in:
Alex Zenla 2023-09-11 01:12:32 -04:00
parent 8d310e337a
commit 2ee1565fb5
Signed by: alex
GPG Key ID: C0780728420EBFE5
7 changed files with 33 additions and 9 deletions

View File

@ -9,7 +9,7 @@ class FunctionContext(val compilationUnitContext: CompilationUnitContext, val no
val native = node.native!! val native = node.native!!
val nativeFunctionProvider = val nativeFunctionProvider =
compilationUnitContext.evaluator.nativeFunctionProvider(native.form.id) compilationUnitContext.evaluator.nativeFunctionProvider(native.form.id)
nativeFunctionProvider.provideNativeFunction(native.definition.text) nativeFunctionProvider.provideNativeFunction(native.definition.text, node.arguments)
} }
private val nativeCached by lazy { resolveMaybeNative() } private val nativeCached by lazy { resolveMaybeNative() }

View File

@ -1,12 +1,14 @@
package gay.pizza.pork.evaluator package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.ArgumentSpec
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider { class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
private val functions = mutableMapOf( private val functions = mutableMapOf(
"print" to CallableFunction(::printValues), "print" to CallableFunction(::printValues),
"println" to CallableFunction(::printLine) "println" to CallableFunction(::printLine)
) )
override fun provideNativeFunction(definition: String): CallableFunction { override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition") return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
} }

View File

@ -1,5 +1,7 @@
package gay.pizza.pork.evaluator package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.ArgumentSpec
interface NativeProvider { interface NativeProvider {
fun provideNativeFunction(definition: String): CallableFunction fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction
} }

5
examples/printf.pork Normal file
View File

@ -0,0 +1,5 @@
import std ffi.printf
export func main() {
printf("Hello World: %s\n", "Jolk")
}

View File

@ -1,5 +1,6 @@
package gay.pizza.pork.ffi package gay.pizza.pork.ffi
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
import gay.pizza.pork.evaluator.None import gay.pizza.pork.evaluator.None
@ -9,7 +10,7 @@ import java.lang.invoke.MethodType
class JavaNativeProvider : NativeProvider { class JavaNativeProvider : NativeProvider {
private val lookup = MethodHandles.lookup() private val lookup = MethodHandles.lookup()
override fun provideNativeFunction(definition: String): CallableFunction { override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
val functionDefinition = JavaFunctionDefinition.parse(definition) val functionDefinition = JavaFunctionDefinition.parse(definition)
val javaClass = lookupClass(functionDefinition.type) val javaClass = lookupClass(functionDefinition.type)
val returnTypeClass = lookupClass(functionDefinition.returnType) val returnTypeClass = lookupClass(functionDefinition.returnType)
@ -21,7 +22,7 @@ class JavaNativeProvider : NativeProvider {
returnTypeClass, returnTypeClass,
parameterClasses parameterClasses
) )
return CallableFunction { arguments -> handle.invokeWithArguments(arguments.values) ?: None } return CallableFunction { functionArguments -> handle.invokeWithArguments(functionArguments.values) ?: None }
} }
private fun lookupClass(name: String): Class<*> = when (name) { private fun lookupClass(name: String): Class<*> = when (name) {

View File

@ -1,19 +1,31 @@
package gay.pizza.pork.ffi package gay.pizza.pork.ffi
import com.sun.jna.Function import com.sun.jna.Function
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
class JnaNativeProvider : NativeProvider { class JnaNativeProvider : NativeProvider {
override fun provideNativeFunction(definition: String): CallableFunction { override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
val functionDefinition = FfiFunctionDefinition.parse(definition) val functionDefinition = FfiFunctionDefinition.parse(definition)
val function = Function.getFunction(functionDefinition.library, functionDefinition.function) val function = Function.getFunction(functionDefinition.library, functionDefinition.function)
return CallableFunction { return CallableFunction { functionArgs ->
invoke(function, it.values.toTypedArray(), functionDefinition.returnType) val ffiArgs = mutableListOf<Any?>()
for ((index, spec) in arguments.withIndex()) {
if (spec.multiple) {
val variableArguments = functionArgs.values
.subList(index, functionArgs.values.size)
ffiArgs.addAll(variableArguments)
break
} else {
ffiArgs.add(functionArgs.values[index])
}
}
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 (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)

View File

@ -0,0 +1,2 @@
export func printf(format, arguments...)
native ffi "c:printf:int:char*,..."