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

@ -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) }
}
}

View File

@ -1,3 +0,0 @@
package gay.pizza.pork.evaluator
typealias ArgumentList = List<Any>

View File

@ -1,5 +1,7 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.execution.ArgumentList
fun interface CallableFunction {
fun call(arguments: ArgumentList, stack: CallStack): Any
}

View File

@ -2,6 +2,7 @@ package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.FunctionLevelVisitor
import gay.pizza.pork.ast.gen.*
import gay.pizza.pork.execution.None
import kotlin.math.abs
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")

View File

@ -1,24 +1,21 @@
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.Slab
import gay.pizza.pork.frontend.World
class Evaluator(val world: World) : ExecutionContextProvider {
class Evaluator(val world: World) {
private val scope = Scope.root()
private val contexts = mutableMapOf<Slab, SlabContext>()
private val nativeProviders = mutableMapOf<String, NativeProvider>()
private val nativeProviders = mutableMapOf<String, ExpandedNativeProvider>()
fun evaluate(locator: ImportLocator): Scope {
val slabContext = context(locator)
val slabContext = slabContext(locator)
slabContext.finalizeScope()
return slabContext.externalScope
}
fun context(slab: Slab): SlabContext {
fun slabContext(slab: Slab): SlabContext {
val slabContext = contexts.computeIfAbsent(slab) {
SlabContext(slab, this, scope)
}
@ -26,20 +23,14 @@ class Evaluator(val world: World) : ExecutionContextProvider {
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] ?:
throw RuntimeException("Unknown native function form: $form")
}
fun addNativeProvider(form: String, nativeProvider: NativeProvider) {
fun addNativeProvider(form: String, nativeProvider: ExpandedNativeProvider) {
nativeProviders[form] = nativeProvider
}
override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext {
val slab = context(importLocator)
slab.finalizeScope()
return EvaluatorExecutionContext(this, slab, entryPointSymbol)
}
}

View File

@ -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)
}
}

View File

@ -2,6 +2,6 @@ package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.gen.ArgumentSpec
interface NativeProvider {
interface ExpandedNativeProvider {
fun provideNativeFunction(definitions: List<String>, arguments: List<ArgumentSpec>, inside: SlabContext): CallableFunction
}

View File

@ -1,6 +1,7 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.gen.FunctionDefinition
import gay.pizza.pork.execution.ArgumentList
class FunctionContext(val slabContext: SlabContext, val node: FunctionDefinition) : CallableFunction {
val name: String by lazy { "${slabContext.slab.location.commonFriendlyName} ${node.symbol.id}" }

View File

@ -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] }
}
}

View File

@ -1,3 +0,0 @@
package gay.pizza.pork.evaluator
data object None

View File

@ -1,5 +1,7 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.execution.None
class Scope(
var parent: Scope? = null,
var inherits: List<Scope> = emptyList(),

View File

@ -16,7 +16,7 @@ class SlabContext(val slab: Slab, val evaluator: Evaluator, rootScope: Scope) {
fun ensureImportedContextsExist() {
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() {
for (importedSlab in slab.importedSlabs) {
val importedSlabContext = evaluator.context(importedSlab)
val importedSlabContext = evaluator.slabContext(importedSlab)
importedSlabContext.processFinalImportScopes()
internalScope.inherit(importedSlabContext.externalScope)
}

View File

@ -1,5 +1,7 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.execution.None
class ValueStore(var value: Any, var type: ValueStoreType) {
var isCurrentlyFree = false