global: a working virtual machine for some of the use cases. APIs and validation still WIP.

This commit is contained in:
2023-11-21 22:18:05 -08:00
parent 0a2d029c5c
commit 6211ad4ff1
53 changed files with 434 additions and 182 deletions

View File

@ -2,8 +2,9 @@ package gay.pizza.pork.vm
import gay.pizza.pork.bytecode.CompiledWorld
import gay.pizza.pork.bytecode.ConstantTag
import gay.pizza.pork.execution.NativeRegistry
class InternalMachine(val world: CompiledWorld, val handlers: List<OpHandler>) {
class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegistry, val handlers: List<OpHandler>) {
private val inlined = world.code.map { op ->
val handler = handlers.firstOrNull { it.code == op.code } ?:
throw VirtualMachineException("Opcode ${op.code.name} does not have a handler.")

View File

@ -0,0 +1,56 @@
package gay.pizza.pork.vm
import gay.pizza.pork.vm.ops.*
val StandardOpHandlers: List<OpHandler> = listOf(
IntegerOpHandler,
ConstantOpHandler,
TrueOpHandler,
FalseOpHandler,
NoneOpHandler,
ListMakeOpHandler,
ListSizeOpHandler,
IndexOpHandler,
AndOpHandler,
OrOpHandler,
NotOpHandler,
CompareEqualOpHandler,
CompareLesserOpHandler,
CompareGreaterOpHandler,
CompareLesserEqualOpHandler,
CompareGreaterEqualOpHandler,
AddOpHandler,
SubtractOpHandler,
MultiplyOpHandler,
UnaryMinusOpHandler,
UnaryPlusOpHandler,
BinaryAndOpHandler,
BinaryOrOpHandler,
BinaryNotOpHandler,
JumpOpHandler,
JumpIfOpHandler,
LoadLocalOpHandler,
StoreLocalOpHandler,
ReturnAddressOpHandler,
CallOpHandler,
ReturnOpHandler,
NativeOpHandler,
ScopeInOpHandler,
ScopeOutOpHandler,
EndOpHandler
)

View File

@ -2,57 +2,21 @@ package gay.pizza.pork.vm
import gay.pizza.pork.bytecode.CompiledWorld
import gay.pizza.pork.execution.ExecutionContext
import gay.pizza.pork.vm.ops.*
import gay.pizza.pork.execution.NativeRegistry
class VirtualMachine(world: CompiledWorld) : ExecutionContext {
private val internal = InternalMachine(world, listOf(
IntegerOpHandler,
ConstantOpHandler,
TrueOpHandler,
FalseOpHandler,
NoneOpHandler,
ListMakeOpHandler,
ListSizeOpHandler,
IndexOpHandler,
AndOpHandler,
OrOpHandler,
NotOpHandler,
CompareEqualOpHandler,
CompareLesserEqualOpHandler,
CompareGreaterEqualOpHandler,
AddOpHandler,
JumpOpHandler,
JumpIfOpHandler,
LoadLocalOpHandler,
StoreLocalOpHandler,
ReturnAddressOpHandler,
CallOpHandler,
ReturnOpHandler,
NativeOpHandler,
ScopeInOpHandler,
ScopeOutOpHandler,
EndOpHandler
))
class VirtualMachine(world: CompiledWorld, nativeRegistry: NativeRegistry) : ExecutionContext {
private val internal = InternalMachine(
world = world,
nativeRegistry = nativeRegistry,
handlers = StandardOpHandlers
)
override fun execute() {
internal.reset()
while (true) {
if (!internal.step()) {
break
}
}
internal.reset()
}
}

View File

@ -4,17 +4,18 @@ import gay.pizza.pork.ast.gen.Symbol
import gay.pizza.pork.compiler.Compiler
import gay.pizza.pork.execution.ExecutionContext
import gay.pizza.pork.execution.ExecutionContextProvider
import gay.pizza.pork.execution.NativeRegistry
import gay.pizza.pork.frontend.ImportLocator
import gay.pizza.pork.frontend.World
class VirtualMachineProvider(val world: World) : ExecutionContextProvider {
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext {
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext {
val compiler = Compiler()
val slab = world.load(importLocator)
val compilableSlab = compiler.compilableSlabs.of(slab)
val compilableSymbol = compilableSlab.resolve(entryPointSymbol) ?:
throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
val compiledWorld = compiler.compile(compilableSymbol)
return VirtualMachine(compiledWorld)
return VirtualMachine(compiledWorld, nativeRegistry)
}
}

View File

@ -0,0 +1,14 @@
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 BinaryAndOpHandler : OpHandler(Opcode.BinaryAnd) {
override fun handle(machine: InternalMachine, op: Op) {
val right = machine.pop<Int>()
val left = machine.pop<Int>()
machine.push(left and right)
}
}

View File

@ -0,0 +1,13 @@
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 BinaryNotOpHandler : OpHandler(Opcode.BinaryNot) {
override fun handle(machine: InternalMachine, op: Op) {
val value = machine.pop<Int>()
machine.push(value.inv())
}
}

View File

@ -0,0 +1,14 @@
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 BinaryOrOpHandler : OpHandler(Opcode.BinaryOr) {
override fun handle(machine: InternalMachine, op: Op) {
val right = machine.pop<Int>()
val left = machine.pop<Int>()
machine.push(left or right)
}
}

View File

@ -0,0 +1,14 @@
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 CompareGreaterOpHandler : OpHandler(Opcode.CompareGreater) {
override fun handle(machine: InternalMachine, op: Op) {
val right = machine.pop<Int>()
val left = machine.pop<Int>()
machine.push(left > right)
}
}

View File

@ -0,0 +1,14 @@
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 CompareLesserOpHandler : OpHandler(Opcode.CompareLesser) {
override fun handle(machine: InternalMachine, op: Op) {
val right = machine.pop<Int>()
val left = machine.pop<Int>()
machine.push(left < right)
}
}

View File

@ -0,0 +1,14 @@
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 MultiplyOpHandler : OpHandler(Opcode.Multiply) {
override fun handle(machine: InternalMachine, op: Op) {
val left = machine.pop<Int>()
val right = machine.pop<Int>()
machine.push(left * right)
}
}

View File

@ -7,10 +7,21 @@ import gay.pizza.pork.vm.OpHandler
object NativeOpHandler : OpHandler(Opcode.Native) {
override fun handle(machine: InternalMachine, op: Op) {
val countOfNativeDefs = op.args[1].toInt()
val defs = mutableListOf<Any>()
for (i in 0 until countOfNativeDefs) {
defs.add(machine.pop() as String)
val argumentCount = op.args[2]
val arguments = mutableListOf<Any>()
for (i in 0u until argumentCount) {
machine.loadLocal(i)
arguments.add(machine.popAnyValue())
}
val formConstant = machine.world.constantPool.read(op.args[0])
val form = formConstant.readAsString()
val provider = machine.nativeRegistry.of(form)
val countOfNativeDefs = op.args[1].toInt()
val defs = mutableListOf<String>()
for (i in 0 until countOfNativeDefs) {
defs.add(machine.pop())
}
val function = provider.provideNativeFunction(defs)
function.invoke(arguments)
}
}

View File

@ -0,0 +1,14 @@
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 SubtractOpHandler : OpHandler(Opcode.Subtract) {
override fun handle(machine: InternalMachine, op: Op) {
val left = machine.pop<Int>()
val right = machine.pop<Int>()
machine.push(left - right)
}
}

View File

@ -0,0 +1,13 @@
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 UnaryMinusOpHandler : OpHandler(Opcode.UnaryMinus) {
override fun handle(machine: InternalMachine, op: Op) {
val value = machine.pop<Int>()
machine.push(-value)
}
}

View File

@ -0,0 +1,13 @@
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 UnaryPlusOpHandler : OpHandler(Opcode.UnaryPlus) {
override fun handle(machine: InternalMachine, op: Op) {
val value = machine.pop<Int>()
machine.push(+value)
}
}