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 nativeFunctionProvider =
compilationUnitContext.evaluator.nativeFunctionProvider(native.form.id)
nativeFunctionProvider.provideNativeFunction(native.definition.text)
nativeFunctionProvider.provideNativeFunction(native.definition.text, node.arguments)
}
private val nativeCached by lazy { resolveMaybeNative() }

View File

@ -1,12 +1,14 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.ArgumentSpec
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
private val functions = mutableMapOf(
"print" to CallableFunction(::printValues),
"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")
}

View File

@ -1,5 +1,7 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.ArgumentSpec
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
import gay.pizza.pork.ast.ArgumentSpec
import gay.pizza.pork.evaluator.CallableFunction
import gay.pizza.pork.evaluator.NativeProvider
import gay.pizza.pork.evaluator.None
@ -9,7 +10,7 @@ import java.lang.invoke.MethodType
class JavaNativeProvider : NativeProvider {
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 javaClass = lookupClass(functionDefinition.type)
val returnTypeClass = lookupClass(functionDefinition.returnType)
@ -21,7 +22,7 @@ class JavaNativeProvider : NativeProvider {
returnTypeClass,
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) {

View File

@ -1,19 +1,31 @@
package gay.pizza.pork.ffi
import com.sun.jna.Function
import gay.pizza.pork.ast.ArgumentSpec
import gay.pizza.pork.evaluator.CallableFunction
import gay.pizza.pork.evaluator.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 function = Function.getFunction(functionDefinition.library, functionDefinition.function)
return CallableFunction {
invoke(function, it.values.toTypedArray(), functionDefinition.returnType)
return CallableFunction { functionArgs ->
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)
"int" -> function.invokeInt(values)
"long" -> function.invokeLong(values)

View File

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