mirror of
				https://github.com/GayPizzaSpecifications/pork.git
				synced 2025-11-03 17:39:38 +00:00 
			
		
		
		
	native: pass argument specs in order to support varadic ffi
This commit is contained in:
		@ -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() }
 | 
				
			||||||
 | 
				
			|||||||
@ -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")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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
									
								
							
							
						
						
									
										5
									
								
								examples/printf.pork
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import std ffi.printf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export func main() {
 | 
				
			||||||
 | 
					  printf("Hello World: %s\n", "Jolk")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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) {
 | 
				
			||||||
 | 
				
			|||||||
@ -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)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								stdlib/src/main/pork/ffi/printf.pork
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								stdlib/src/main/pork/ffi/printf.pork
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					export func printf(format, arguments...)
 | 
				
			||||||
 | 
					  native ffi "c:printf:int:char*,..."
 | 
				
			||||||
		Reference in New Issue
	
	Block a user