diff --git a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Constant.kt b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Constant.kt index b566e28..d85a869 100644 --- a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Constant.kt +++ b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Constant.kt @@ -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 diff --git a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/ConstantPool.kt b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/ConstantPool.kt index 152e2ad..7273437 100644 --- a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/ConstantPool.kt +++ b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/ConstantPool.kt @@ -3,4 +3,6 @@ package gay.pizza.pork.bytecode import kotlinx.serialization.Serializable @Serializable -data class ConstantPool(val constants: List) +data class ConstantPool(val constants: List) { + fun read(index: UInt): Constant = constants[index.toInt()] +} diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt index 6b6db1b..875fdb1 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt @@ -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) + } } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalState.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalState.kt index 4bf8651..69b11d7 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalState.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalState.kt @@ -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) } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt index b9f5adc..21ef47a 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt @@ -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) { diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/AdaptedNativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/AdaptedNativeProvider.kt new file mode 100644 index 0000000..b82a229 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/AdaptedNativeProvider.kt @@ -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, + arguments: List, + inside: SlabContext + ): CallableFunction { + val function = provider.provideNativeFunction(definitions) + return CallableFunction { args, _ -> function.invoke(args) } + } +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt deleted file mode 100644 index b4f87b0..0000000 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt +++ /dev/null @@ -1,3 +0,0 @@ -package gay.pizza.pork.evaluator - -typealias ArgumentList = List diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt index aed6bdd..928801b 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt @@ -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 } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt index c9699d9..03869be 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -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") diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt index 36d9230..ee85c17 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Evaluator.kt @@ -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() - private val nativeProviders = mutableMapOf() + private val nativeProviders = mutableMapOf() 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) - } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluatorProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluatorProvider.kt new file mode 100644 index 0000000..9aa4c1f --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluatorProvider.kt @@ -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) + } +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ExpandedNativeProvider.kt similarity index 85% rename from evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt rename to evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ExpandedNativeProvider.kt index 24fa606..4b44dbb 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/NativeProvider.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ExpandedNativeProvider.kt @@ -2,6 +2,6 @@ package gay.pizza.pork.evaluator import gay.pizza.pork.ast.gen.ArgumentSpec -interface NativeProvider { +interface ExpandedNativeProvider { fun provideNativeFunction(definitions: List, arguments: List, inside: SlabContext): CallableFunction } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt index f68bd55..a15046c 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt @@ -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}" } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt deleted file mode 100644 index e308acd..0000000 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt +++ /dev/null @@ -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, - arguments: List, - 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 - 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] } - } -} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/None.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/None.kt deleted file mode 100644 index b9c123e..0000000 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/None.kt +++ /dev/null @@ -1,3 +0,0 @@ -package gay.pizza.pork.evaluator - -data object None diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt index a76187a..9fe6401 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt @@ -1,5 +1,7 @@ package gay.pizza.pork.evaluator +import gay.pizza.pork.execution.None + class Scope( var parent: Scope? = null, var inherits: List = emptyList(), diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/SlabContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/SlabContext.kt index c1085c4..1470b88 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/SlabContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/SlabContext.kt @@ -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) } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt index 5d437c6..9693a0e 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt @@ -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 diff --git a/examples/count.pork b/examples/count.pork index 4a3304e..8ae595e 100644 --- a/examples/count.pork +++ b/examples/count.pork @@ -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++ } } diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/ArgumentList.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/ArgumentList.kt new file mode 100644 index 0000000..c60127f --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/ArgumentList.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.execution + +typealias ArgumentList = List + +inline fun ArgumentList.at(index: Int): T = this[index] as T diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/ExecutionContextProvider.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/ExecutionContextProvider.kt index af3c085..34f20b1 100644 --- a/execution/src/main/kotlin/gay/pizza/pork/execution/ExecutionContextProvider.kt +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/ExecutionContextProvider.kt @@ -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 } diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt new file mode 100644 index 0000000..7048214 --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/InternalNativeProvider.kt @@ -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): 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>(0).joinToString(" ") { it.toString() }) + return None + } + + private fun printLine(arguments: ArgumentList): Any { + if (quiet) return None + println(arguments.at>(0).joinToString(" ") { it.toString() }) + return Unit + } + + private fun setInList(arguments: ArgumentList): Any { + @Suppress("UNCHECKED_CAST") + val list = arguments[0] as MutableList + val value = arguments[2] + list[(arguments.at(0)).toInt()] = value + return value + } + + private fun listInitWith(arguments: ArgumentList): Any { + val size = arguments.at(0).toInt() + return MutableList(size) { arguments[1] } + } +} diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeFunction.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeFunction.kt new file mode 100644 index 0000000..c4ae7bc --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeFunction.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.execution + +fun interface NativeFunction { + fun invoke(args: ArgumentList): Any +} diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt new file mode 100644 index 0000000..079c0c5 --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeProvider.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.execution + +interface NativeProvider { + fun provideNativeFunction(definitions: List): NativeFunction +} diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt new file mode 100644 index 0000000..7d04bf3 --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt @@ -0,0 +1,18 @@ +package gay.pizza.pork.execution + +class NativeRegistry { + private val providers = mutableMapOf() + + 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}") +} diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/None.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/None.kt new file mode 100644 index 0000000..275404b --- /dev/null +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/None.kt @@ -0,0 +1,3 @@ +package gay.pizza.pork.execution + +data object None diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt index 346fba1..a82d1c6 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt @@ -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 Any>( "ffiStructDefine" to ::ffiStructDefine, "ffiStructAllocate" to ::ffiStructAllocate, diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt index e46e499..cb77521 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiPrimitiveType.kt @@ -2,7 +2,7 @@ package gay.pizza.pork.ffi import com.kenai.jffi.InvocationBuffer import com.kenai.jffi.MemoryIO -import gay.pizza.pork.evaluator.None +import gay.pizza.pork.execution.None enum class FfiPrimitiveType( val id: kotlin.String, diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt index ed1965b..1321ebe 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiStruct.kt @@ -3,7 +3,7 @@ package gay.pizza.pork.ffi import com.kenai.jffi.InvocationBuffer import com.kenai.jffi.MemoryIO import com.kenai.jffi.Struct -import gay.pizza.pork.evaluator.None +import gay.pizza.pork.execution.None class FfiStruct(val ffiTypeRegistry: FfiTypeRegistry) : FfiType { private val fields = LinkedHashMap() diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt index a299bef..09ee76a 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt @@ -3,12 +3,12 @@ package gay.pizza.pork.ffi import gay.pizza.pork.ast.gen.ArgumentSpec import gay.pizza.pork.evaluator.CallableFunction import gay.pizza.pork.evaluator.SlabContext -import gay.pizza.pork.evaluator.NativeProvider -import gay.pizza.pork.evaluator.None +import gay.pizza.pork.evaluator.ExpandedNativeProvider +import gay.pizza.pork.execution.None import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType -class JavaNativeProvider : NativeProvider { +class JavaNativeProvider : ExpandedNativeProvider { private val lookup = MethodHandles.lookup() override fun provideNativeFunction( diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt index 9a1d3bf..0fb7b89 100644 --- a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt @@ -104,7 +104,7 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { } override fun visitSetAssignment(node: SetAssignment) { - node.visitChildren(this) + node.value.visit(this) } override fun visitStringLiteral(node: StringLiteral) { diff --git a/minimal/build.gradle.kts b/minimal/build.gradle.kts index 0c7aa60..b2bfa9c 100644 --- a/minimal/build.gradle.kts +++ b/minimal/build.gradle.kts @@ -10,6 +10,7 @@ dependencies { api(project(":parser")) api(project(":frontend")) api(project(":evaluator")) + api(project(":vm")) api(project(":stdlib")) api(project(":ffi")) implementation(project(":common")) diff --git a/minimal/src/main/kotlin/gay/pizza/pork/minimal/ExecutionType.kt b/minimal/src/main/kotlin/gay/pizza/pork/minimal/ExecutionType.kt new file mode 100644 index 0000000..c226b6a --- /dev/null +++ b/minimal/src/main/kotlin/gay/pizza/pork/minimal/ExecutionType.kt @@ -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) }) +} diff --git a/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt b/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt index ee4a8f5..0c85f37 100644 --- a/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt +++ b/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt @@ -2,8 +2,13 @@ package gay.pizza.pork.minimal import gay.pizza.pork.ast.gen.CompilationUnit 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.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.JavaAutogenContentSource import gay.pizza.pork.ffi.JavaNativeProvider @@ -36,20 +41,13 @@ abstract class Tool { fun visit(visitor: NodeVisitor): T = visitor.visit(parse()) - fun loadMainFunction(setupEvaluator: Evaluator.() -> Unit = {}): CallableFunction { - val world = buildWorld() - val evaluator = Evaluator(world) - setupEvaluator(evaluator) - val resultingScope = evaluator.evaluate(rootImportLocator) - return resultingScope.value("main") as CallableFunction - } + fun createExecutionContextProvider(type: ExecutionType): ExecutionContextProvider = + type.create(buildWorld()) - fun loadMainFunctionStandard(quiet: Boolean = false): CallableFunction = - loadMainFunction(setupEvaluator = { - addNativeProvider("internal", InternalNativeProvider(quiet = quiet)) - addNativeProvider("ffi", FfiNativeProvider()) - addNativeProvider("java", JavaNativeProvider()) - }) + fun createExecutionContext(type: ExecutionType, symbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext { + val executionContextProvider = createExecutionContextProvider(type) + return executionContextProvider.prepare(rootImportLocator, symbol, nativeRegistry) + } fun buildWorld(): World { val fileContentSource = createContentSource() @@ -59,9 +57,4 @@ abstract class Tool { dynamicImportSource.addContentSource("java", JavaAutogenContentSource) return World(dynamicImportSource) } - - fun run(quiet: Boolean = false) { - val main = loadMainFunctionStandard(quiet = quiet) - main.call(emptyList(), CallStack()) - } } diff --git a/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt b/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt index e185ec4..365f167 100644 --- a/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt +++ b/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt @@ -1,7 +1,10 @@ package gay.pizza.pork.minimal import gay.pizza.dough.fs.PlatformFsProvider +import gay.pizza.pork.ast.gen.Symbol import gay.pizza.pork.evaluator.Scope +import gay.pizza.pork.execution.InternalNativeProvider +import gay.pizza.pork.execution.NativeRegistry import kotlin.system.exitProcess fun main(args: Array) { @@ -11,5 +14,12 @@ fun main(args: Array) { } val path = PlatformFsProvider.resolve(args[0]) 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() } diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt index c9206f7..93cd476 100644 --- a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt @@ -39,6 +39,7 @@ object PorkElementFactory { NodeType.ForIn -> ForInElement(node) NodeType.Break -> BreakElement(node) NodeType.Continue -> ContinueElement(node) + NodeType.Return -> ReturnElement(node) NodeType.NoneLiteral -> NoneLiteralElement(node) NodeType.NativeFunctionDescriptor -> NativeFunctionDescriptorElement(node) NodeType.IndexedBy -> IndexedByElement(node) diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/ReturnElement.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/ReturnElement.kt new file mode 100644 index 0000000..1f18a1b --- /dev/null +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/ReturnElement.kt @@ -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) +} diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt index ee91f25..e8d9b67 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt @@ -6,7 +6,6 @@ import gay.pizza.dough.fs.PlatformFsProvider import gay.pizza.pork.ast.gen.Symbol import gay.pizza.pork.compiler.Compiler import gay.pizza.pork.minimal.FileTool -import gay.pizza.pork.vm.VirtualMachine class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") { 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}") } } - val vm = VirtualMachine(compiledWorld) - vm.execute() } } diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt index 9f81f34..14440b2 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt @@ -2,33 +2,33 @@ package gay.pizza.pork.tool import com.github.ajalt.clikt.core.CliktCommand 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.option +import com.github.ajalt.clikt.parameters.types.enum 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 class RunCommand : CliktCommand(help = "Run Program", name = "run") { val loop by option("--loop", help = "Loop Program").flag() val measure by option("--measure", help = "Measure Time").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 { it.id } + .default(ExecutionType.VirtualMachine) val path by argument("file") override fun run() { val tool = FileTool(PlatformFsProvider.resolve(path)) - val main = tool.loadMainFunctionStandard(quiet = quiet) - - if (dumpScope) { - val functionContext = main as FunctionContext - val internalScope = functionContext.slabContext.internalScope - internalScope.crawlScopePath { key, path -> - println("[scope] $key [${path.joinToString(" -> ")}]") - } - } - + val nativeRegistry = NativeRegistry() + nativeRegistry.add("internal", InternalNativeProvider(quiet = quiet)) + val main = tool.createExecutionContext(executionType, Symbol("main"), nativeRegistry) maybeLoopAndMeasure(loop, measure) { - main.call(emptyList(), CallStack()) + main.execute() } } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt index 6b160ad..b0217a0 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt @@ -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) { +class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegistry, val handlers: List) { 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.") diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt new file mode 100644 index 0000000..5591e3a --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt @@ -0,0 +1,56 @@ +package gay.pizza.pork.vm + +import gay.pizza.pork.vm.ops.* + +val StandardOpHandlers: List = 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 +) diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt index 72ff202..3a4c008 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt @@ -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() } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt index 768ea0a..9b39618 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt @@ -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) } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryAndOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryAndOpHandler.kt new file mode 100644 index 0000000..cd224ff --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryAndOpHandler.kt @@ -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() + val left = machine.pop() + machine.push(left and right) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryNotOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryNotOpHandler.kt new file mode 100644 index 0000000..0dbec72 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryNotOpHandler.kt @@ -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() + machine.push(value.inv()) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryOrOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryOrOpHandler.kt new file mode 100644 index 0000000..7a425f3 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/BinaryOrOpHandler.kt @@ -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() + val left = machine.pop() + machine.push(left or right) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/CompareGreaterOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/CompareGreaterOpHandler.kt new file mode 100644 index 0000000..105151f --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/CompareGreaterOpHandler.kt @@ -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() + val left = machine.pop() + machine.push(left > right) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/CompareLesserOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/CompareLesserOpHandler.kt new file mode 100644 index 0000000..80c709e --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/CompareLesserOpHandler.kt @@ -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() + val left = machine.pop() + machine.push(left < right) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/MultiplyOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/MultiplyOpHandler.kt new file mode 100644 index 0000000..e44ee98 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/MultiplyOpHandler.kt @@ -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() + val right = machine.pop() + machine.push(left * right) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt index f3d3062..8cab8e1 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt @@ -7,10 +7,21 @@ import gay.pizza.pork.vm.OpHandler object NativeOpHandler : OpHandler(Opcode.Native) { override fun handle(machine: InternalMachine, op: Op) { + val argumentCount = op.args[2] + val arguments = mutableListOf() + 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() + val defs = mutableListOf() for (i in 0 until countOfNativeDefs) { - defs.add(machine.pop() as String) + defs.add(machine.pop()) } + val function = provider.provideNativeFunction(defs) + function.invoke(arguments) } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt new file mode 100644 index 0000000..15eccdb --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt @@ -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() + val right = machine.pop() + machine.push(left - right) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/UnaryMinusOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/UnaryMinusOpHandler.kt new file mode 100644 index 0000000..7222b97 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/UnaryMinusOpHandler.kt @@ -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() + machine.push(-value) + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/UnaryPlusOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/UnaryPlusOpHandler.kt new file mode 100644 index 0000000..9803171 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/UnaryPlusOpHandler.kt @@ -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() + machine.push(+value) + } +}