Skip to content

Commit

Permalink
global: a working virtual machine for some of the use cases. APIs and…
Browse files Browse the repository at this point in the history
… validation still WIP.
  • Loading branch information
azenla committed Nov 22, 2023
1 parent 0a2d029 commit 6211ad4
Show file tree
Hide file tree
Showing 53 changed files with 432 additions and 180 deletions.
7 changes: 7 additions & 0 deletions bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Constant.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import kotlinx.serialization.Serializable

@Serializable
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 {
if (this === other) return true
other as Constant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ package gay.pizza.pork.bytecode
import kotlinx.serialization.Serializable

@Serializable
data class ConstantPool(val constants: List<Constant>)
data class ConstantPool(val constants: List<Constant>) {
fun read(index: UInt): Constant = constants[index.toInt()]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ class CompilableSlab(val compiler: Compiler, val slab: Slab) {
fun resolve(symbol: Symbol): CompilableSymbol? = compilableSymbols.firstOrNull {
it.scopeSymbol.symbol == symbol
}

fun resolveVisible(symbol: Symbol): CompilableSymbol? {
val scopeSymbol = slab.scope.resolve(symbol) ?: return null
return compiler.resolveOrNull(scopeSymbol)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class LocalState(val symbol: CompilableSymbol) {
return Loadable(stubVar = found)
}
}
val found = this.symbol.compilableSlab.resolve(symbol)
val found = this.symbol.compilableSlab.resolveVisible(symbol)
if (found != null) {
return Loadable(call = found)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,9 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
code.emit(Opcode.Constant, listOf(defConstant))
}
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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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) }
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
23 changes: 7 additions & 16 deletions evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt
Original file line number Diff line number Diff line change
@@ -1,45 +1,36 @@
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)
}
slabContext.ensureImportedContextsExist()
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)
}
}
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
@@ -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}" }
Expand Down

This file was deleted.

3 changes: 0 additions & 3 deletions evaluator/src/main/kotlin/gay/pizza/pork/evaluator/None.kt

This file was deleted.

2 changes: 2 additions & 0 deletions evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt
Original file line number Diff line number Diff line change
@@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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

Expand Down
6 changes: 1 addition & 5 deletions examples/count.pork
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
export func main() {
var x = 1
while x <= 5 {
if x == 3 {
println("The value is 3")
} else {
println("The value is not 3")
}
println(x)
x++
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import gay.pizza.pork.ast.gen.Symbol
import gay.pizza.pork.frontend.ImportLocator

interface ExecutionContextProvider {
fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol): ExecutionContext
fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext
}
Original file line number Diff line number Diff line change
@@ -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] }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gay.pizza.pork.execution

fun interface NativeFunction {
fun invoke(args: ArgumentList): Any
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gay.pizza.pork.execution

interface NativeProvider {
fun provideNativeFunction(definitions: List<String>): NativeFunction
}
Original file line number Diff line number Diff line change
@@ -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}")
}
3 changes: 3 additions & 0 deletions execution/src/main/kotlin/gay/pizza/pork/execution/None.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package gay.pizza.pork.execution

data object None
4 changes: 3 additions & 1 deletion ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import com.kenai.jffi.*
import com.kenai.jffi.Function
import gay.pizza.pork.ast.gen.ArgumentSpec
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.absolutePathString
import kotlin.io.path.exists

class FfiNativeProvider : NativeProvider {
class FfiNativeProvider : ExpandedNativeProvider {
private val internalFunctions = mutableMapOf<String, (ArgumentList) -> Any>(
"ffiStructDefine" to ::ffiStructDefine,
"ffiStructAllocate" to ::ffiStructAllocate,
Expand Down
Loading

0 comments on commit 6211ad4

Please sign in to comment.