diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt index 0185de3..64e5a67 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt @@ -6,5 +6,6 @@ import kotlinx.serialization.Serializable enum class IrDefinitionType { Variable, CodeFunction, - NativeFunction + NativeFunction, + NativeType, } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt index fff2801..2787655 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt @@ -3,6 +3,6 @@ package gay.pizza.pork.bir import kotlinx.serialization.Serializable @Serializable -data class IrNativeDefinition(var form: String, var definitions: List) : IrCodeElement() { +data class IrNativeDefinition(var kind: IrNativeDefinitionKind, var form: String, var definitions: List) : IrCodeElement() { override fun crawl(block: (IrElement) -> Unit) {} } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinitionKind.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinitionKind.kt new file mode 100644 index 0000000..8261a20 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinitionKind.kt @@ -0,0 +1,9 @@ +package gay.pizza.pork.bir + +import kotlinx.serialization.Serializable + +@Serializable +enum class IrNativeDefinitionKind { + Function, + Type +} diff --git a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt index ed68ad2..6b7cc2d 100644 --- a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt +++ b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt @@ -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), diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt index 59969f0..406ddca 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt @@ -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 } ) diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt index a010627..cc9f03c 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt @@ -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, diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt index dc0c52c..3faba0b 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt @@ -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) { diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt index a816e04..a2e5b77 100644 --- a/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt @@ -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): NativeFunction { val definition = definitions[0] return functions[definition] ?: throw RuntimeException("Unknown internal function: $definition") } + override fun provideNativeType(definitions: List): 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>(0).joinToString(" ") { it.toString() }) diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt index 079c0c5..f6e0658 100644 --- a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt @@ -2,4 +2,5 @@ package gay.pizza.pork.execution interface NativeProvider { fun provideNativeFunction(definitions: List): NativeFunction + fun provideNativeType(definitions: List): NativeType } diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeType.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeType.kt new file mode 100644 index 0000000..d6ad44c --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeType.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.execution + +fun interface NativeType { + fun value(): Any +} diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt index 7cae9e1..c2c85e6 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt @@ -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): NativeType { + throw RuntimeException("Unknown native type") + } + companion object { fun typeConversion(type: FfiType): Type = when (type) { FfiPrimitiveType.UnsignedByte -> Type.UINT8 diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt index 4836314..e388ea9 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt @@ -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): NativeFunction { throw RuntimeException("Invalid Native Function Usage") } + + override fun provideNativeType(definitions: List): NativeType { + throw RuntimeException("Invalid Native Type Usage") + } } diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt index 8fff0fd..90e05cd 100644 --- a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt @@ -16,6 +16,9 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { internalSymbols.removeLast() } + override fun visitTypeDefinition(node: TypeDefinition) { + } + override fun visitLetDefinition(node: LetDefinition) { node.value.visit(this) } diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt index ec0553d..dac3de2 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt @@ -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() + "\"" diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt index 5591e3a..217b7f4 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt @@ -47,7 +47,8 @@ val StandardOpHandlers: List = listOf( CallOpHandler, ReturnOpHandler, - NativeOpHandler, + NativeFunctionOpHandler, + NativeTypeOpHandler, ScopeInOpHandler, ScopeOutOpHandler, diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeFunctionOpHandler.kt similarity index 83% rename from vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt rename to vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeFunctionOpHandler.kt index f520967..9f1aab4 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeFunctionOpHandler.kt @@ -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) } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeTypeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeTypeOpHandler.kt new file mode 100644 index 0000000..fa365f3 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeTypeOpHandler.kt @@ -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) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeFunctionOpHandler.kt similarity index 85% rename from vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeOpHandler.kt rename to vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeFunctionOpHandler.kt index 22a1df0..236bf97 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeFunctionOpHandler.kt @@ -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() diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeTypeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeTypeOpHandler.kt new file mode 100644 index 0000000..0b6effe --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/OptimizedNativeTypeOpHandler.kt @@ -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) + } +}