mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
ffi: autogen java bindings (very wip)
This commit is contained in:
parent
540826fb6e
commit
a2f2252965
@ -1,10 +1,8 @@
|
||||
func java_system_err()
|
||||
native java "java.lang.System:static-getter:err:java.io.PrintStream"
|
||||
import java java.lang.System
|
||||
|
||||
func print_stream_println(stream, line)
|
||||
native java "java.io.PrintStream:virtual:println:void:String"
|
||||
func java_io_PrintStream_println(a) native java "java.io.PrintStream:virtual:println:void:String"
|
||||
|
||||
export func main() {
|
||||
let error = java_system_err()
|
||||
print_stream_println(error, "Hello World")
|
||||
let stream = java_lang_System_err_get()
|
||||
java_io_PrintStream_println(stream, "Hello World")
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":frontend"))
|
||||
api(project(":evaluator"))
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (node.modifiers.export) {
|
||||
append("export ")
|
||||
}
|
||||
append("func ")
|
||||
visit(node.symbol)
|
||||
append("(")
|
||||
|
@ -6,6 +6,7 @@ import gay.pizza.pork.ast.visit
|
||||
import gay.pizza.pork.evaluator.CallableFunction
|
||||
import gay.pizza.pork.evaluator.Evaluator
|
||||
import gay.pizza.pork.evaluator.Scope
|
||||
import gay.pizza.pork.ffi.JavaAutogenContentSource
|
||||
import gay.pizza.pork.frontend.ContentSource
|
||||
import gay.pizza.pork.frontend.ImportLocator
|
||||
import gay.pizza.pork.frontend.DynamicImportSource
|
||||
@ -36,6 +37,7 @@ abstract class Tool {
|
||||
val dynamicImportSource = DynamicImportSource()
|
||||
dynamicImportSource.addContentSource("std", PorkStdlib)
|
||||
dynamicImportSource.addContentSource("local", fileContentSource)
|
||||
dynamicImportSource.addContentSource("java", JavaAutogenContentSource)
|
||||
val world = World(dynamicImportSource)
|
||||
val evaluator = Evaluator(world, scope)
|
||||
setupEvaluator(evaluator)
|
||||
|
Loading…
Reference in New Issue
Block a user