diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt index cf55229..997f6a3 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt @@ -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() } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt index a276711..9fc2490 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt @@ -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): CallableFunction { return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition") } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt index df6e3e7..95483f7 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt @@ -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): CallableFunction } diff --git a/examples/printf.pork b/examples/printf.pork new file mode 100644 index 0000000..2ac723e --- /dev/null +++ b/examples/printf.pork @@ -0,0 +1,5 @@ +import std ffi.printf + +export func main() { + printf("Hello World: %s\n", "Jolk") +} diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt index b845570..4008e83 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt @@ -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): 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) { 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 a9003b0..97925fd 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt @@ -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): 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() + 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, type: String): Any = when (type) { + private fun invoke(function: Function, values: Array, type: String): Any = when (type) { "void*" -> function.invokePointer(values) "int" -> function.invokeInt(values) "long" -> function.invokeLong(values) diff --git a/stdlib/src/main/pork/ffi/printf.pork b/stdlib/src/main/pork/ffi/printf.pork new file mode 100644 index 0000000..1e79a0a --- /dev/null +++ b/stdlib/src/main/pork/ffi/printf.pork @@ -0,0 +1,2 @@ +export func printf(format, arguments...) + native ffi "c:printf:int:char*,..."