mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
implement native type compilation
This commit is contained in:
parent
f7ff896f81
commit
837e0c1b38
@ -6,5 +6,6 @@ import kotlinx.serialization.Serializable
|
||||
enum class IrDefinitionType {
|
||||
Variable,
|
||||
CodeFunction,
|
||||
NativeFunction
|
||||
NativeFunction,
|
||||
NativeType,
|
||||
}
|
||||
|
@ -3,6 +3,6 @@ package gay.pizza.pork.bir
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class IrNativeDefinition(var form: String, var definitions: List<String>) : IrCodeElement() {
|
||||
data class IrNativeDefinition(var kind: IrNativeDefinitionKind, var form: String, var definitions: List<String>) : IrCodeElement() {
|
||||
override fun crawl(block: (IrElement) -> Unit) {}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package gay.pizza.pork.bir
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
enum class IrNativeDefinitionKind {
|
||||
Function,
|
||||
Type
|
||||
}
|
@ -13,7 +13,8 @@ enum class Opcode(val id: UByte) {
|
||||
UnaryMinus(10u),
|
||||
BinaryNot(11u),
|
||||
And(20u),
|
||||
Native(24u),
|
||||
NativeFunction(24u),
|
||||
NativeType(43u),
|
||||
Return(10u),
|
||||
StoreLocal(16u),
|
||||
LoadLocal(17u),
|
||||
|
@ -308,6 +308,13 @@ class AstIrEmitter(
|
||||
}
|
||||
|
||||
override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor): IrCodeElement = IrNativeDefinition(
|
||||
kind = IrNativeDefinitionKind.Function,
|
||||
form = node.form.id,
|
||||
definitions = node.definitions.map { it.text }
|
||||
)
|
||||
|
||||
override fun visitNativeTypeDescriptor(node: NativeTypeDescriptor): IrCodeElement = IrNativeDefinition(
|
||||
kind = IrNativeDefinitionKind.Type,
|
||||
form = node.form.id,
|
||||
definitions = node.definitions.map { it.text }
|
||||
)
|
||||
|
@ -3,6 +3,8 @@ package gay.pizza.pork.compiler
|
||||
import gay.pizza.pork.ast.gen.FunctionDefinition
|
||||
import gay.pizza.pork.ast.gen.LetDefinition
|
||||
import gay.pizza.pork.ast.gen.NativeFunctionDescriptor
|
||||
import gay.pizza.pork.ast.gen.NativeTypeDescriptor
|
||||
import gay.pizza.pork.ast.gen.TypeDefinition
|
||||
import gay.pizza.pork.ast.gen.visit
|
||||
import gay.pizza.pork.bir.IrCodeBlock
|
||||
import gay.pizza.pork.bir.IrDefinition
|
||||
@ -36,25 +38,34 @@ class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: Scop
|
||||
scope = compilableSlab.slab.scope
|
||||
)
|
||||
irCodeEmitter.enterLocalScope()
|
||||
val what = if (scopeSymbol.definition is FunctionDefinition) {
|
||||
val functionDefinition = scopeSymbol.definition as FunctionDefinition
|
||||
irCodeEmitter.createFunctionArguments(functionDefinition)
|
||||
functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!!
|
||||
} else {
|
||||
val letDefinition = scopeSymbol.definition as LetDefinition
|
||||
letDefinition.value
|
||||
val what = when (scopeSymbol.definition) {
|
||||
is FunctionDefinition -> {
|
||||
val functionDefinition = scopeSymbol.definition as FunctionDefinition
|
||||
irCodeEmitter.createFunctionArguments(functionDefinition)
|
||||
functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!!
|
||||
}
|
||||
|
||||
is TypeDefinition -> {
|
||||
val typeDefinition = scopeSymbol.definition as TypeDefinition
|
||||
typeDefinition.nativeTypeDescriptor!!
|
||||
}
|
||||
|
||||
else -> {
|
||||
val letDefinition = scopeSymbol.definition as LetDefinition
|
||||
letDefinition.value
|
||||
}
|
||||
}
|
||||
val type = if (what is NativeFunctionDescriptor) {
|
||||
IrDefinitionType.NativeFunction
|
||||
} else if (what is NativeTypeDescriptor) {
|
||||
IrDefinitionType.NativeType
|
||||
} else if (scopeSymbol.definition is LetDefinition) {
|
||||
IrDefinitionType.Variable
|
||||
} else {
|
||||
IrDefinitionType.CodeFunction
|
||||
}
|
||||
val irCodeElement = irCodeEmitter.visit(what)
|
||||
val irCodeBlock = if (irCodeElement is IrCodeBlock) {
|
||||
irCodeElement
|
||||
} else IrCodeBlock(listOf(irCodeElement))
|
||||
val irCodeBlock = irCodeElement as? IrCodeBlock ?: IrCodeBlock(listOf(irCodeElement))
|
||||
irCodeEmitter.exitLocalScope()
|
||||
return IrDefinition(
|
||||
symbol = functionSymbol,
|
||||
|
@ -233,7 +233,15 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I
|
||||
ConstantTag.NativeDefinition,
|
||||
buffer,
|
||||
)
|
||||
code.emit(Opcode.Native, listOf(nativeDefinitionConstant, functionArgumentCount.toUInt()))
|
||||
|
||||
when (ir.kind) {
|
||||
IrNativeDefinitionKind.Function -> {
|
||||
code.emit(Opcode.NativeFunction, listOf(nativeDefinitionConstant, functionArgumentCount.toUInt()))
|
||||
}
|
||||
IrNativeDefinitionKind.Type -> {
|
||||
code.emit(Opcode.NativeType, listOf(nativeDefinitionConstant))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitIrIndex(ir: IrIndex) {
|
||||
|
@ -8,16 +8,35 @@ class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
|
||||
"listInitWith" to NativeFunction(::listInitWith)
|
||||
)
|
||||
|
||||
private val types = mutableMapOf(
|
||||
"int32" to NativeType { Int::class.java },
|
||||
"int64" to NativeType { Long::class.java },
|
||||
"string" to NativeType { String::class.java },
|
||||
"float32" to NativeType { Float::class.java },
|
||||
"float64" to NativeType { Double::class.java },
|
||||
"bool" to NativeType { Boolean::class.java },
|
||||
)
|
||||
|
||||
fun add(name: String, function: NativeFunction) {
|
||||
functions[name] = function
|
||||
}
|
||||
|
||||
fun add(name: String, type: NativeType) {
|
||||
types[name] = type
|
||||
}
|
||||
|
||||
override fun provideNativeFunction(definitions: List<String>): NativeFunction {
|
||||
val definition = definitions[0]
|
||||
return functions[definition] ?:
|
||||
throw RuntimeException("Unknown internal function: $definition")
|
||||
}
|
||||
|
||||
override fun provideNativeType(definitions: List<String>): NativeType {
|
||||
val definition = definitions[0]
|
||||
return types[definition] ?:
|
||||
throw RuntimeException("Unknown internal type: $definition")
|
||||
}
|
||||
|
||||
private fun printValues(arguments: ArgumentList): Any {
|
||||
if (quiet || arguments.isEmpty()) return None
|
||||
print(arguments.at<List<*>>(0).joinToString(" ") { it.toString() })
|
||||
|
@ -2,4 +2,5 @@ package gay.pizza.pork.execution
|
||||
|
||||
interface NativeProvider {
|
||||
fun provideNativeFunction(definitions: List<String>): NativeFunction
|
||||
fun provideNativeType(definitions: List<String>): NativeType
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package gay.pizza.pork.execution
|
||||
|
||||
fun interface NativeType {
|
||||
fun value(): Any
|
||||
}
|
@ -8,6 +8,7 @@ import gay.pizza.pork.evaluator.*
|
||||
import gay.pizza.pork.execution.ArgumentList
|
||||
import gay.pizza.pork.execution.NativeFunction
|
||||
import gay.pizza.pork.execution.NativeProvider
|
||||
import gay.pizza.pork.execution.NativeType
|
||||
import gay.pizza.pork.execution.None
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
@ -231,6 +232,11 @@ class FfiNativeProvider : ExpandedNativeProvider, NativeProvider {
|
||||
callable.call(arguments, CallStack())
|
||||
}
|
||||
}
|
||||
|
||||
override fun provideNativeType(definitions: List<String>): NativeType {
|
||||
throw RuntimeException("Unknown native type")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun typeConversion(type: FfiType): Type = when (type) {
|
||||
FfiPrimitiveType.UnsignedByte -> Type.UINT8
|
||||
|
@ -6,6 +6,7 @@ import gay.pizza.pork.evaluator.SlabContext
|
||||
import gay.pizza.pork.evaluator.ExpandedNativeProvider
|
||||
import gay.pizza.pork.execution.NativeFunction
|
||||
import gay.pizza.pork.execution.NativeProvider
|
||||
import gay.pizza.pork.execution.NativeType
|
||||
import gay.pizza.pork.execution.None
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
@ -68,4 +69,8 @@ class JavaNativeProvider : ExpandedNativeProvider, NativeProvider {
|
||||
override fun provideNativeFunction(definitions: List<String>): NativeFunction {
|
||||
throw RuntimeException("Invalid Native Function Usage")
|
||||
}
|
||||
|
||||
override fun provideNativeType(definitions: List<String>): NativeType {
|
||||
throw RuntimeException("Invalid Native Type Usage")
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor<Unit>() {
|
||||
internalSymbols.removeLast()
|
||||
}
|
||||
|
||||
override fun visitTypeDefinition(node: TypeDefinition) {
|
||||
}
|
||||
|
||||
override fun visitLetDefinition(node: LetDefinition) {
|
||||
node.value.visit(this)
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class CompileCommand : CliktCommand("compile") {
|
||||
annotation = " ; ${annotations.joinToString(", ") { it.text }}"
|
||||
}
|
||||
print(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
|
||||
if (op.code == Opcode.Constant || op.code == Opcode.Native) {
|
||||
if (op.code == Opcode.Constant || op.code == Opcode.NativeFunction) {
|
||||
val constant = compiledWorld.constantPool.constants[op.args[0].toInt()]
|
||||
val constantString = when (constant.tag) {
|
||||
ConstantTag.String -> "string = \"" + constant.readAsString() + "\""
|
||||
|
@ -47,7 +47,8 @@ val StandardOpHandlers: List<OpHandler> = listOf(
|
||||
CallOpHandler,
|
||||
ReturnOpHandler,
|
||||
|
||||
NativeOpHandler,
|
||||
NativeFunctionOpHandler,
|
||||
NativeTypeOpHandler,
|
||||
|
||||
ScopeInOpHandler,
|
||||
ScopeOutOpHandler,
|
||||
|
@ -2,11 +2,10 @@ package gay.pizza.pork.vm.ops
|
||||
|
||||
import gay.pizza.pork.bytecode.Op
|
||||
import gay.pizza.pork.bytecode.Opcode
|
||||
import gay.pizza.pork.execution.None
|
||||
import gay.pizza.pork.vm.InternalMachine
|
||||
import gay.pizza.pork.vm.OpHandler
|
||||
|
||||
object NativeOpHandler : OpHandler(Opcode.Native) {
|
||||
object NativeFunctionOpHandler : OpHandler(Opcode.NativeFunction) {
|
||||
override fun handle(machine: InternalMachine, op: Op) {
|
||||
val handler = optimize(machine, op)
|
||||
handler.handle(machine, op)
|
||||
@ -17,6 +16,6 @@ object NativeOpHandler : OpHandler(Opcode.Native) {
|
||||
val form = nativeDefinition[0]
|
||||
val provider = machine.nativeRegistry.of(form)
|
||||
val function = provider.provideNativeFunction(nativeDefinition.subList(1, nativeDefinition.size))
|
||||
return OptimizedNativeOpHandler(function)
|
||||
return OptimizedNativeFunctionOpHandler(function)
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package gay.pizza.pork.vm.ops
|
||||
|
||||
import gay.pizza.pork.bytecode.Op
|
||||
import gay.pizza.pork.bytecode.Opcode
|
||||
import gay.pizza.pork.vm.InternalMachine
|
||||
import gay.pizza.pork.vm.OpHandler
|
||||
|
||||
object NativeTypeOpHandler : OpHandler(Opcode.NativeType) {
|
||||
override fun handle(machine: InternalMachine, op: Op) {
|
||||
val handler = optimize(machine, op)
|
||||
handler.handle(machine, op)
|
||||
}
|
||||
|
||||
override fun optimize(machine: InternalMachine, op: Op): OpHandler {
|
||||
val nativeDefinition = machine.world.constantPool.read(op.args[0]).readAsNativeDefinition()
|
||||
val form = nativeDefinition[0]
|
||||
val provider = machine.nativeRegistry.of(form)
|
||||
val type = provider.provideNativeType(nativeDefinition.subList(1, nativeDefinition.size))
|
||||
return OptimizedNativeTypeOpHandler(type)
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import gay.pizza.pork.execution.None
|
||||
import gay.pizza.pork.vm.InternalMachine
|
||||
import gay.pizza.pork.vm.OpHandler
|
||||
|
||||
class OptimizedNativeOpHandler(val function: NativeFunction) : OpHandler(Opcode.Native) {
|
||||
class OptimizedNativeFunctionOpHandler(val function: NativeFunction) : OpHandler(Opcode.NativeFunction) {
|
||||
override fun handle(machine: InternalMachine, op: Op) {
|
||||
val argumentCount = op.args[1]
|
||||
val arguments = mutableListOf<Any>()
|
@ -0,0 +1,16 @@
|
||||
package gay.pizza.pork.vm.ops
|
||||
|
||||
import gay.pizza.pork.bytecode.Op
|
||||
import gay.pizza.pork.bytecode.Opcode
|
||||
import gay.pizza.pork.execution.NativeFunction
|
||||
import gay.pizza.pork.execution.NativeType
|
||||
import gay.pizza.pork.execution.None
|
||||
import gay.pizza.pork.vm.InternalMachine
|
||||
import gay.pizza.pork.vm.OpHandler
|
||||
|
||||
class OptimizedNativeTypeOpHandler(val type: NativeType) : OpHandler(Opcode.NativeType) {
|
||||
override fun handle(machine: InternalMachine, op: Op) {
|
||||
val result = type.value()
|
||||
machine.push(if (result == Unit) None else result)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user