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()
|
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user