mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 21:21:33 +00:00
global: a working virtual machine for some of the use cases. APIs and validation still WIP.
This commit is contained in:
@ -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.")
|
||||
|
56
vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt
Normal file
56
vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt
Normal 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
|
||||
)
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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())
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user