mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 05:10:55 +00:00
global: a working virtual machine for some of the use cases. APIs and validation still WIP.
This commit is contained in:
parent
0a2d029c5c
commit
6211ad4ff1
@ -4,6 +4,13 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Constant(val id: UInt, val tag: ConstantTag, val value: ByteArray) {
|
data class Constant(val id: UInt, val tag: ConstantTag, val value: ByteArray) {
|
||||||
|
fun readAsString(): String {
|
||||||
|
if (tag != ConstantTag.String) {
|
||||||
|
throw RuntimeException("Constant $id is not tagged as a string")
|
||||||
|
}
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
other as Constant
|
other as Constant
|
||||||
|
@ -3,4 +3,6 @@ package gay.pizza.pork.bytecode
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ConstantPool(val constants: List<Constant>)
|
data class ConstantPool(val constants: List<Constant>) {
|
||||||
|
fun read(index: UInt): Constant = constants[index.toInt()]
|
||||||
|
}
|
||||||
|
@ -13,4 +13,9 @@ class CompilableSlab(val compiler: Compiler, val slab: Slab) {
|
|||||||
fun resolve(symbol: Symbol): CompilableSymbol? = compilableSymbols.firstOrNull {
|
fun resolve(symbol: Symbol): CompilableSymbol? = compilableSymbols.firstOrNull {
|
||||||
it.scopeSymbol.symbol == symbol
|
it.scopeSymbol.symbol == symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resolveVisible(symbol: Symbol): CompilableSymbol? {
|
||||||
|
val scopeSymbol = slab.scope.resolve(symbol) ?: return null
|
||||||
|
return compiler.resolveOrNull(scopeSymbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class LocalState(val symbol: CompilableSymbol) {
|
|||||||
return Loadable(stubVar = found)
|
return Loadable(stubVar = found)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val found = this.symbol.compilableSlab.resolve(symbol)
|
val found = this.symbol.compilableSlab.resolveVisible(symbol)
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
return Loadable(call = found)
|
return Loadable(call = found)
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,9 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
|
|||||||
code.emit(Opcode.Constant, listOf(defConstant))
|
code.emit(Opcode.Constant, listOf(defConstant))
|
||||||
}
|
}
|
||||||
val formConstant = compiler.constantPool.assign(ConstantTag.String, node.form.id.toByteArray())
|
val formConstant = compiler.constantPool.assign(ConstantTag.String, node.form.id.toByteArray())
|
||||||
code.emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt()))
|
val functionDefinition = symbol.scopeSymbol.definition as FunctionDefinition
|
||||||
|
val functionArgumentCount = functionDefinition.arguments.size
|
||||||
|
code.emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt(), functionArgumentCount.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun load(callOrStubVar: Loadable) {
|
private fun load(callOrStubVar: Loadable) {
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.gen.ArgumentSpec
|
||||||
|
import gay.pizza.pork.execution.NativeProvider
|
||||||
|
|
||||||
|
class AdaptedNativeProvider(val provider: NativeProvider) : ExpandedNativeProvider {
|
||||||
|
override fun provideNativeFunction(
|
||||||
|
definitions: List<String>,
|
||||||
|
arguments: List<ArgumentSpec>,
|
||||||
|
inside: SlabContext
|
||||||
|
): CallableFunction {
|
||||||
|
val function = provider.provideNativeFunction(definitions)
|
||||||
|
return CallableFunction { args, _ -> function.invoke(args) }
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
package gay.pizza.pork.evaluator
|
|
||||||
|
|
||||||
typealias ArgumentList = List<Any>
|
|
@ -1,5 +1,7 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.execution.ArgumentList
|
||||||
|
|
||||||
fun interface CallableFunction {
|
fun interface CallableFunction {
|
||||||
fun call(arguments: ArgumentList, stack: CallStack): Any
|
fun call(arguments: ArgumentList, stack: CallStack): Any
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package gay.pizza.pork.evaluator
|
|||||||
|
|
||||||
import gay.pizza.pork.ast.FunctionLevelVisitor
|
import gay.pizza.pork.ast.FunctionLevelVisitor
|
||||||
import gay.pizza.pork.ast.gen.*
|
import gay.pizza.pork.ast.gen.*
|
||||||
|
import gay.pizza.pork.execution.None
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
|
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
import gay.pizza.pork.ast.gen.Symbol
|
|
||||||
import gay.pizza.pork.execution.ExecutionContext
|
|
||||||
import gay.pizza.pork.execution.ExecutionContextProvider
|
|
||||||
import gay.pizza.pork.frontend.ImportLocator
|
import gay.pizza.pork.frontend.ImportLocator
|
||||||
import gay.pizza.pork.frontend.Slab
|
import gay.pizza.pork.frontend.Slab
|
||||||
import gay.pizza.pork.frontend.World
|
import gay.pizza.pork.frontend.World
|
||||||
|
|
||||||
class Evaluator(val world: World) : ExecutionContextProvider {
|
class Evaluator(val world: World) {
|
||||||
private val scope = Scope.root()
|
private val scope = Scope.root()
|
||||||
private val contexts = mutableMapOf<Slab, SlabContext>()
|
private val contexts = mutableMapOf<Slab, SlabContext>()
|
||||||
private val nativeProviders = mutableMapOf<String, NativeProvider>()
|
private val nativeProviders = mutableMapOf<String, ExpandedNativeProvider>()
|
||||||
|
|
||||||
fun evaluate(locator: ImportLocator): Scope {
|
fun evaluate(locator: ImportLocator): Scope {
|
||||||
val slabContext = context(locator)
|
val slabContext = slabContext(locator)
|
||||||
slabContext.finalizeScope()
|
slabContext.finalizeScope()
|
||||||
return slabContext.externalScope
|
return slabContext.externalScope
|
||||||
}
|
}
|
||||||
|
|
||||||
fun context(slab: Slab): SlabContext {
|
fun slabContext(slab: Slab): SlabContext {
|
||||||
val slabContext = contexts.computeIfAbsent(slab) {
|
val slabContext = contexts.computeIfAbsent(slab) {
|
||||||
SlabContext(slab, this, scope)
|
SlabContext(slab, this, scope)
|
||||||
}
|
}
|
||||||
@ -26,20 +23,14 @@ class Evaluator(val world: World) : ExecutionContextProvider {
|
|||||||
return slabContext
|
return slabContext
|
||||||
}
|
}
|
||||||
|
|
||||||
fun context(locator: ImportLocator): SlabContext = context(world.load(locator))
|
fun slabContext(locator: ImportLocator): SlabContext = slabContext(world.load(locator))
|
||||||
|
|
||||||
fun nativeFunctionProvider(form: String): NativeProvider {
|
fun nativeFunctionProvider(form: String): ExpandedNativeProvider {
|
||||||
return nativeProviders[form] ?:
|
return nativeProviders[form] ?:
|
||||||
throw RuntimeException("Unknown native function form: $form")
|
throw RuntimeException("Unknown native function form: $form")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addNativeProvider(form: String, nativeProvider: NativeProvider) {
|
fun addNativeProvider(form: String, nativeProvider: ExpandedNativeProvider) {
|
||||||
nativeProviders[form] = nativeProvider
|
nativeProviders[form] = nativeProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext {
|
|
||||||
val slab = context(importLocator)
|
|
||||||
slab.finalizeScope()
|
|
||||||
return EvaluatorExecutionContext(this, slab, entryPointSymbol)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
|
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 EvaluatorProvider(val world: World) : ExecutionContextProvider {
|
||||||
|
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext {
|
||||||
|
val evaluator = Evaluator(world)
|
||||||
|
nativeRegistry.forEachProvider { form, provider ->
|
||||||
|
evaluator.addNativeProvider(form, AdaptedNativeProvider(provider))
|
||||||
|
}
|
||||||
|
val slab = evaluator.slabContext(importLocator)
|
||||||
|
slab.finalizeScope()
|
||||||
|
return EvaluatorExecutionContext(evaluator, slab, entryPointSymbol)
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,6 @@ package gay.pizza.pork.evaluator
|
|||||||
|
|
||||||
import gay.pizza.pork.ast.gen.ArgumentSpec
|
import gay.pizza.pork.ast.gen.ArgumentSpec
|
||||||
|
|
||||||
interface NativeProvider {
|
interface ExpandedNativeProvider {
|
||||||
fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>, inside: SlabContext): CallableFunction
|
fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>, inside: SlabContext): CallableFunction
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
import gay.pizza.pork.ast.gen.FunctionDefinition
|
import gay.pizza.pork.ast.gen.FunctionDefinition
|
||||||
|
import gay.pizza.pork.execution.ArgumentList
|
||||||
|
|
||||||
class FunctionContext(val slabContext: SlabContext, val node: FunctionDefinition) : CallableFunction {
|
class FunctionContext(val slabContext: SlabContext, val node: FunctionDefinition) : CallableFunction {
|
||||||
val name: String by lazy { "${slabContext.slab.location.commonFriendlyName} ${node.symbol.id}" }
|
val name: String by lazy { "${slabContext.slab.location.commonFriendlyName} ${node.symbol.id}" }
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package gay.pizza.pork.evaluator
|
|
||||||
|
|
||||||
import gay.pizza.pork.ast.gen.ArgumentSpec
|
|
||||||
import gay.pizza.pork.common.unused
|
|
||||||
|
|
||||||
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
|
|
||||||
private val functions = mutableMapOf(
|
|
||||||
"print" to CallableFunction(::printValues),
|
|
||||||
"println" to CallableFunction(::printLine),
|
|
||||||
"listSet" to CallableFunction(::setInList),
|
|
||||||
"listInitWith" to CallableFunction(::listInitWith)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun add(name: String, function: CallableFunction) {
|
|
||||||
functions[name] = function
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun provideNativeFunction(
|
|
||||||
definitions: List<String>,
|
|
||||||
arguments: List<ArgumentSpec>,
|
|
||||||
inside: SlabContext
|
|
||||||
): CallableFunction {
|
|
||||||
val definition = definitions[0]
|
|
||||||
return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printValues(arguments: ArgumentList, stack: CallStack): Any {
|
|
||||||
unused(stack)
|
|
||||||
if (quiet || arguments.isEmpty()) return None
|
|
||||||
print(arguments.joinToString(" "))
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printLine(arguments: ArgumentList, stack: CallStack): Any {
|
|
||||||
unused(stack)
|
|
||||||
if (quiet) return None
|
|
||||||
println(arguments.joinToString(" "))
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setInList(arguments: ArgumentList, stack: CallStack): Any {
|
|
||||||
unused(stack)
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
val list = arguments[0] as MutableList<Any>
|
|
||||||
val value = arguments[2]
|
|
||||||
list[(arguments[1] as Number).toInt()] = value
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun listInitWith(arguments: ArgumentList, stack: CallStack): Any {
|
|
||||||
unused(stack)
|
|
||||||
val size = (arguments[0] as Number).toInt()
|
|
||||||
return MutableList(size) { arguments[1] }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
package gay.pizza.pork.evaluator
|
|
||||||
|
|
||||||
data object None
|
|
@ -1,5 +1,7 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.execution.None
|
||||||
|
|
||||||
class Scope(
|
class Scope(
|
||||||
var parent: Scope? = null,
|
var parent: Scope? = null,
|
||||||
var inherits: List<Scope> = emptyList(),
|
var inherits: List<Scope> = emptyList(),
|
||||||
|
@ -16,7 +16,7 @@ class SlabContext(val slab: Slab, val evaluator: Evaluator, rootScope: Scope) {
|
|||||||
|
|
||||||
fun ensureImportedContextsExist() {
|
fun ensureImportedContextsExist() {
|
||||||
for (importedSlab in slab.importedSlabs) {
|
for (importedSlab in slab.importedSlabs) {
|
||||||
evaluator.context(importedSlab)
|
evaluator.slabContext(importedSlab)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class SlabContext(val slab: Slab, val evaluator: Evaluator, rootScope: Scope) {
|
|||||||
|
|
||||||
private fun processFinalImportScopes() {
|
private fun processFinalImportScopes() {
|
||||||
for (importedSlab in slab.importedSlabs) {
|
for (importedSlab in slab.importedSlabs) {
|
||||||
val importedSlabContext = evaluator.context(importedSlab)
|
val importedSlabContext = evaluator.slabContext(importedSlab)
|
||||||
importedSlabContext.processFinalImportScopes()
|
importedSlabContext.processFinalImportScopes()
|
||||||
internalScope.inherit(importedSlabContext.externalScope)
|
internalScope.inherit(importedSlabContext.externalScope)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.execution.None
|
||||||
|
|
||||||
class ValueStore(var value: Any, var type: ValueStoreType) {
|
class ValueStore(var value: Any, var type: ValueStoreType) {
|
||||||
var isCurrentlyFree = false
|
var isCurrentlyFree = false
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
export func main() {
|
export func main() {
|
||||||
var x = 1
|
var x = 1
|
||||||
while x <= 5 {
|
while x <= 5 {
|
||||||
if x == 3 {
|
println(x)
|
||||||
println("The value is 3")
|
|
||||||
} else {
|
|
||||||
println("The value is not 3")
|
|
||||||
}
|
|
||||||
x++
|
x++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.execution
|
||||||
|
|
||||||
|
typealias ArgumentList = List<Any>
|
||||||
|
|
||||||
|
inline fun <reified T> ArgumentList.at(index: Int): T = this[index] as T
|
@ -4,5 +4,5 @@ import gay.pizza.pork.ast.gen.Symbol
|
|||||||
import gay.pizza.pork.frontend.ImportLocator
|
import gay.pizza.pork.frontend.ImportLocator
|
||||||
|
|
||||||
interface ExecutionContextProvider {
|
interface ExecutionContextProvider {
|
||||||
fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext
|
fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package gay.pizza.pork.execution
|
||||||
|
|
||||||
|
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
|
||||||
|
private val functions = mutableMapOf(
|
||||||
|
"print" to NativeFunction(::printValues),
|
||||||
|
"println" to NativeFunction(::printLine),
|
||||||
|
"listSet" to NativeFunction(::setInList),
|
||||||
|
"listInitWith" to NativeFunction(::listInitWith)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun add(name: String, function: NativeFunction) {
|
||||||
|
functions[name] = function
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun provideNativeFunction(definitions: List<String>): NativeFunction {
|
||||||
|
val definition = definitions[0]
|
||||||
|
return functions[definition] ?:
|
||||||
|
throw RuntimeException("Unknown internal function: $definition")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printValues(arguments: ArgumentList): Any {
|
||||||
|
if (quiet || arguments.isEmpty()) return None
|
||||||
|
print(arguments.at<List<*>>(0).joinToString(" ") { it.toString() })
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printLine(arguments: ArgumentList): Any {
|
||||||
|
if (quiet) return None
|
||||||
|
println(arguments.at<List<*>>(0).joinToString(" ") { it.toString() })
|
||||||
|
return Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInList(arguments: ArgumentList): Any {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val list = arguments[0] as MutableList<Any>
|
||||||
|
val value = arguments[2]
|
||||||
|
list[(arguments.at<Number>(0)).toInt()] = value
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listInitWith(arguments: ArgumentList): Any {
|
||||||
|
val size = arguments.at<Number>(0).toInt()
|
||||||
|
return MutableList(size) { arguments[1] }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.execution
|
||||||
|
|
||||||
|
fun interface NativeFunction {
|
||||||
|
fun invoke(args: ArgumentList): Any
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.execution
|
||||||
|
|
||||||
|
interface NativeProvider {
|
||||||
|
fun provideNativeFunction(definitions: List<String>): NativeFunction
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package gay.pizza.pork.execution
|
||||||
|
|
||||||
|
class NativeRegistry {
|
||||||
|
private val providers = mutableMapOf<String, NativeProvider>()
|
||||||
|
|
||||||
|
fun add(form: String, provider: NativeProvider) {
|
||||||
|
providers[form] = provider
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forEachProvider(block: (String, NativeProvider) -> Unit) {
|
||||||
|
for ((form, provider) in providers) {
|
||||||
|
block(form, provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun of(form: String): NativeProvider =
|
||||||
|
providers[form] ?: throw RuntimeException("Unknown native form: ${form}")
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
package gay.pizza.pork.execution
|
||||||
|
|
||||||
|
data object None
|
@ -4,11 +4,13 @@ import com.kenai.jffi.*
|
|||||||
import com.kenai.jffi.Function
|
import com.kenai.jffi.Function
|
||||||
import gay.pizza.pork.ast.gen.ArgumentSpec
|
import gay.pizza.pork.ast.gen.ArgumentSpec
|
||||||
import gay.pizza.pork.evaluator.*
|
import gay.pizza.pork.evaluator.*
|
||||||
|
import gay.pizza.pork.execution.ArgumentList
|
||||||
|
import gay.pizza.pork.execution.None
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.absolutePathString
|
import kotlin.io.path.absolutePathString
|
||||||
import kotlin.io.path.exists
|
import kotlin.io.path.exists
|
||||||
|
|
||||||
class FfiNativeProvider : NativeProvider {
|
class FfiNativeProvider : ExpandedNativeProvider {
|
||||||
private val internalFunctions = mutableMapOf<String, (ArgumentList) -> Any>(
|
private val internalFunctions = mutableMapOf<String, (ArgumentList) -> Any>(
|
||||||
"ffiStructDefine" to ::ffiStructDefine,
|
"ffiStructDefine" to ::ffiStructDefine,
|
||||||
"ffiStructAllocate" to ::ffiStructAllocate,
|
"ffiStructAllocate" to ::ffiStructAllocate,
|
||||||
|
@ -2,7 +2,7 @@ package gay.pizza.pork.ffi
|
|||||||
|
|
||||||
import com.kenai.jffi.InvocationBuffer
|
import com.kenai.jffi.InvocationBuffer
|
||||||
import com.kenai.jffi.MemoryIO
|
import com.kenai.jffi.MemoryIO
|
||||||
import gay.pizza.pork.evaluator.None
|
import gay.pizza.pork.execution.None
|
||||||
|
|
||||||
enum class FfiPrimitiveType(
|
enum class FfiPrimitiveType(
|
||||||
val id: kotlin.String,
|
val id: kotlin.String,
|
||||||
|
@ -3,7 +3,7 @@ package gay.pizza.pork.ffi
|
|||||||
import com.kenai.jffi.InvocationBuffer
|
import com.kenai.jffi.InvocationBuffer
|
||||||
import com.kenai.jffi.MemoryIO
|
import com.kenai.jffi.MemoryIO
|
||||||
import com.kenai.jffi.Struct
|
import com.kenai.jffi.Struct
|
||||||
import gay.pizza.pork.evaluator.None
|
import gay.pizza.pork.execution.None
|
||||||
|
|
||||||
class FfiStruct(val ffiTypeRegistry: FfiTypeRegistry) : FfiType {
|
class FfiStruct(val ffiTypeRegistry: FfiTypeRegistry) : FfiType {
|
||||||
private val fields = LinkedHashMap<String, FfiStructField>()
|
private val fields = LinkedHashMap<String, FfiStructField>()
|
||||||
|
@ -3,12 +3,12 @@ package gay.pizza.pork.ffi
|
|||||||
import gay.pizza.pork.ast.gen.ArgumentSpec
|
import gay.pizza.pork.ast.gen.ArgumentSpec
|
||||||
import gay.pizza.pork.evaluator.CallableFunction
|
import gay.pizza.pork.evaluator.CallableFunction
|
||||||
import gay.pizza.pork.evaluator.SlabContext
|
import gay.pizza.pork.evaluator.SlabContext
|
||||||
import gay.pizza.pork.evaluator.NativeProvider
|
import gay.pizza.pork.evaluator.ExpandedNativeProvider
|
||||||
import gay.pizza.pork.evaluator.None
|
import gay.pizza.pork.execution.None
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.invoke.MethodType
|
import java.lang.invoke.MethodType
|
||||||
|
|
||||||
class JavaNativeProvider : NativeProvider {
|
class JavaNativeProvider : ExpandedNativeProvider {
|
||||||
private val lookup = MethodHandles.lookup()
|
private val lookup = MethodHandles.lookup()
|
||||||
|
|
||||||
override fun provideNativeFunction(
|
override fun provideNativeFunction(
|
||||||
|
@ -104,7 +104,7 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor<Unit>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSetAssignment(node: SetAssignment) {
|
override fun visitSetAssignment(node: SetAssignment) {
|
||||||
node.visitChildren(this)
|
node.value.visit(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringLiteral(node: StringLiteral) {
|
override fun visitStringLiteral(node: StringLiteral) {
|
||||||
|
@ -10,6 +10,7 @@ dependencies {
|
|||||||
api(project(":parser"))
|
api(project(":parser"))
|
||||||
api(project(":frontend"))
|
api(project(":frontend"))
|
||||||
api(project(":evaluator"))
|
api(project(":evaluator"))
|
||||||
|
api(project(":vm"))
|
||||||
api(project(":stdlib"))
|
api(project(":stdlib"))
|
||||||
api(project(":ffi"))
|
api(project(":ffi"))
|
||||||
implementation(project(":common"))
|
implementation(project(":common"))
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package gay.pizza.pork.minimal
|
||||||
|
|
||||||
|
import gay.pizza.pork.evaluator.EvaluatorProvider
|
||||||
|
import gay.pizza.pork.execution.ExecutionContextProvider
|
||||||
|
import gay.pizza.pork.frontend.World
|
||||||
|
import gay.pizza.pork.vm.VirtualMachineProvider
|
||||||
|
|
||||||
|
enum class ExecutionType(val id: String, val create: (World) -> ExecutionContextProvider) {
|
||||||
|
Evaluator("evaluator", { world -> EvaluatorProvider(world) }),
|
||||||
|
VirtualMachine("virtual-machine", { world -> VirtualMachineProvider(world) })
|
||||||
|
}
|
@ -2,8 +2,13 @@ package gay.pizza.pork.minimal
|
|||||||
|
|
||||||
import gay.pizza.pork.ast.gen.CompilationUnit
|
import gay.pizza.pork.ast.gen.CompilationUnit
|
||||||
import gay.pizza.pork.ast.gen.NodeVisitor
|
import gay.pizza.pork.ast.gen.NodeVisitor
|
||||||
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
import gay.pizza.pork.ast.gen.visit
|
import gay.pizza.pork.ast.gen.visit
|
||||||
import gay.pizza.pork.evaluator.*
|
import gay.pizza.pork.evaluator.*
|
||||||
|
import gay.pizza.pork.execution.ExecutionContext
|
||||||
|
import gay.pizza.pork.execution.ExecutionContextProvider
|
||||||
|
import gay.pizza.pork.execution.InternalNativeProvider
|
||||||
|
import gay.pizza.pork.execution.NativeRegistry
|
||||||
import gay.pizza.pork.ffi.FfiNativeProvider
|
import gay.pizza.pork.ffi.FfiNativeProvider
|
||||||
import gay.pizza.pork.ffi.JavaAutogenContentSource
|
import gay.pizza.pork.ffi.JavaAutogenContentSource
|
||||||
import gay.pizza.pork.ffi.JavaNativeProvider
|
import gay.pizza.pork.ffi.JavaNativeProvider
|
||||||
@ -36,20 +41,13 @@ abstract class Tool {
|
|||||||
|
|
||||||
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
||||||
|
|
||||||
fun loadMainFunction(setupEvaluator: Evaluator.() -> Unit = {}): CallableFunction {
|
fun createExecutionContextProvider(type: ExecutionType): ExecutionContextProvider =
|
||||||
val world = buildWorld()
|
type.create(buildWorld())
|
||||||
val evaluator = Evaluator(world)
|
|
||||||
setupEvaluator(evaluator)
|
|
||||||
val resultingScope = evaluator.evaluate(rootImportLocator)
|
|
||||||
return resultingScope.value("main") as CallableFunction
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadMainFunctionStandard(quiet: Boolean = false): CallableFunction =
|
fun createExecutionContext(type: ExecutionType, symbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext {
|
||||||
loadMainFunction(setupEvaluator = {
|
val executionContextProvider = createExecutionContextProvider(type)
|
||||||
addNativeProvider("internal", InternalNativeProvider(quiet = quiet))
|
return executionContextProvider.prepare(rootImportLocator, symbol, nativeRegistry)
|
||||||
addNativeProvider("ffi", FfiNativeProvider())
|
}
|
||||||
addNativeProvider("java", JavaNativeProvider())
|
|
||||||
})
|
|
||||||
|
|
||||||
fun buildWorld(): World {
|
fun buildWorld(): World {
|
||||||
val fileContentSource = createContentSource()
|
val fileContentSource = createContentSource()
|
||||||
@ -59,9 +57,4 @@ abstract class Tool {
|
|||||||
dynamicImportSource.addContentSource("java", JavaAutogenContentSource)
|
dynamicImportSource.addContentSource("java", JavaAutogenContentSource)
|
||||||
return World(dynamicImportSource)
|
return World(dynamicImportSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun run(quiet: Boolean = false) {
|
|
||||||
val main = loadMainFunctionStandard(quiet = quiet)
|
|
||||||
main.call(emptyList(), CallStack())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package gay.pizza.pork.minimal
|
package gay.pizza.pork.minimal
|
||||||
|
|
||||||
import gay.pizza.dough.fs.PlatformFsProvider
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
import gay.pizza.pork.evaluator.Scope
|
import gay.pizza.pork.evaluator.Scope
|
||||||
|
import gay.pizza.pork.execution.InternalNativeProvider
|
||||||
|
import gay.pizza.pork.execution.NativeRegistry
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
@ -11,5 +14,12 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
val path = PlatformFsProvider.resolve(args[0])
|
val path = PlatformFsProvider.resolve(args[0])
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(path)
|
||||||
tool.run()
|
val nativeRegistry = NativeRegistry()
|
||||||
|
nativeRegistry.add("internal", InternalNativeProvider(quiet = false))
|
||||||
|
val main = tool.createExecutionContext(
|
||||||
|
ExecutionType.Evaluator,
|
||||||
|
Symbol("main"),
|
||||||
|
nativeRegistry
|
||||||
|
)
|
||||||
|
main.execute()
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ object PorkElementFactory {
|
|||||||
NodeType.ForIn -> ForInElement(node)
|
NodeType.ForIn -> ForInElement(node)
|
||||||
NodeType.Break -> BreakElement(node)
|
NodeType.Break -> BreakElement(node)
|
||||||
NodeType.Continue -> ContinueElement(node)
|
NodeType.Continue -> ContinueElement(node)
|
||||||
|
NodeType.Return -> ReturnElement(node)
|
||||||
NodeType.NoneLiteral -> NoneLiteralElement(node)
|
NodeType.NoneLiteral -> NoneLiteralElement(node)
|
||||||
NodeType.NativeFunctionDescriptor -> NativeFunctionDescriptorElement(node)
|
NodeType.NativeFunctionDescriptor -> NativeFunctionDescriptorElement(node)
|
||||||
NodeType.IndexedBy -> IndexedByElement(node)
|
NodeType.IndexedBy -> IndexedByElement(node)
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.idea.psi.gen
|
||||||
|
|
||||||
|
import com.intellij.lang.ASTNode
|
||||||
|
import com.intellij.navigation.ItemPresentation
|
||||||
|
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ReturnElement(node: ASTNode) : PorkElement(node) {
|
||||||
|
override fun getIcon(flags: Int): Icon? =
|
||||||
|
PorkElementHelpers.iconOf(this)
|
||||||
|
|
||||||
|
override fun getPresentation(): ItemPresentation? =
|
||||||
|
PorkElementHelpers.presentationOf(this)
|
||||||
|
}
|
@ -6,7 +6,6 @@ import gay.pizza.dough.fs.PlatformFsProvider
|
|||||||
import gay.pizza.pork.ast.gen.Symbol
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
import gay.pizza.pork.compiler.Compiler
|
import gay.pizza.pork.compiler.Compiler
|
||||||
import gay.pizza.pork.minimal.FileTool
|
import gay.pizza.pork.minimal.FileTool
|
||||||
import gay.pizza.pork.vm.VirtualMachine
|
|
||||||
|
|
||||||
class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") {
|
class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") {
|
||||||
val path by argument("file")
|
val path by argument("file")
|
||||||
@ -32,7 +31,5 @@ class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "c
|
|||||||
println(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
|
println(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val vm = VirtualMachine(compiledWorld)
|
|
||||||
vm.execute()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,33 +2,33 @@ package gay.pizza.pork.tool
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
|
import com.github.ajalt.clikt.parameters.options.default
|
||||||
import com.github.ajalt.clikt.parameters.options.flag
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
import com.github.ajalt.clikt.parameters.options.option
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
|
import com.github.ajalt.clikt.parameters.types.enum
|
||||||
import gay.pizza.dough.fs.PlatformFsProvider
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
import gay.pizza.pork.evaluator.*
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
|
import gay.pizza.pork.execution.InternalNativeProvider
|
||||||
|
import gay.pizza.pork.execution.NativeRegistry
|
||||||
|
import gay.pizza.pork.minimal.ExecutionType
|
||||||
import gay.pizza.pork.minimal.FileTool
|
import gay.pizza.pork.minimal.FileTool
|
||||||
|
|
||||||
class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
||||||
val loop by option("--loop", help = "Loop Program").flag()
|
val loop by option("--loop", help = "Loop Program").flag()
|
||||||
val measure by option("--measure", help = "Measure Time").flag()
|
val measure by option("--measure", help = "Measure Time").flag()
|
||||||
val quiet by option("--quiet", help = "Silence Prints").flag()
|
val quiet by option("--quiet", help = "Silence Prints").flag()
|
||||||
val dumpScope by option("--dump-scope", help = "Dump Scope").flag()
|
val executionType by option("--execution-type", "-E")
|
||||||
|
.enum<ExecutionType> { it.id }
|
||||||
|
.default(ExecutionType.VirtualMachine)
|
||||||
val path by argument("file")
|
val path by argument("file")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(PlatformFsProvider.resolve(path))
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
val main = tool.loadMainFunctionStandard(quiet = quiet)
|
val nativeRegistry = NativeRegistry()
|
||||||
|
nativeRegistry.add("internal", InternalNativeProvider(quiet = quiet))
|
||||||
if (dumpScope) {
|
val main = tool.createExecutionContext(executionType, Symbol("main"), nativeRegistry)
|
||||||
val functionContext = main as FunctionContext
|
|
||||||
val internalScope = functionContext.slabContext.internalScope
|
|
||||||
internalScope.crawlScopePath { key, path ->
|
|
||||||
println("[scope] $key [${path.joinToString(" -> ")}]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maybeLoopAndMeasure(loop, measure) {
|
maybeLoopAndMeasure(loop, measure) {
|
||||||
main.call(emptyList(), CallStack())
|
main.execute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,9 @@ package gay.pizza.pork.vm
|
|||||||
|
|
||||||
import gay.pizza.pork.bytecode.CompiledWorld
|
import gay.pizza.pork.bytecode.CompiledWorld
|
||||||
import gay.pizza.pork.bytecode.ConstantTag
|
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 ->
|
private val inlined = world.code.map { op ->
|
||||||
val handler = handlers.firstOrNull { it.code == op.code } ?:
|
val handler = handlers.firstOrNull { it.code == op.code } ?:
|
||||||
throw VirtualMachineException("Opcode ${op.code.name} does not have a handler.")
|
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.bytecode.CompiledWorld
|
||||||
import gay.pizza.pork.execution.ExecutionContext
|
import gay.pizza.pork.execution.ExecutionContext
|
||||||
import gay.pizza.pork.vm.ops.*
|
import gay.pizza.pork.execution.NativeRegistry
|
||||||
|
|
||||||
class VirtualMachine(world: CompiledWorld) : ExecutionContext {
|
class VirtualMachine(world: CompiledWorld, nativeRegistry: NativeRegistry) : ExecutionContext {
|
||||||
private val internal = InternalMachine(world, listOf(
|
private val internal = InternalMachine(
|
||||||
IntegerOpHandler,
|
world = world,
|
||||||
ConstantOpHandler,
|
nativeRegistry = nativeRegistry,
|
||||||
|
handlers = StandardOpHandlers
|
||||||
TrueOpHandler,
|
)
|
||||||
FalseOpHandler,
|
|
||||||
|
|
||||||
NoneOpHandler,
|
|
||||||
|
|
||||||
ListMakeOpHandler,
|
|
||||||
ListSizeOpHandler,
|
|
||||||
|
|
||||||
IndexOpHandler,
|
|
||||||
|
|
||||||
AndOpHandler,
|
|
||||||
OrOpHandler,
|
|
||||||
NotOpHandler,
|
|
||||||
|
|
||||||
CompareEqualOpHandler,
|
|
||||||
CompareLesserEqualOpHandler,
|
|
||||||
CompareGreaterEqualOpHandler,
|
|
||||||
|
|
||||||
AddOpHandler,
|
|
||||||
|
|
||||||
JumpOpHandler,
|
|
||||||
JumpIfOpHandler,
|
|
||||||
|
|
||||||
LoadLocalOpHandler,
|
|
||||||
StoreLocalOpHandler,
|
|
||||||
|
|
||||||
ReturnAddressOpHandler,
|
|
||||||
CallOpHandler,
|
|
||||||
ReturnOpHandler,
|
|
||||||
|
|
||||||
NativeOpHandler,
|
|
||||||
|
|
||||||
ScopeInOpHandler,
|
|
||||||
ScopeOutOpHandler,
|
|
||||||
|
|
||||||
EndOpHandler
|
|
||||||
))
|
|
||||||
|
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
|
internal.reset()
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!internal.step()) {
|
if (!internal.step()) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal.reset()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,18 @@ import gay.pizza.pork.ast.gen.Symbol
|
|||||||
import gay.pizza.pork.compiler.Compiler
|
import gay.pizza.pork.compiler.Compiler
|
||||||
import gay.pizza.pork.execution.ExecutionContext
|
import gay.pizza.pork.execution.ExecutionContext
|
||||||
import gay.pizza.pork.execution.ExecutionContextProvider
|
import gay.pizza.pork.execution.ExecutionContextProvider
|
||||||
|
import gay.pizza.pork.execution.NativeRegistry
|
||||||
import gay.pizza.pork.frontend.ImportLocator
|
import gay.pizza.pork.frontend.ImportLocator
|
||||||
import gay.pizza.pork.frontend.World
|
import gay.pizza.pork.frontend.World
|
||||||
|
|
||||||
class VirtualMachineProvider(val world: World) : ExecutionContextProvider {
|
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 compiler = Compiler()
|
||||||
val slab = world.load(importLocator)
|
val slab = world.load(importLocator)
|
||||||
val compilableSlab = compiler.compilableSlabs.of(slab)
|
val compilableSlab = compiler.compilableSlabs.of(slab)
|
||||||
val compilableSymbol = compilableSlab.resolve(entryPointSymbol) ?:
|
val compilableSymbol = compilableSlab.resolve(entryPointSymbol) ?:
|
||||||
throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
|
throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
|
||||||
val compiledWorld = compiler.compile(compilableSymbol)
|
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) {
|
object NativeOpHandler : OpHandler(Opcode.Native) {
|
||||||
override fun handle(machine: InternalMachine, op: Op) {
|
override fun handle(machine: InternalMachine, op: Op) {
|
||||||
|
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 countOfNativeDefs = op.args[1].toInt()
|
||||||
val defs = mutableListOf<Any>()
|
val defs = mutableListOf<String>()
|
||||||
for (i in 0 until countOfNativeDefs) {
|
for (i in 0 until countOfNativeDefs) {
|
||||||
defs.add(machine.pop() as String)
|
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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user