mirror of
				https://github.com/GayPizzaSpecifications/pork.git
				synced 2025-11-03 17:39:38 +00:00 
			
		
		
		
	ffi: autogen java bindings (very wip)
This commit is contained in:
		@ -1,10 +1,8 @@
 | 
				
			|||||||
func java_system_err()
 | 
					import java java.lang.System
 | 
				
			||||||
  native java "java.lang.System:static-getter:err:java.io.PrintStream"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func print_stream_println(stream, line)
 | 
					func java_io_PrintStream_println(a) native java "java.io.PrintStream:virtual:println:void:String"
 | 
				
			||||||
  native java "java.io.PrintStream:virtual:println:void:String"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export func main() {
 | 
					export func main() {
 | 
				
			||||||
  let error = java_system_err()
 | 
					  let stream = java_lang_System_err_get()
 | 
				
			||||||
  print_stream_println(error, "Hello World")
 | 
					  java_io_PrintStream_println(stream, "Hello World")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ plugins {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
 | 
					  api(project(":frontend"))
 | 
				
			||||||
  api(project(":evaluator"))
 | 
					  api(project(":evaluator"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  implementation(project(":common"))
 | 
					  implementation(project(":common"))
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										94
									
								
								ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.ffi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.*
 | 
				
			||||||
 | 
					import java.io.PrintStream
 | 
				
			||||||
 | 
					import java.lang.reflect.Modifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class JavaAutogen(val javaClass: Class<*>) {
 | 
				
			||||||
 | 
					  private val prefix = javaClass.name.replace(".", "_")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun generateCompilationUnit(): CompilationUnit {
 | 
				
			||||||
 | 
					    return CompilationUnit(
 | 
				
			||||||
 | 
					      declarations = listOf(),
 | 
				
			||||||
 | 
					      definitions = generateFunctionDefinitions()
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun generateFunctionDefinitions(): List<FunctionDefinition> {
 | 
				
			||||||
 | 
					    val definitions = mutableMapOf<String, FunctionDefinition>()
 | 
				
			||||||
 | 
					    for (method in javaClass.methods) {
 | 
				
			||||||
 | 
					      if (!Modifier.isPublic(method.modifiers)) {
 | 
				
			||||||
 | 
					        continue
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val name = method.name
 | 
				
			||||||
 | 
					      val returnTypeName = method.returnType.name
 | 
				
			||||||
 | 
					      val parameterNames = method.parameters.indices.map { ('a' + it).toString() }
 | 
				
			||||||
 | 
					      val parameterTypeNames = method.parameters.map { it.type.name }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      fun form(kind: String): JavaFunctionDefinition =
 | 
				
			||||||
 | 
					        JavaFunctionDefinition(javaClass.name, kind, name, returnTypeName, parameterTypeNames)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (Modifier.isStatic(method.modifiers)) {
 | 
				
			||||||
 | 
					        definitions[name] = function(name, parameterNames, form("static"))
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        definitions[name] = function(name, parameterNames, form("virtual"))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (field in javaClass.fields) {
 | 
				
			||||||
 | 
					      if (!Modifier.isPublic(field.modifiers)) {
 | 
				
			||||||
 | 
					        continue
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val name = field.name
 | 
				
			||||||
 | 
					      val valueTypeName = field.type.name
 | 
				
			||||||
 | 
					      val isStatic = Modifier.isStatic(field.modifiers)
 | 
				
			||||||
 | 
					      fun form(kind: String, getOrSet: Boolean): JavaFunctionDefinition =
 | 
				
			||||||
 | 
					        JavaFunctionDefinition(javaClass.name, kind, name, valueTypeName, if (getOrSet) {
 | 
				
			||||||
 | 
					          if (isStatic) {
 | 
				
			||||||
 | 
					            emptyList()
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            listOf(javaClass.name)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          if (isStatic) {
 | 
				
			||||||
 | 
					            listOf(valueTypeName)
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            listOf(javaClass.name, valueTypeName)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val parametersForGetter = if (isStatic) {
 | 
				
			||||||
 | 
					        emptyList()
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        listOf("object")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val parametersForSetter = if (isStatic) {
 | 
				
			||||||
 | 
					        listOf("value")
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        listOf("object", "value")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val getterKind = if (isStatic) "static-getter" else "getter"
 | 
				
			||||||
 | 
					      val setterKind = if (isStatic) "static-setter" else "setter"
 | 
				
			||||||
 | 
					      definitions[name + "_get"] = function(name + "_get", parametersForGetter, form(getterKind, true))
 | 
				
			||||||
 | 
					      definitions[name + "_set"] = function(name + "_set", parametersForSetter, form(setterKind, false))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return definitions.values.toList()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun function(name: String, parameterNames: List<String>, functionDefinition: JavaFunctionDefinition): FunctionDefinition =
 | 
				
			||||||
 | 
					    FunctionDefinition(
 | 
				
			||||||
 | 
					      modifiers = DefinitionModifiers(true),
 | 
				
			||||||
 | 
					      symbol = Symbol("${prefix}_${name}"),
 | 
				
			||||||
 | 
					      arguments = parameterNames.map { Symbol(it) },
 | 
				
			||||||
 | 
					      native = asNative(functionDefinition),
 | 
				
			||||||
 | 
					      block = null
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun asNative(functionDefinition: JavaFunctionDefinition): Native =
 | 
				
			||||||
 | 
					    Native(Symbol("java"), StringLiteral(functionDefinition.encode()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.ffi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.pork.ast.visit
 | 
				
			||||||
 | 
					import gay.pizza.pork.frontend.ContentSource
 | 
				
			||||||
 | 
					import gay.pizza.pork.parser.CharSource
 | 
				
			||||||
 | 
					import gay.pizza.pork.parser.Printer
 | 
				
			||||||
 | 
					import gay.pizza.pork.parser.StringCharSource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object JavaAutogenContentSource : ContentSource {
 | 
				
			||||||
 | 
					  override fun loadAsCharSource(path: String): CharSource {
 | 
				
			||||||
 | 
					    val javaClassName = path.replace("/", ".").substring(0, path.length - 5)
 | 
				
			||||||
 | 
					    val autogen = JavaAutogen(Class.forName(javaClassName))
 | 
				
			||||||
 | 
					    val compilationUnit = autogen.generateCompilationUnit()
 | 
				
			||||||
 | 
					    val content = buildString { Printer(this).visit(compilationUnit) }
 | 
				
			||||||
 | 
					    return StringCharSource(content)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun stableContentIdentity(path: String): String = path
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -20,4 +20,12 @@ class JavaFunctionDefinition(
 | 
				
			|||||||
      return JavaFunctionDefinition(type, kind, symbol, returnType, parameters)
 | 
					      return JavaFunctionDefinition(type, kind, symbol, returnType, parameters)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun encode(): String = buildString {
 | 
				
			||||||
 | 
					    append("${type}:${kind}:${symbol}:${returnType}")
 | 
				
			||||||
 | 
					    if (parameters.isNotEmpty()) {
 | 
				
			||||||
 | 
					      append(":")
 | 
				
			||||||
 | 
					      append(parameters.joinToString(","))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -131,6 +131,9 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitFunctionDefinition(node: FunctionDefinition) {
 | 
					  override fun visitFunctionDefinition(node: FunctionDefinition) {
 | 
				
			||||||
 | 
					    if (node.modifiers.export) {
 | 
				
			||||||
 | 
					      append("export ")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    append("func ")
 | 
					    append("func ")
 | 
				
			||||||
    visit(node.symbol)
 | 
					    visit(node.symbol)
 | 
				
			||||||
    append("(")
 | 
					    append("(")
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import gay.pizza.pork.ast.visit
 | 
				
			|||||||
import gay.pizza.pork.evaluator.CallableFunction
 | 
					import gay.pizza.pork.evaluator.CallableFunction
 | 
				
			||||||
import gay.pizza.pork.evaluator.Evaluator
 | 
					import gay.pizza.pork.evaluator.Evaluator
 | 
				
			||||||
import gay.pizza.pork.evaluator.Scope
 | 
					import gay.pizza.pork.evaluator.Scope
 | 
				
			||||||
 | 
					import gay.pizza.pork.ffi.JavaAutogenContentSource
 | 
				
			||||||
import gay.pizza.pork.frontend.ContentSource
 | 
					import gay.pizza.pork.frontend.ContentSource
 | 
				
			||||||
import gay.pizza.pork.frontend.ImportLocator
 | 
					import gay.pizza.pork.frontend.ImportLocator
 | 
				
			||||||
import gay.pizza.pork.frontend.DynamicImportSource
 | 
					import gay.pizza.pork.frontend.DynamicImportSource
 | 
				
			||||||
@ -36,6 +37,7 @@ abstract class Tool {
 | 
				
			|||||||
    val dynamicImportSource = DynamicImportSource()
 | 
					    val dynamicImportSource = DynamicImportSource()
 | 
				
			||||||
    dynamicImportSource.addContentSource("std", PorkStdlib)
 | 
					    dynamicImportSource.addContentSource("std", PorkStdlib)
 | 
				
			||||||
    dynamicImportSource.addContentSource("local", fileContentSource)
 | 
					    dynamicImportSource.addContentSource("local", fileContentSource)
 | 
				
			||||||
 | 
					    dynamicImportSource.addContentSource("java", JavaAutogenContentSource)
 | 
				
			||||||
    val world = World(dynamicImportSource)
 | 
					    val world = World(dynamicImportSource)
 | 
				
			||||||
    val evaluator = Evaluator(world, scope)
 | 
					    val evaluator = Evaluator(world, scope)
 | 
				
			||||||
    setupEvaluator(evaluator)
 | 
					    setupEvaluator(evaluator)
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user